探索黑客技术攻防,实战研究与安全创新

导航菜单

Windows7下的栈溢出原理与实践

在我们的生活中,存在的许许多多的漏洞,下面向大家介绍的就是平时比较常见的栈溢出漏洞的实践过程。我们将用一个非常简单的例子让大家对栈溢出漏洞有个直观的认识。下面是一个简单的密码验证程序,因为代码不严密,导致了栈溢出漏洞的产生。


#includestdio.h
#includestring.h
#definePASSWORD1234567
intverify_password(char*password)
{

intauthenticated;
charbuffer[8];//定义一个大小为8字节的数组,控制没溢出的字符串长度;(超出这个长度就发生溢出)
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//这个语句就直接导致了溢出的发生
returnauthenticated;
}
main()
{
intvalid_flag=0;
charpassword[1024];
while(1)
{
printf(请输入密码:);
scanf(%s,password);
valid_flag=verify_password(password);
if(valid_flag)
{
printf(密码错误!\n\n);
}
else
{
printf(恭喜,你通过了验证!\n);
break;
}
}
}


具体运行情况如图1所示。

A1.png

如果我们输入这样的密码,它也能通过,如图2所示。

A2.png

那么,出现这种情况的原因是什么呢?如图3所示,是程序运行时栈的情况。

A3.png

图3

学过C语言的人应该知道,一个字符串的结尾是以字符串截断符null作为字符串结束标志的。在这个程序中,我们开始定义的char型buffer数组长度为8,如果你输入的密码长度不等于8的话,那么这个密码验证程序的功能还是完善的,但是如果你的密码长度为8的话,这个栈溢出漏洞的危害就显现出来了。密码长度为8,buffer字符串数组的’结束标志就会溢出至intauthenticated的内存空间内,并将原来的数据覆盖。

观察源代码不难发现,authenticated变量的值来源于strcmp函数的返回值,之后会返回给main函数作为密码验证成功与否的标志变量:当authenticated为0时,表示验证成功,反之,验证不成功。下面我们用ollydbg来验证一下到底是不是这样,如图4所示,我们输入8个q。

A4.png

图4

在图5中,我们可以清楚地看到,8个q(ASCII中71代表q)将buffer数组全部占满,字符串截断符溢出至0018FB4C(即原authenticated的位置)。

A5.png

栈的具体变化情况如下表所示。

A6.png

通过上面的解释,大家对栈溢出应该有了一个初步的认识。这里介绍的栈溢出漏洞看起来很简单,但实际上栈溢出是最常见的内存错误之一,也是攻击者入侵系统时所用到的最强大、最经典的一类漏洞利用方式。但还要注意以下情况:

1)在观察内存的时候应当注意内存数据与数值数据的区别,电脑在存储数据的时候并不是按照我们平时记忆的方式存储。在调试环境中,内存有低到高分布,但在数值应用的时候确实由高位字节向低位字节进行解释。

2)在输入密码时,如果你输入的字符串小于原来定义的密码,是不能冲破验证程序的。

3)这个实验是在win764位环境下完成的,在其他环境下栈溢出的原理相同,但内存地址不同。

4)在WindowsXP以上系统中,系统增强了保护功能,有部分复杂的栈溢出不能在不做修改的情况下完成。

本文内容所提及均为本地测试或经过目标授权同意,旨在提供教育和研究信息,内容已去除关键敏感信息和代码,以防止被恶意利用。文章内提及的漏洞均已修复,作者不鼓励或支持任何形式的非法破解行为。