DynELF简介
在做漏洞利用的时候,由于ASLR的影响,我们在获取某些函数地址的时候,需要一些特殊操作;一种方法是先泄露出libc.so中的某个函数,然后根据函数之间的偏移,计算我们需要的函数地址,但是这种方法局限于我们需要找到和目标服务器上一样的libc.so,而有些特殊情况下往往找不到对应的libc.so文件;另一种方法就是利用如pwntools的DynELF模块,对内存进行搜索,直到得到我们需要的函数。
官方文档给出了下面的例子:
1 | # Assume a process or remote connection |
可以看到需要使用者进行的工作主要集中在leak函数的实现上,通过这个函数可以获取到某个地址上最少1byte的数据 ,然后将这个函数作为参数调用d = DynELF(leak,elf)
,该模块的初始化就完成了,然后就可以使用它提供的函数进行内存搜索,得到我们想要的函数地址。
类DynELF的初始化方法如下:
1 | def __init__(self, leak, pointer=None, elf=None, libcdb=True): |
leak
: leak函数,它是一个pwnlib.memleak.MenLeak
实例pointer
: 一个指向 libc 内任意地址的指针elf
: elf 文件libcdb
: 是一个作者收集的libc 库,默认启用以加快搜索
使用条件:
1) 目标程序存在可以泄露libc空间信息的漏洞,如read@got就指向libc地址空间
2) 目标程序中存在的信息泄露漏洞能够反复触发,从而可以不断泄露libc地址空间内的信息(同样我们实现的leak函数要能够被循环调用)
DynELF 实例
在 libc 中,通常使用write
、puts
、printf
函数来打印指定内存的数据
这三个函数中最佳选择当然是write
了,因为打印的字节个数全部由write的第三个参数 size 决定,唯一的缺点就是需要传递3个参数,32位程序通过栈传递方便很多,但是64位通过寄存器就麻烦了不少。
这里以xdctf15-pwn200为例
xdctf15-pwn200
32位程序,使用write进行打印注释都在脚本上了
1 | #coding:utf-8 |
puts
函数:使用的参数只有一上,即需要输出数据的起始地址,遇到’\x00’截断,在末尾加上换行符\n
,所以puts输出 的数据长度是不容易控制 的,我们无法预料到0截断会在哪里出现;该函数的优点是参数少,在64位程序中很方便使用;缺点就是输出长度不可控,需要在leak函数中做特殊处理;
1、如果puts输出数据后没有接其它字符,我们可以这样写
1 | def leak(addr): |
2、puts输出数据后接其它字符
1 | def leak(addr): |
lctf16-pwn100
64位程序 ,只有puts函数可以调用
1 | #coding:utf-8 |
RCTF2015-welpwn
64位程序,存在puts和write函数可以调用
1 | #coding:utf-8 |