分享
 
 
 

通通透透讲溢出攻击

王朝other·作者佚名  2006-12-16
窄屏简体版  字體: |||超大  

缓冲区溢出技术基础

为了提高大家的技术水平,为了更了解我们讨论的这种技术,为了把这个论坛建成一个更更好的论坛,下面我为大家推出一系列完整的有关溢出,溢出攻击的文章。让大家更能了解到这个天天说但又不太清楚怎么回事的东西。我想,看了这个以后大家也不再会问,为什么我用了这个工具,怎么没有用呀什么的问题?

在这里强调一下,想完全看的懂这篇文章,至少需要具备一定的汇编语言,C语言和LINUX的基础。

缓冲区溢出”在英文中可以解释为:buffer overflow,buffer overrun,smash the

stack,trash the stack,scribble the stack, mangle the stack, memory

leak,overrun screw;

我们通常所说的“溢出”指的是缓冲区溢出,(废话,不然要从那里溢出呀!)先解释一下什么是缓冲区——缓冲区是内存中存放数据的地方,是程序运行时计算机内存中的一个连续的块,它保存了给定类型的数据。问题随着动态分配变量而出现。为了不用太多的内存,一个有动态分配变量的程序在程序运行时才决定给他们分配多少内存。当程序试图将数据放到计算机内存中的某一位置,但没有足够空间时会发生缓冲区溢出。另一种说法,就是说程序在动态分配缓冲区放入太多的数据会有什么现象?它会溢出,会漏到了别的地方。

一个缓冲区溢出应用程序使用这个溢出的数据将汇编语言代码放到计算机的内存中,通常是产生root权限的地方。单单的缓冲区溢出,并不会产生安全问题。只有将溢出送到能够以root权限运行命令的区域才行。这样,一个缓冲区利用程序将能运行的指令放在了有root权限的内存中,从而一旦运行这些指令,就是以root权限控制了计算机。

所以我们更多的时候把缓冲区溢出指的是一种系统攻击的手段,通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其它指令,以达到攻击的目的。据统计,通过缓冲区溢出进行的攻击占所有系统攻击总数的80%以上。

世界上第一个缓冲区溢出攻击——著名的Morris蠕虫,发生在十年前,它曾造成了全世界6000多台网络服务器瘫痪。我这是我所知的最早的缓冲区溢出攻击程序。

记住,造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数!!!

下面举一个最为常见的,也是最简单的溢出。

void function(char *str){

char buffer[16];

strcpy(buffer,str);

}

在这个例子中上面的buffer的长度被限制在16,而strcpy()将直接把str中的内容copy到buffer中。这样只要str的长度大于16,就会造成buffer的溢出,使程序运行出错。So,我们说这个程序溢出了。

在C语言中,静态变量是分配在数据段中的,动态变量是分配在堆栈段的。缓冲区溢出是利用堆栈段的溢出的。一个正常的程序在内存中通常分为程序段,数据端和堆栈三部分。程序段里放着程序的机器码和只读数据,这个段通常是只读,对它的写操作是非法的。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。在内存中,它们的位置如下:

/――――――――\内存低端

程序段

―――――――――

数据段

―――――――――

堆栈

\―――――――――/内存高端

堆栈是内存中的一个连续的块。一个叫堆栈指针的寄存器(SP)指向堆栈的栈顶。堆栈的底部是一个固定地址。堆栈有一个特点就是,后进先出。也就是说,后放入的数据第一个取出。它支持两个操作,PUSH和POP。PUSH是将数据放到栈的顶端,POP是将栈顶的数据取出。

在高级语言中,程序函数调用和函数中的临时变量都用到堆栈。为什么呢?因为在调用一个函数时,我们需要对当前的操作进行保护,也为了函数执行后,程序可以正确的找到地方继续执行,所以参数的传递和返回值也用到了堆栈。通常对局部变量的引用是通过给出它们对SP的偏移量来实现的。另外还有一个基址指针(FP,在Intel芯片中是BP),许多编译器实际上是用它来引用本地变量和参数的。通常,参数的相对FP的偏移是正的,局部变量是负的。

当程序中发生函数调用时,计算机做如下操作:首先把参数压入堆栈;然后保存指令寄存器(IP)中的内容,做为返回地址(RET);第三个放入堆栈的是基址寄存器(FP);然后把当前的栈指针(SP)拷贝到FP,做为新的基地址;最后为本地变量留出一定空间,把SP减去适当的数值。

比如说下面这个程序:

void function(int a, int b, int c){

char buffer1[10];

char buffer2[15];

}

void main(){

function(1,2,3);

}

假设我们在Linux下,用gcc对这段源码进行编译,产生汇编代码输出:

$ gcc -S -o example1.s example1.c

看看输出文件中调用函数的那部分:

