免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2675 | 回复: 3
打印 上一主题 下一主题

浅析Linux环境下利用vsyscalls构造exploit [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2005-05-07 00:03 |只看该作者 |倒序浏览
浅析Linux环境下利用vsyscalls构造exploit

+---------------------------------+
|  翻译整理/s5Eal www.ph4nt0m.org |
|  Contact:s5Eal@ph4nt0m.org     |
|  Date:2005/05/06               |
+---------------------------------+
这篇文章将尝试介绍一些在具有特殊背景的栈下编写缓冲区溢出时经常遇到的问题,并提出了对此的一些简单解决的方法。

首先希望读者具备的知识包括:汇编语言,C语言,以及linux/unix方面的一些知识,当然必须知道关于缓冲区溢出方面的一些知识,因此强烈建议你去读一读。

关于原文:http://www.lse.epita.fr/publications/2005/ret-onto-vsyscall.txt

首先我们来看一个简单的程序

#include <stdio.h>;
#include <string.h>;
#include <unistd.h>;

void copy(char *str)
{
        char buf[256];
        int i;

        memset(buf, 0, 256);
        for (i = 0; str; i++) {
                buf = str;
        }
}

int main(int ac, char **av)
{
        if (ac < 2) {
                fprintf(stderr, "I take at least one argument.\n";
                return (0);
        }
        copy(av[1]);
        return (0);
}


这个程序本身并没有什么特别之处,copy函数复制其仅有的一个参数到一个具有固定大小(256bytes)的缓冲区。需要注意的就是这里并没有在copy结束后为其多增加一个null byte。

很明显这个程序的问题出在copy函数,如果这个参数“str”非常长,那么我们将破坏这个缓冲区的外围,比如EBP,甚至EIP。

假设我们的主机不允许我们使用暴力破解的方法来进行exploit,那我们可以求助于一种精确定位返回地址的exploit的构造方法,比如return-into-libc技术,下面我们来准备构造我们的栈来使return-into-libc能够成功。我们仔细看一下copy函数,指向被copy的字符串的指针是这个函数唯一的一个参数,它在栈中是放在EIP后面的,了解这一点非常重要,因为这是个严重的问题。如果这个参数过长导致溢出,那么我们将不能按照我们设想的那样去构造我们的栈来实现return-into-libc,因为这样有可能会覆盖这个参数的指针,这将导致其指向一个随机的区域,我们copy的也是一些随机的数据,这个copy过程将会因为遇到一个null byte而结束或者是因为一个SIGSEGV信号,传统的return-into-libc技术在这里将永远不会成功。

我们来看一下在调用copy函数前栈的状态:

top
|    ...    |
+-----------+
|    str    |
+-----------+
|    EIP    |
+-----------+
|           |
| buf[256] |
|           |
+-----------+
|    ...    |
bottom

如果我们用一个指向RET指令的地址去覆盖EIP,那么另外一个返回将被实现,,这个第二个返回将把EIP之后的这个str的地址当作ESP的地址,并将其放到EIP去,然后EIP本身的返回执行,此时程序继续执行,执行的是这个str的内容,聪明的读者可能已经意识到,当然这个str里应该放的是我们的shellcode,这里可能有点绕,建议大家先去了解一下RET指令的执行过程。因为程序是从str的头部开始执行,所以我们把shellcode写在字符串的开始处,这样就可以不用使用类似NOP之类的无效指令了,当然我们以上所做的一切都需要一个前提也就是这个栈是可执行的。

在这里我们只需要一个额外的RET指令地址,因为这里只有一个参数,如果这里有好几个参数,那么我们可以把几个RET指令地址写成一个队列以对应向应的EIP和str。

现在主要的困难就是如何找一个指向RET指令的地址,这个并不是很大的问题。在Linux2.6内核中,内核开发者加入了对虚拟系统调用vsyscall的支持,这意味着用户层的程序可以直接连接到内核空间,而不是通过系统调用。Vsyscall的代码是用汇编写的,放在arch/i386/kernel下,正因为它是汇编写的,所以它被系统改变的可能性很低,类似于一个函数库一样放在内存中(共享目标)。

        cat /proc/self/maps
08048000-0804c000 r-xp 00000000 03:01 589888 /bin/cat
0804c000-0804d000 rw-p 00003000 03:01 589888 /bin/cat
0804d000-0806e000 rw-p 0804d000 00:00 0
40000000-40016000 r-xp 00000000 03:01 671776 /lib/ld-2.3.2.so
40016000-40017000 rw-p 00015000 03:01 671776 /lib/ld-2.3.2.so
40017000-40018000 rw-p 40017000 00:00 0
40022000-4014b000 r-xp 00000000 03:01 2048049 /lib/tls/libc-2.3.2.so
4014b000-40153000 rw-p 00129000 03:01 2048049 /lib/tls/libc-2.3.2.so
40153000-40157000 rw-p 40153000 00:00 0
bffff000-c0000000 rw-p bffff000 00:00 0
ffffe000-fffff000 ---p 00000000 00:00 0

vsyscall被放在0xffffe000,如果我们用gdb调试任意一个进程,并且分析这个区域,那么可以看到:

(gdb) x/i 0xffffe413
0xffffe413 <__kernel_vsyscall+19>;: ret

我们在大量的2.6.x内核的机器上测试过,总是在这个地址处找到一个RET.指令,利用这一点,可以使exploit程序更有成效,这也就是我们学习的目的。

在前面的例子中我们看到,代码中并没有在copy的结尾处加上一个null byte,正因为如此,所以我们很难实现return-into-stack,我们可能需要测试很多次才能成功,我们可以使用vsyscalls,以此来减少失败的次数。

因为这个可能有点绕人,为了更好的理解所以我们需要慢慢的深入的来看这个问题,我们再次来看一下一个普通堆栈的情况:

high addresses
|    ...    |
+-----------+
|    str    |
+-----------+
|    EIP    |
+-----------+
|           |
| buf[256] |
|           |
+-----------+
|    ...    |
low addresses

记住它是怎么运行的,首先是把str字符串copy到buf处,现在我们假设一个null byte添加在copy结束的时候,这样到底为什么可以增加我们成功的可能性呢?下面我们接着看,我们知道任何一个函数,尤其是我们这个有着问题的函数,在它第一次调用的时候是被另外一个函数调用的(比如main函数),所以我们的栈看上去是这样的:

high addresses
|    ...    |
+-----------+
|    EIP    |
+-----------+
|    EBP    | <-- Here is EBP from calling function
+-----------+ 0xbfffeed0
|           |
|    ...    |
|           |
+-----------+
|    EIP    |
+-----------+
|    EBP    | <-- Here is EBP from our vulnerable function (= 0xbfffeed0)
+-----------+ 0xbfffee90
|           |
| buf[256] |
|           |
+-----------+
|    ...    |
low addresses

我们可以看到,这个问题函数copy的EBP是一个栈地址,这个地址指向了调用copy函数的函数的栈地址,也就是说,因为栈是从低地址方向向高地址进行分配的,所以这个指向前一个栈的指针其所包含的地址的值是要大于这里的BUF[256]的地址的,从上一个图上可以很明显的看出,这个应该是不难理解的。

换句话来说,如果我们把问题函数copy中的EBP中的值用一个null byte覆盖后也许我们可以改变其指向到BUFFER中,而不是原来的上一个栈了。

比如在我们的例子当中,0xbfffeed0是原先问题函数copy保存的EBP的值,如果copy结束后覆盖了一个null byte到EBP里,那么考虑到我们面对的是一个little-endian的机器,这个EBP的值将变成0xbffffee00。

现在我们看一个通常一个函数结尾时候的汇编代码:

mov %ebp, %esp
        pop %ebp
        ret

当程序开始执行的时候首先是问题函数的copy的EBP值被修改,当从copy函数中返回上一层的时候,这时的ESP等于这个被修改过的EBP的值,ESP此时指向buf中的某个位置,最后是一个POP,跟着一个RET。

我们可以看一下我们的BUF的线性的构造例子:

0              128           132            256
____________________________________________
|               |             |                     |
| AAA ..... AAAA| addr to jmp | Shellcode... |
|_______________|_____________|______________|
<------------------------------------------>;
                    256 bytes

因为我们的buf足够大,所以我们可以确定EBP肯定会指向它,但是我们不能确定具体指向buf的哪里,不管怎么样我们需要在四个dummy bytes(AAAAAAAA之类的就是dummy bytes,可以理解为垃圾数据)之后接一个地址指向一个“jmp *%esp”指令,我们来看一下:

(gdb) x/i 0xffffe6cb
0xffffe6cb:     jmp    *%esp

根据上面的buf排列,假设我们把EBP的第一个byte填充为null byte,然后它正好指向buf偏移124位处,所以当问题函数成功返回后,EBP将填充为下面的四个dummy byte “AAAA”,这时候返回地址为四个A下面的指向“jmp *%esp”指令的地址,这时候程序将从shellcode处开始执行(译者注:这个地方如果可能有点难以理解,我建议大家去看一看Phrack
55-08的《The Frame Pointer Overwrite》和红盟的bkbll的《利用jmp esp 执行shellcode》)

这个方法的缺点就是需要多试几次以使buffer的安排符合栈的需要,这里需要注意的就是dummy bytes应该四个一组四个一组的排列,这样的四字对齐可以减少测试的次数。

这两个简短的例子证明了vsyscalls可以被高超的攻击者用来构造缓冲区溢出程序。在第二个例子中,“jmp *%esp”指令并不是内核设计者构造的一个真正的指令,事实上我们是用section’data中的dummy bytes,它被处理器解释成“jmp *%esp”。这个可以用gdb在vsyscalls pages的标准的汇编代码中找到。Vsyscalls中的其他代码也可能成为有趣的对溢出有帮助的指令,也许可以有很多种方法去构造一个exploit。

参考资料:
[1] : Phrack 49-14: "Smashing the stack for fun and profit"
[2] : Phrack 58-10: "The advanced return-into-lib(c) exploits: Pax case study"
[3] : Phrack 55-08: "The Frame Pointer Overwrite"
[4] : bkbll         "利用jmp esp 执行shellcode"

论坛徽章:
0
2 [报告]
发表于 2005-05-09 14:04 |只看该作者

浅析Linux环境下利用vsyscalls构造exploit

怎么大家一点反应没有?!

论坛徽章:
0
3 [报告]
发表于 2005-05-09 16:49 |只看该作者

浅析Linux环境下利用vsyscalls构造exploit

vsyscall允许不走系统调用,直接转入内核态?
Me太孤陋寡闻了,google一下先~~

论坛徽章:
0
4 [报告]
发表于 2005-05-09 17:56 |只看该作者

浅析Linux环境下利用vsyscalls构造exploit

其实现在的这些paper都是属于细枝末节的附加性质的东西了,虽然技术精湛,但普遍使用性不强,相比实际使用而言,理论的成分更多一点

Phrack 58-10那篇的确很强,但这些都不是新概念的方法论,再也没有像smashing the stack for fun and profit那样开天辟地的感觉

如果能找到超越缓冲区溢出的方法,就可以瞬间黑了所有的安全公司
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP