栈溢出利用之Return to dl-resolve

0x00 前言

在CTF中一般的栈溢出题目会给出程序对应的libc,这样我们在泄漏一个libc地址之后就能根据偏移量去计算libc的其他地址,比如system/bin/sh或是libc基址。 那如果题目中没有给出libc,我们就无法得知题目所用的libc版本。这个时候如果我们要计算system函数的地址的话,可以利用泄露出的libc地址去http://libcdb.com搜索对应的libc版本,因为一个libc函数地址的低三位在对应的libc版本中总是不变的。(当然你也可能搜不到) 今天要介绍的这项技术就是"Return_to_dl_resolve"。 理论上来讲,它能在不泄露libc地址、不需要知道libc版本的情况下完成任意libc函数的调用。(包括system) 在正式介绍这项技术之前,先了解一下相关知识。

0x01 背景知识

我们应该知道Linux glibc函数在第一次被调用的时候才会去寻找真正的函数地址并进行绑定(不了解这块知识可以百度“PLT 延迟绑定”),而解析函数地址的工作由函数dl_runtime_resolve来完成。

上面一张图片简单描述了第一次调用函数的流程。而要说到dl_runtime_resolve如何解析函数,那就不得不提到ELF文件中几个关键的节区了。见下图框起来的部分。

上面第一张图的STRTABSYMTABJMPREL分别就是第二张图的dynstrdynsymrel.plt , 上图也提供了如何查看这些信息的命令。

要谈到这些节区的关系,我们先从dl_runtime_resolve函数的参数说起。

注意到我给的函数第一次调用流程图中有两个push指令,两个push分别将参数link_mapreloc_arg压入栈中,图中我写的rel_off也就是参数reloc_arg,另一个就是link_map。 rel_off即为需要重定位的函数在rel_plt节中的偏移,该节查看如下

上面是重定位变量,下面是重定位函数,我们主要看下面的部分。 比如第一个函数setbuf,在表中占第一位,那么它的rel_off就为0,第二个函数read的偏移就为8.第n个函数的偏移为n*len_of_elfRel,在32位程序中len_of_elfRel大小为8. elfRel为保存每个重定位函数信息的数据结构 结构如下

typedef struct {
Elf32_Addr r_offset;    
Elf32_Word r_info;      // 符号表索引
} Elf32_Rel;

r_offset就是该函数在got表的位置,r_info用来检索函数其他信息在节区dynsym中的位置。

ELF32_R_SYM(Elf32_Rel->r_info) = (Elf32_Rel->r_info) >> 8  

dynsym节区中每个存储函数信息的数据结构如下:

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;

查看内存的话一般看到的是下面这个样子的:

前四个字节的值是函数的名称在dynstr表中的偏移,dynstr基址加上这个偏移就是对应函数名称所在的位置。

dynstr表中装有需要重定位的函数和变量名称的字符串。

前面提到过,函数的解析工作是由dl_runtime_reslove函数完成的。

该函数使用汇编语言实现的,而在其中会首先调用一个函数 dl_fixup,传输由寄存器传递。

我们关注一些关键部分即可:

那么我们的漏洞利用思路就比较清晰了

0x02 思路

  1. 伪造一个很大的rel_off参数,使reloc落在我们可控的范围。
  2. 将参数压栈,控制eip跳到PLT[0]
  3. 伪造reloc内容,第一个为需要覆写的GOT表地址,一个是dynsym的索引值。伪造索引值可以使得sym落在我们可控范围内。
  4. 伪造sym中的st_name所代表的偏移值,可以使得str落在我们可控范围内。
  5. 伪造str的值,比如system

我在上次写到的NSCTF的wp中有说到那两道题目都可以通过ret2resolve完成攻击,那么这次我就一其中一题作为例子来做演示。

0x03 EXP(pwn1)

这就是修改过的exp。 中间我用虚线分割的部分是一些构造ROP的地址,上面提到的三个节区的地址,以及伪造的地址及信息。 data部分是从bss段开始的,我留出了880个字节当作dl_runtime_resolve函数调用所需的栈空间,得益于这是一片可写区域。之后的空间就是我放置伪造信息的区域了。

0x04 注意事项

  1. 伪造的dynsym表的首地址需要和真正的表的首地址对齐,alignment为16个字节。
  2. 伪造的reloc信息中的r_info部分,最低位必须为7,因为会有函数专门check这个值。所以r_info部分的构造就是:将伪dynsym表与真表的偏移乘以0x10,再加上一个7。

0x05 参考文章

Return-to-dl-resolve】http://http://pwn4.fun/2016/11/09/Return-to-dl-resolve/

总结

这种攻击方式相较ret2libc来讲较为复杂,操作起来也比较麻烦,而且在开了PIERELRO FULL时不好利用,慎用。

本文分享自微信公众号 - 信安之路(xazlsec)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-08-04

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端桃园

知识体系解决迷茫的你

最近在星球里群里都有小伙伴说道自己对未来的路比较迷茫,一旦闲下来就不知道自己改干啥,今天我这篇文章就是让你觉得一天给你 25 个小时你都不够用,觉得睡觉都是浪费...

22440
来自专栏非著名程序员

「我真的没有改需求」

12110
来自专栏web前端教室

你可以从面试中学到什么?

讲一下我对面试的一些。。。“偏见”,哈哈,熟悉我的同学们一定要批判的读接下来的内容哈。

12400
来自专栏非著名程序员

这是对付产品经理的一副毒药,程序员慎入

程序员和产品经理的日常就像是一对天生的冤家,为了需求的实现,几乎天天在争吵。这不,就在昨天各大技术和产品群里一个程序员暴打产品经理的视频火了,被广泛传播。

12620
来自专栏FSociety

SQL中GROUP BY用法示例

GROUP BY我们可以先从字面上来理解,GROUP表示分组,BY后面写字段名,就表示根据哪个字段进行分组,如果有用Excel比较多的话,GROUP BY比较类...

5.2K20
来自专栏haifeiWu与他朋友们的专栏

复杂业务下向Mysql导入30万条数据代码优化的踩坑记录

从毕业到现在第一次接触到超过30万条数据导入MySQL的场景(有点low),就是在顺丰公司接入我司EMM产品时需要将AD中的员工数据导入MySQL中,因此楼主负...

30540
来自专栏腾讯NEXT学位

今天我就说三句话

11720
来自专栏腾讯大讲堂的专栏

白底黑字or黑底白字,眼睛更喜欢哪一个?

12310
来自专栏Ken的杂谈

【系统设置】CentOS 修改机器名

18430
来自专栏微信公众号:小白课代表

不只是软件,在线也可以免费下载百度文库了。

不管是学生,还是职场员工,下载各种文档几乎是不可避免的,各种XXX.docx,XXX.pptx更是家常便饭,人们最常用的就是百度文库,豆丁文库,道客巴巴这些下载...

44830

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励