pushl $3

pushl $2

pushl $1

call function

这就将3个参数推入堆栈里了,并调用function()。指令call会将指令指针IP压入堆栈。在返回时,RET要用到这个保存的IP。在函数中,第一要做的事是进行一些必要的处理。每个函数都必须有这些过程(为了保护呀,不然就找不到了。):

pushl %ebp

movl %esp,%ebp

subl $20,%esp

这几条指令将EBP,基址指针放入堆栈。然后将当前SP拷贝到EBP。然后,为本地变量分配空间,并将它们的大小从SP里减掉。由于内存分配是以字为单位的,因此,这里的buffer1用了8字节(2个字,一个字4字节)。Buffer2用了12字节(3个字)。所以这里将ESP减了20。这样,现在,堆栈看起来应该是这样的。

低端内存 高端内存

buffer2 buffer1 sfp ret a b c

< ------ [ ] [ ] [ ] [ ] [ ] [ ] [ ]

栈顶 栈底

那是什么导致了溢出呢?缓冲区溢出就是在一个缓冲区里写入过多的数据。要怎么样利用呢?看下面这个程序:

void function(char *str) {

char buffer[16];

strcpy(buffer,str);

}

void main() {

char large_string[256];

int i;

for( i = 0; i < 255; i++)

large_string[i] = 'A';

function(large_string);

}

||||||这个程序是一个经典的缓冲区溢出编码错误。函数将一个字符串不经过边界检查,拷贝到另一内存区域。当调用函数function()时,堆栈如下:

低内存端 高内存端

buffer sfp ret *str

< ------ [ ] [ ] [ ] [ ]

栈顶 栈底

很明显,程序执行的结果是"Segmentation fault (core

dumped)"或类似的出错信息。因为从buffer开始的256个字节都将被*str的内容'A'覆盖,包括sfp,

ret,甚至*str。'A'的十六进值为0x41,所以函数的返回地址变成了0x41414141,

这超出了程序的地址空间,所以出现段错误。可见,缓冲区溢出允许我们改变一个函数的返回地址,在这个例子中,我们可以通过修改0x41414141来改变程序返回后的入口地址。同样通过这种方式,就可以改变程序的执行顺序了。

存在象strcpy这样的问题的标准函数还有strcat(),sprintf(),vsprintf(),gets(),scanf(),以及在循环内的getc(),fgetc(),getchar()等。

缓冲区溢出技术基础

为了提高大家的技术水平,为了更了解我们讨论的这种技术,为了把这个论坛建成一个更更好的论坛,下面我为大家推出一系列完整的有关溢出,溢出攻击的文章。让大家更能了解到这个天天说但又不太清楚怎么回事的东西。我想,看了这个以后大家也不再会问,为什么我用了这个工具,怎么没有用呀什么的问题?

在这里强调一下,想完全看的懂这篇文章,至少需要具备一定的汇编语言,C语言和LINUX的基础。

缓冲区溢出”在英文中可以解释为:buffer overflow,buffer overrun,smash the

stack,trash the stack,scribble the stack, mangle the stack, memory

leak,overrun screw;

我们通常所说的“溢出”指的是缓冲区溢出,(废话,不然要从那里溢出呀!)先解释一下什么是缓冲区——缓冲区是内存中存放数据的地方,是程序运行时计算机内存中的一个连续的块,它保存了给定类型的数据。问题随着动态分配变量而出现。为了不用太多的内存,一个有动态分配变量的程序在程序运行时才决定给他们分配多少内存。当程序试图将数据放到计算机内存中的某一位置,但没有足够空间时会发生缓冲区溢出。另一种说法,就是说程序在动态分配缓冲区放入太多的数据会有什么现象?它会溢出,会漏到了别的地方。

一个缓冲区溢出应用程序使用这个溢出的数据将汇编语言代码放到计算机的内存中,通常是产生root权限的地方。单单的缓冲区溢出,并不会产生安全问题。只有将溢出送到能够以root权限运行命令的区域才行。这样,一个缓冲区利用程序将能运行的指令放在了有root权限的内存中,从而一旦运行这些指令,就是以root权限控制了计算机。

所以我们更多的时候把缓冲区溢出指的是一种系统攻击的手段,通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,使程序转而执行其它指令,以达到攻击的目的。据统计,通过缓冲区溢出进行的攻击占所有系统攻击总数的80%以上。

世界上第一个缓冲区溢出攻击——著名的Morris蠕虫,发生在十年前,它曾造成了全世界6000多台网络服务器瘫痪。我这是我所知的最早的缓冲区溢出攻击程序。

记住,造成缓冲区溢出的原因是程序中没有仔细检查用户输入的参数!!!

下面举一个最为常见的,也是最简单的溢出。

