首页
社区
课程
招聘
[原创]通过一道pwn题详细分析retdlresolve技术
发表于: 2019-11-20 18:26 9818

[原创]通过一道pwn题详细分析retdlresolve技术

2019-11-20 18:26
9818

本文涉及到的ELF节以及相关结构如下:

(1).rel.plt节是用于函数重定位,.rel.dyn节是用于变量重定位。.rel.plt节相关的Elf32_Rel结构如下:

以write函数为例,write函数的r_offset=0x0804a01c,r_info=0x607

.got节保存全局变量偏移表,.got.plt节保存全局函数偏移表(即GOT表)。其中.got.plt对应着Elf32_Rel结构中r_offset的值。

可以通过上图命令获得.rel.plt的地址,rel.plt节保存着函数对应.got.plt地址和r_info信息

(2).dynsym节包含了动态链接符号表。Elf32_Sym[num]中的num对应着ELF32_R_SYM(Elf32_Rel->r_info)。根据定义:

所以,write的索引值为ELF32_R_SYM(0x607) = 0x607 >> 8 = 6。即Elf32_Sym[6]保存着write的符号表信息。并且ELF32_R_TYPE(0x607) = 7,对应R_386_JUMP_SLOT,write的索引值为6如下图所示:

.dynsym节相关的Elf32_Sym结构如下:

根据所以根据索引6可以找到,Elf32_Sym结构中st_name值:
Elf32_Sym[6]->st_name=0x4c(.dynsym + Elf32_Sym_size * num)

(3).dynstr节包含了动态链接的字符串。这个节以\x00作为开始和结尾,中间每个字符串也以\x00间隔。

最终要找到write函数的符号,要先在.dynsym中找到偏移,.dynstr加上0x4c的偏移量,就是字符串write

漏洞程序demo代码:

也是一个简单的栈溢出,保护只开了NX,栈不可执行,所以需要通过rop来get shell。

该漏洞利用涉及到延迟绑定的技术,基础知识如下:

GOT表的布局大致如下:

延迟绑定的过程如下:

(1)执行put@plt,此时puts函数的GOT表填充的只是下一条指令地址,push reloc_arg=0x0

(2)执行puts@plt+11指令,跳转到PLT[0],push GOT[1]的内容,并跳转到GOT[2]上去执行

随后调用_dl_runtime_resolve(link_map, reloc_arg),_dl_runtime_resolve函数中会调用_dl_fixup来完成解析:

最终效果就是将puts函数的实际地址填充到0x601018处,下次再调用时就可以直接跳转到相应地址执行。

过程大致如下:

retdlresolve的利用过程,主要就是控制上图中的resolver
(1)控制上图中的resolver,即reloc_arg
(2)根据reloc_arg,会将.rel.plt基址+reloc_arg获得函数的.got.plt地址(r_offset)和r_info信息(涉及 Elf32_Rel结构)
(3)根据r_info,将.dynsym基址 + ((r_info)>>8)*0x10获得Elf32_Sym[(r_info)>>8]->st_name信息(涉及Elf32_Sym结构,结构大小为0x10)
(4)根据st_name,将.dynstr基址+st_name得到函数的符号
(5)最后通过查找符号得到函数实际运行地址,填入(2)中GOT表地址中。
所以就需要伪造(2)、(3)、(4)中的reloc_arg,r_info,st_name这些偏移,使其查找过程都落在可控的区域中(如.bss中)。最终将函数符号伪造成“system”。

网上基本都是通过roputils工具直接做题,下面就分析一下工具产生的rop链的执行过程:

使用roputils工具产生的rop链如下:

offset是相对于.rel.plt的基址(0x8048330)而言,根据这个偏移找到函数的got表地址和r_info信息

(1)首先在.bss段开辟一个栈空间,起始地址为:.bss=0x0804a040(fake_stack)
(2)在返回地址填上read@plt地址,往0x0804a840地址写入构造的数据
(3)fake_stack上要构造的有两处:一个是fake_reloc,放在fake_stack+0x18处,第二个是.dynsym信息,存放在fake_stack+0x28处

计算过程如下:

exp代码如下:

使用工具的简单式操作:

这里传入bss_base+20的地址,但实际写入的确实bss_base+0x18的位置,是因为有对齐字节的操作:

看roputils源码可以看到这些函数也是经过了exp代码中的那些计算,使我们可以直接调用。

参考链接中:http://pwn4.fun/2016/11/09/Return-to-dl-resolve/ 的利用过程如下:

(1)控制eip为PLT[0]的地址,只需传递一个index_arg参数
(2)控制index_arg的大小,使reloc的位置落在可控地址内
(3)伪造reloc的内容,使sym落在可控地址内
(4)伪造sym的内容,使name落在可控地址内
(5)伪造name为任意库函数,如system

文中的利用过程很详尽,这边只是做一下调试的记录(主要不同时进行了栈的切换,将栈切到.bss+0x800位置,并修改write函数为system进行getshell,而本文的exp是直接修改read函数为system)

stage3 中在base_stage中伪造fake_reloc,填入的是write函数的.got.plt以及r_info,并计算该地址距离.rel.plt的偏移,因为函数的GOT表地址就是根据.rel.plt地址+偏移查找获得的。

stage4 中对write函数在.dynsym中的st_name进行伪造,因为该查找过程是靠r_info进行计算,所以对r_info进行修改

stage5 相对的st_name已经在我们的控制之中,可以在base_stage区域中一个地址填充write字符串,算出该地址与.dynstr的偏移,将偏移填充到st_name中即可。

stage6 只需将write字符串改成system字符串就可以在write的got表中填充system地址,并且调用,实现get shell。

https://github.com/nushosilayer8/pwn/tree/master/ret2dlresolve
http://pwn4.fun/2016/11/09/Return-to-dl-resolve/
http://rk700.github.io/2015/08/09/return-to-dl-resolve/
https://github.com/inaz2/roputils

 

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

最后于 2019-11-20 18:26 被笔墨编辑 ,原因:
上传的附件:
收藏
免费 9
支持
分享
最新回复 (6)
雪    币: 14494
活跃值: (17473)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
2
mark,楼主辛苦了
2019-11-21 09:15
0
雪    币: 15170
活跃值: (16832)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
3
楼主辛苦
2019-11-21 11:12
0
雪    币: 1841
活跃值: (1280)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2019-11-24 05:09
0
雪    币: 26588
活跃值: (63242)
能力值: (RANK:135 )
在线值:
发帖
回帖
粉丝
5
感谢分享!
2019-11-25 13:52
0
雪    币: 3664
活跃值: (3060)
能力值: ( LV8,RANK:147 )
在线值:
发帖
回帖
粉丝
7
好东西,先收藏
2019-11-29 13:34
0
游客
登录 | 注册 方可回帖
返回
//