首页
社区
课程
招聘
[原创]hack.lu 2015 bookstore writeup
发表于: 2018-9-11 21:02 17059

[原创]hack.lu 2015 bookstore writeup

2018-9-11 21:02
17059

15年的一道题,尝试解题无果之后去搜了搜writeup,结果并没有搜到。。只有一篇非正常getshell的文章。。作者打比赛时候靠着本机环境和比赛机一致,靠着设定好system地址getshell。看的我一脸懵,还是靠自己解吧。。肝了一天多终于肝出来了。。本菜鸡还是菜啊。。

这道题虽然看似漏洞很多,但是要利用起来还真是有点困难。

checksec:

该程序是个书店,订书的功能,最多订购两本书,订购每本书的时候可以填写订单内容,这里面可以无限制任意写,然后是删除订单,删除订单中只free掉了指针,没有把指针置为NULL,存在UAF漏洞,且指针的位置处于栈地址上,最后是一个提交功能,提交功能是将两本书的内容合在一起打印出来,但是提交后存在一个格式化字符串的漏洞。

那么问题来了,漏洞看起来这么的多,怎么去利用?首先我们得注意三点:

但是我们会遇到一些问题,比如说我们想用溢出控制第三块堆中的内容再利用格式化字符串的时候会遇到填写订单内容后被strcpy函数给重新覆盖掉第三堆块的内容。

这里我们应当使用到Overlapping,先delete第二堆块,再用堆块一溢出堆块二的size字段为0x151,这样当利用submit功能的时候所申请的0x140堆块就能出现在堆块二的位置上,随后便能利用submit合并两个堆块内容的作用覆盖到第三堆块,如果构造好覆盖内容,我们便能在程序最后利用到格式化字符串的内容。

显然,一次利用并不能达到我们getshell的目的,这里用到这么一个知识点 :

所以我们可以利用第一次格式化字符串将.fini_array地址处的函数修改成main函数的地址,使程序重新回到main函数。当然,我们还需要泄漏libc地址。

delete掉堆块二:

利用堆块一覆盖重写的这里我们需要注意,我们所构造的payload需要和后面利用的格式化字符串所匹配。

堆块位置如下:

我们需要让printf堆块处执行格式化的漏洞,就需要让submit功能去帮助我们覆盖,submit功能会加上order1:等这些字符串,不能漏掉,总结后可以得知新申请的堆块内容为:

Order 1: + chunk1 + \n + Order 2: + chunk2 + \n

因为chunk2已经被delete掉了,所以当复制chunk2中的内容的时候复制的其实是order 1: + chunk1。所以上述可以变为:

Order 1: + chunk1 + \n + Order 2: + Order 1: + chunk1 + \n

所以我们可以构造第二次的chunk1内容恰好覆盖到dest堆块处。也就是:

size(Order 1: + chunk1 + \n + Order 2: + Order 1:) == 0x90

size(chunk1) == 0x90 - 28 == 0x74

所以我们构造chunk1中的内容的时候只要使其中非0字符串的个数达到0x74就行了。

因为输入选项的时候可输入128个数字符串:

所以我们可以提前在栈中构造好我们所需要用格式化字符串修改的任意地址。

输入点在格式化偏移为12处,我们第一轮利用需要修改的是.fini_array处的内容,所以我们在栈中可以这么构造:

chunk1中的内容可以这么构造:

这里的'.%31$p'目的是泄漏__libc_start_main函数的地址,从而leak libc的地址。而这里的',%28$p'目的我后面会说到。

这里我们能怎么接下去利用呢?ctf-wiki上的解法是拿到system函数的地址后去覆盖free_got。我试了这解法后才知道这解法还需要再来一轮去触发free函数。。所以这个思路行不通。。wiki上贴的exp好像只执行了第一阶段,第二阶段的利用没有。。

搜索到的唯一一个exp是通过设定system地址佛系getshell的。。所以还是得自己来着手。。我想这题目肯定是有一个常规解的。所以我自己来肝。。

我的思路是通过第二阶段修改主函数返回地址getshell:

返回地址在栈上的位置是随机的,所以我们需要找一个与返回地址有固定偏移的栈地址。我们从栈上去找一找,我发现了这么一个地址:

这个栈地址始终指向比自己低0x10字节的栈地址,而且指向的栈地址和返回地址也有固定的0x28的偏移,所以我选择用格式化字符串泄漏这个栈地址,但是这里还有一个问题:

上面所提到的payload',%28$p'的目的就是泄漏这个栈地址。

我们直接把gdb attach上去计算固定的偏移:

泄漏得到的第一阶段的返回地址:0x7ffd88f7d6f8

gdb中得到的第二阶段的返回地址:0x7ffd88f7d4e8

所以固定偏移为:0x7ffd88f7d6f8 - 0x7ffd88f7d4e8 = 0x210

我们得到了第二阶段的返回地址的栈地址之后就好办事了,重复第一阶段的构造利用即可,这里面为了方便,可以直接利用one_gadget工具中的execve函数地址来覆盖返回地址。这里经过观察可以发现,execve的地址和返回地址只有最后三个字节不同,所以构造格式化漏洞的时候只需要覆盖返回地址最后的三位即可。

可能机子环境不一样这个固定偏移也不一样,我的环境是:

Ubuntu16.04,glibc2.23

Hack.lu 2015 bookstore writeup

 
 
 

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2018-9-12 08:18 被V1NKe编辑 ,原因:
上传的附件:
收藏
免费 1
支持
分享
最新回复 (3)
雪    币: 61
活跃值: (2390)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
2
感谢师傅分享,学到了
2018-10-25 23:58
0
雪    币: 247
活跃值: (109)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

这个栈地址始终指向比自己低0x10字节的栈地址,而且指向的栈地址和返回地址也有固定的0x28的偏移


这里的地址是0x7fffffffde40,不是dd40偏移应该不是0x28????
2019-5-3 14:48
0
雪    币: 3567
活跃值: (467)
能力值: ( LV10,RANK:170 )
在线值:
发帖
回帖
粉丝
4
Freway 这个栈地址始终指向比自己低0x10字节的栈地址,而且指向的栈地址和返回地址也有固定的0x28的偏移 这里的地址是0x7fffffffde40,不是dd40偏移应该不是0x28????
感谢提出,应该是当时眼花了,具体的按exp来调,由于太久的缘故我记不太清了。
2019-5-6 18:12
0
游客
登录 | 注册 方可回帖
返回
//