首页
社区
课程
招聘
2015 9447ctf search_engine 双解
发表于: 2018-10-11 09:17 9860

2015 9447ctf search_engine 双解

2018-10-11 09:17
9860

分析一下2015 9447ctf search_engine这道题目。CTF-wiki中2015-9447-ctf-search-engine对于漏洞利用已经讲的十分清楚,我对于程序的功能分析进行一下补充,然后对exp做一下简单的注释,便于理解一些。

1.泄露stack_addr: 首先利用输入长度为48的非数字,而程序不会为字符串设置截断符,可以泄露栈区信息。(可能要输入多次“a”*48,因为有可能恰好在stack区域中,字符串结尾恰好是“\00”,导致不能泄露stack信息,而由于这个stack是递归的,每一次都会导致stack下移,因为多输入几次,即可成功泄露stack信息。)

2.泄露libc: 然后是泄露libc,本文提供了一种新的思路,如何控制node的内容:申请一个存放sentence的chunk,大小与node的大小一样,然后free sentence,然后继而在add一个sentence,并且sentence_chunk_size != node_size,那么node就会被分配到我们前面用来存放sentence的chunk中,即将此chunk加入到了node_list中去。然后我们可以通过比较“\00”使最近添加的node_chunk删除(即删除前面的node的sentence,对应到当前的node),从而又将node_chunk放到了fastbin中,然后我们可以申请一个sentence_chunk_size与之对应sentence,那么我们后面就可以通过控制sentence来控制这个node了,从而实现任意地址读取。泄露libc

3.后面通过double free以及fastbin_attack改写fd,分配fake_chunk到stack区域,然后覆盖ret(没有复现成功以及理解)


首先是泄露stack的信息:

在输入选项1或者2或者3的时候,他有一个48字节的缓冲区,当输入非数字字符长度为48的时候,他并不会在字符串末尾设置截断符,并且由于strol,会将栈区信息泄露出来。


这题目算是本菜鸡做pwn以来读的最难懂的程序了,程序的内容以及数据结构花了比较长的时间才弄清楚,下面分析一下这个题目的功能。

程序开始之后,对输出缓冲区做了限制,但是没有对输入缓冲区进行限制,因此程序开始之后会先申请一段heap空间作为输入缓冲区。
下面进入功能函数,我对某些变量做了标注,就如图中展示的一样。
get_numbe()函数用来接受输入,根据输入的数字来执行相应的功能。
get_numbe()函数用来接受输入,根据输入的数字来执行相应的功能。
get_numbe()函数用来接受输入,根据输入的数字来执行相应的功能。
程序只有两个功能,说实话,我看到的时候很迷。。

首先介绍index_sentence()的功能,功能的名字叫做索引句子。有点难懂啊,索引句子到底是怎么个索引方式。

为了完成索引,在你输入的句子中需要有一个空格" ",比如“aaa b”这样,当然还要输入size = 6。输入完成之后可以根据“aaa”或者"b"来找到输入的句子并且选择是否删除。
输入一个新的sentence之后创建两个数据结构来存储信息。
struct node
{
char * word;     索引字符串的起始地址
int word_size;     索引字符串的大小
char * sentence;   句子的其实地址
int sentence_size;   句子的大小
void * pre_node;    上一个节点
}
看一下测试的结果加深一下理解,在index功能下输入size = 7 ,sentence="aaa b "效果如下:
pwndbg> x 0x6020b8
0x6020b8:	0x00603470
pwndbg> x/20xg 0x603410
0x603410:	0x0000000000000000	0x0000000000000021         
0x603420:	0x000a206220616161	0x0000000000000000          字符串“aaa b ”
0x603430:	0x0000000000000000	0x0000000000000031
0x603440:	0x0000000000603420	0x0000000000000003           "aaa"的起始地址以及size=3
0x603450:	0x0000000000603420	0x0000000000000006
0x603460:	0x0000000000000000	0x0000000000000031                                               也就是说添加一个sentence会生成两个结构node
0x603470:	0x0000000000603424	0x0000000000000002           "b"的起始地址以及size = 1
0x603480:	0x0000000000603420	0x0000000000000006
0x603490:	0x0000000000603440	0x0000000000020b71            上一个节点是0
0x6034a0:	0x0000000000000000	0x0000000000000000

pwndbg> x 0x6020b8
0x6020b8:	0x00603470
pwndbg> x/20xg 0x603410
0x603410:	0x0000000000000000	0x0000000000000021         
0x603420:	0x000a206220616161	0x0000000000000000          字符串“aaa b ”
0x603430:	0x0000000000000000	0x0000000000000031
0x603440:	0x0000000000603420	0x0000000000000003           "aaa"的起始地址以及size=3
0x603450:	0x0000000000603420	0x0000000000000006
0x603460:	0x0000000000000000	0x0000000000000031                                               也就是说添加一个sentence会生成两个结构node
0x603470:	0x0000000000603424	0x0000000000000002           "b"的起始地址以及size = 1
0x603480:	0x0000000000603420	0x0000000000000006
0x603490:	0x0000000000603440	0x0000000000020b71            上一个节点是0
0x6034a0:	0x0000000000000000	0x0000000000000000

search_with_word的时候输入"aaa"或者"b"的时候都可以找到这个句子。

下面看一下search_with_word功能。


我也做了相应的注释,就是取bss段中存储的最新添加进去的节点,然后依次判断有没有条件相符的,并且首先要保证node中的sentence的内容不为空。其实是最低字节不能为空**(_BYTE **)(i+16)
找到符合条件以后,如果选择删除之后,那么会先对sengtence置0并且free掉,但是并没有设置NULL而且node中的sentence的内容仍然存在,存在UAF漏洞,可以继续使用。

此外get_input函数中还有一个漏洞,如果输入的字符串长度恰好的读取长度相同,在结尾值没有设置结束符"\00"。

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 1
支持
分享
最新回复 (4)
雪    币: 33
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
2
1
2018-10-11 10:02
0
雪    币: 1
活跃值: (47)
能力值: ( LV3,RANK:27 )
在线值:
发帖
回帖
粉丝
3
1
2018-10-15 21:37
0
雪    币: 1
活跃值: (47)
能力值: ( LV3,RANK:27 )
在线值:
发帖
回帖
粉丝
4
我觉得那个fake_chunk是在栈区寻找 40, 这个值刚好对应结构体的size,栈区中是存在0x400*** 这样的地址,可以刚好用来伪造fake_chunk
2018-10-15 21:38
0
雪    币: 61
活跃值: (2390)
能力值: ( LV9,RANK:260 )
在线值:
发帖
回帖
粉丝
5
siriuswhiter 我觉得那个fake_chunk是在栈区寻找 40, 这个值刚好对应结构体的size,栈区中是存在0x400*** 这样的地址,可以刚好用来伪造fake_chunk
谢谢师傅 我去看看的
2018-10-17 14:29
0
游客
登录 | 注册 方可回帖
返回
//