void function(char *str){

char buffer[16];

strcpy(buffer,str);

}

在这个例子中上面的buffer的长度被限制在16,而strcpy()将直接把str中的内容copy到buffer中。这样只要str的长度大于16,就会造成buffer的溢出,使程序运行出错。So,我们说这个程序溢出了。

在C语言中,静态变量是分配在数据段中的,动态变量是分配在堆栈段的。缓冲区溢出是利用堆栈段的溢出的。一个正常的程序在内存中通常分为程序段,数据端和堆栈三部分。程序段里放着程序的机器码和只读数据,这个段通常是只读,对它的写操作是非法的。数据段放的是程序中的静态数据。动态数据则通过堆栈来存放。在内存中,它们的位置如下:

/――――――――\内存低端

程序段

―――――――――

数据段

―――――――――

堆栈

\―――――――――/内存高端

堆栈是内存中的一个连续的块。一个叫堆栈指针的寄存器(SP)指向堆栈的栈顶。堆栈的底部是一个固定地址。堆栈有一个特点就是,后进先出。也就是说,后放入的数据第一个取出。它支持两个操作,PUSH和POP。PUSH是将数据放到栈的顶端,POP是将栈顶的数据取出。

在高级语言中,程序函数调用和函数中的临时变量都用到堆栈。为什么呢?因为在调用一个函数时,我们需要对当前的操作进行保护,也为了函数执行后,程序可以正确的找到地方继续执行,所以参数的传递和返回值也用到了堆栈。通常对局部变量的引用是通过给出它们对SP的偏移量来实现的。另外还有一个基址指针(FP,在Intel芯片中是BP),许多编译器实际上是用它来引用本地变量和参数的。通常,参数的相对FP的偏移是正的,局部变量是负的。

当程序中发生函数调用时,计算机做如下操作:首先把参数压入堆栈;然后保存指令寄存器(IP)中的内容,做为返回地址(RET);第三个放入堆栈的是基址寄存器(FP);然后把当前的栈指针(SP)拷贝到FP,做为新的基地址;最后为本地变量留出一定空间,把SP减去适当的数值。

比如说下面这个程序:

void function(int a, int b, int c){

char buffer1[10];

char buffer2[15];

}

void main(){

function(1,2,3);

}

假设我们在Linux下,用gcc对这段源码进行编译,产生汇编代码输出:

$ gcc -S -o example1.s example1.c

看看输出文件中调用函数的那部分:

pushl $3

pushl $2

pushl $1

call function

这就将3个参数推入堆栈里了,并调用function()。指令call会将指令指针IP压入堆栈。在返回时,RET要用到这个保存的IP。在函数中,第一要做的事是进行一些必要的处理。每个函数都必须有这些过程(为了保护呀,不然就找不到了。):

pushl %ebp

movl %esp,%ebp

subl $20,%esp

这几条指令将EBP,基址指针放入堆栈。然后将当前SP拷贝到EBP。然后,为本地变量分配空间,并将它们的大小从SP里减掉。由于内存分配是以字为单位的,因此,这里的buffer1用了8字节(2个字,一个字4字节)。Buffer2用了12字节(3个字)。所以这里将ESP减了20。这样,现在,堆栈看起来应该是这样的。

低端内存 高端内存

buffer2 buffer1 sfp ret a b c

< ------ [ ] [ ] [ ] [ ] [ ] [ ] [ ]

栈顶 栈底

那是什么导致了溢出呢?缓冲区溢出就是在一个缓冲区里写入过多的数据。要怎么样利用呢?看下面这个程序:

void function(char *str) {

char buffer[16];

strcpy(buffer,str);

}

void main() {

char large_string[256];

int i;

for( i = 0; i < 255; i++)

large_string[i] = 'A';

function(large_string);

}

这个程序是一个经典的缓冲区溢出编码错误。函数将一个字符串不经过边界检查,拷贝到另一内存区域。当调用函数function()时,堆栈如下:

低内存端 高内存端

buffer sfp ret *str

< ------ [ ] [ ] [ ] [ ]

栈顶 栈底

很明显,程序执行的结果是"Segmentation fault (core

dumped)"或类似的出错信息。因为从buffer开始的256个字节都将被*str的内容'A'覆盖,包括sfp,

ret,甚至*str。'A'的十六进值为0x41,所以函数的返回地址变成了0x41414141,

这超出了程序的地址空间,所以出现段错误。可见,缓冲区溢出允许我们改变一个函数的返回地址,在这个例子中,我们可以通过修改0x41414141来改变程序返回后的入口地址。同样通过这种方式,就可以改变程序的执行顺序了。

存在象strcpy这样的问题的标准函数还有strcat(),sprintf(),vsprintf(),gets(),scanf(),以及在循环内的getc(),fgetc(),getchar()等。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有