缓存溢出.docx
- 文档编号:11518708
- 上传时间:2023-03-02
- 格式:DOCX
- 页数:10
- 大小:17.88KB
缓存溢出.docx
《缓存溢出.docx》由会员分享,可在线阅读,更多相关《缓存溢出.docx(10页珍藏版)》请在冰豆网上搜索。
缓存溢出
缓存溢出
缓存溢出(Bufferoverflow),是指在存在缓存溢出安全漏洞的计算机中,攻击者可以用超出常规长度的字符来填满一个域,通常是内存区地址。
这篇文章就是讲解简单的缓存溢出问题。
文章以x86_32和linux系统平台为蓝本。
为了介绍缓存溢出,数据的存储地址、主要的汇编指令、重要的寄存器等内容都要讲解。
1.变量存储
在C语言中,变量属性有很多中,但是对于缓存溢出问题,我们主要关心的数据的存储位置,或存储空间。
因此,这里我们主要关心全局变量,局部变量和静态变量。
在C语言中,通常全局变量和静态变量被分配于数据段(datasection)中,但是局部变量分配在栈(stack)中。
另外,大家清楚,栈空间中还存储CS,IP等一些列与指令地址相关的重要数据,因此,在对局部变量进行数据拷贝的时候,如果拷贝数据块过大,就可能将IP,CS等寄存器存放的数据空间覆盖掉,写入一些非法的数据,当从设IP值时,计算机就跳转到新的非法数据代码空间了。
这里有一个简单的C文件,overflow1.c
intdata=0x66666666;
intfunc1(void)
{
staticintsdata=0x55555555;
intret=0;
returnret;
}
intmain(intargc,char*argvs[])
{
func1();
return0;
}
我们首先对它进行编译,然后查看编译后的信息。
#gcc–ooverflow1.o–coverflow1.c
#objdump–toverflow1.o
over3.o:
fileformatelf32-i386
SYMBOLTABLE:
00000000ldf*ABS*00000000over3.c
00000000ld.text00000000.text
00000000ld.data00000000.data
00000000ld.bss00000000.bss
00000004lO.data00000004sdata.1280
00000000ld.note.GNU-stack00000000.note.GNU-stack
00000000ld.comment00000000.comment
00000000gO.data00000004data
00000000gF.text00000012func1
00000012gF.text0000001emain
从结果中我们很容易找到data和sdata变量的size,section等信息。
如果想获取变量存储的地址,可以连接后在执行该命令。
但是对于局部ret,恐怕你不容易找到它的存放地址,那么ret的空间在哪里呢?
不要着急,我们继续。
#objdump–doverflow1.o
over3.o:
fileformatelf32-i386
Disassemblyofsection.text:
00000000
0:
55push%ebp
1:
89e5mov%esp,%ebp
3:
83ec10sub$0x10,%esp
6:
c745fc00000000movl$0x0,-0x4(%ebp)
d:
8b45fcmov-0x4(%ebp),%eax
10:
c9leave
11:
c3ret
00000012
12:
8d4c2404lea0x4(%esp),%ecx
16:
83e4f0and$0xfffffff0,%esp
19:
ff71fcpushl-0x4(%ecx)
1c:
55push%ebp
1d:
89e5mov%esp,%ebp
1f:
51push%ecx
20:
e8fcffffffcall21
25:
b800000000mov$0x0,%eax
2a:
59pop%ecx
2b:
5dpop%ebp
2c:
8d61fclea-0x4(%ecx),%esp
2f:
c3ret
从汇编代码里面恐怕还是不明白ret在哪里存储吧?
不用担心,我们回头看看C源文件,在func1函数里有一个intret=0的声明,聪明的你现在是不是找到对应的汇编语句了,你猜对了,就是下面这句话:
6:
c745fc00000000movl$0x0,-0x4(%ebp)
也就是说,ret的空间分配在-0x4%(ebp)指向的空间中。
从
1:
89e5mov%esp,%ebp
你会发现ebp存放的是esp的内容,也就说-0x4%(ebp)指向的是栈空间地址,而ret就存放在哪里。
现在明白了变量的存放空间了,下面我们要继续讲解关于栈中其它的信息。
2.重要指令和寄存器
为了更好的了解缓存溢出,就要了解与其相关的指令和寄存器。
我在这部分内容中会讲解这些信息。
IP,CS,ebp,esp是我们要讲的寄存器。
CS:
IP指向将要执行的指令的存储地址。
一般的函数跳转指令和函数调用指令就是通过修改CS:
IP的值来达到跳转目的。
当指令段发生改变时,CS寄存器的数值才改变,在同一个指令段中,通常只改变IP的数值就可以了。
我们今天介绍的默认只是通过修改IP的值而达到跳转目的。
Esp寄存器存放的当前栈顶地址,而ebp作为一个备份寄存器,保存着进入新函数后esp的值。
在重要的指令中,主要有push,pop,call,ret,leave.Push和pop是一对栈操作指令,push完成入栈操作,将数据写入栈中,并更新esp的内容,而pop指令与其相反,它将数据从栈中取出,并更新esp的内容。
其中call指令是函数调用指令,它主要完成指令计数器寄存器(IP)的入栈操作(为了简单期间,这里不考虑CS入栈问题,有兴趣的同学可以去查看引用文献),类似于指令“puship”。
而ret指令与call指令相反,是一个函数返回指令,将IP的值从栈中弹出,类似”popip”。
Leave也可以看成一个符合指令,它类似于“movebp,esp;popebp”两个指令的效果。
了解了上面的基本知识,我们来分析一下汇编代码。
为了清楚期间,我们将overflow1.o进行连接,然后查看连接后的重要汇编代码片段。
#gcc–ooverflow1overflow.o
#objdump–doverflow1
…..
08048324
8048324:
55push%ebp
8048325:
89e5mov%esp,%ebp
8048327:
83ec10sub$0x10,%esp
804832a:
c745fc00000000movl$0x0,-0x4(%ebp)
8048331:
8b45fcmov-0x4(%ebp),%eax
8048334:
c9leave
8048335:
c3ret
08048336
8048336:
8d4c2404lea0x4(%esp),%ecx
804833a:
83e4f0and$0xfffffff0,%esp
804833d:
ff71fcpushl-0x4(%ecx)
8048340:
55push%ebp
8048341:
89e5mov%esp,%ebp
8048343:
51push%ecx
8048344:
e8dbffffffcall8048324
8048349:
b800000000mov$0x0,%eax
804834e:
59pop%ecx
804834f:
5dpop%ebp
8048350:
8d61fclea-0x4(%ecx),%esp
….
从对func1函数开始调用开始,我们跟踪栈里面的内容。
当call指令执行后,计算机会跳到func1函数处继续执行,现在就将这些指令合并:
8048344:
e8dbffffffcall8048324
8048324:
55push%ebp
8048325:
89e5mov%esp,%ebp
8048327:
83ec10sub$0x10,%esp
804832a:
c745fc00000000movl$0x0,-0x4(%ebp)
执行后的结果是什么呢?
第一条指令是将IP压栈;
第二条指令将ebp压栈
第三条是将esp的值保存到ebp中
第四条指令更新esp的值,向前16bytes。
第五条指令给ret赋初值0,并且可以确定ret的地址是%ebp-4
因此,我们得到当前栈的值
IP0x88-0x8B;;Highaddress
Ebp->oldEBP0x84-0x87;;ebp=0x84
ret0x80-0x83
Nil0x7c-0x7f
Nil0x78-0x7b
Esp->Nil0x74-0x77;;esp=0x74
….….;;lowaddress
并且ebp会作为备份寄存器保留老的esp寄存器的值,当函数返回时,还原esp和ebp,以及IP。
缓存溢出就是在还原之前首先将栈中IP的值修改成其余的数值,从而是CPU跳转到一个错误地址或无效地址。
如果依照上面栈的地址,那么ret变量的地址应该是0x80,而老的IP数据的存储地址应该是0x88,如果在向ret进行数据拷贝时,数据过长,将会覆盖oldebp和IP的地址,从而导致程序在返回时,将错误的IP值弹出到指令计数器中,CPU将会跳转到该错误地址进行代码执行。
下面提供了两个案例程序,给大家参考。
Examples
Overflow2中是一个典型的内存溢出,作者通过向一个局部变量数组中写入过长数据,使程序无条件跳转的my_func()一个非法函数中。
#include
#include
charstrs[32]={0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,\
0xc4,0x83,0x04,0x08,0xc4,0x83,0x04,0x08,\
0xc4,0x83,0x04,0x08,0xc4,0x83,0x04,0x08};
/*my_func的地址是0x080483c4*/
intmy_func(void)
{
printf("inMyFunc!
\n");
return87;
}
intprint(void)
{
inttmp=0x33;
intret=0x22;
charstr[4];
char*data;
strncpy(str,strs,24);
returnret;
}
intmain(intargc,char*argvs[])
{
intret=print();
printf("ret=%x\n",ret);
return0;
}
Overflow3.c是一个不通过函数调用,强制跳转到my_func()函数,并成功返回到主函数。
#include
#include
intmy_func(void)
{
printf("inMyFunc!
\n");
return87;
}
intprint(void)
{
intret=0x22;
intstr[4];
asm(\
"mov0(%%ebp),%%ebx;\
mov%%eax,0(%%ebp);\
push%%eax;\
sub$4,%%ebp;\
mov%%ebx,0(%%ebp)"\
:
\
:
"a"(my_func));
returnret;
}
intmain(intargc,char*argvs[])
{
intret=print();
printf("ret=%x\n",ret);
return0;
}
本文来自CSDN博客,转载请标明出处:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 缓存 溢出