Windows内存漏洞——栈溢出漏洞及其利用分析

栈溢出漏洞及其利用分析

栈帧的标识

  • ESP:扩展栈指针寄存器,其存放的指针指向栈顶
  • EBP:扩展基址指针寄存器,其存放的指针指向栈底
  • EIP:扩展指令指针寄存器,其存放的指针指向下一条要执行的指令

栈帧中的内容

一个函数栈帧中主要包含的信息:

  • 前一个栈帧的栈底位置,也就是前栈帧的EBP,用于在函数调用结束后恢复主调函数的栈帧
  • 该函数的局部变量
  • 函数调用的参数
  • 函数的返回地址RET,用于保存函数调用前指令的位置,以便函数返回时能恢复到调用前的代码区继续执行指令

栈溢出漏洞的基本原理

  • 在函数的栈帧中,局部变量是顺序排列的,局部变量下面紧跟着的是前栈帧EBP及函数返回地址RET。如果这些局部变量为数组,由于存在越界的漏洞,那么越界的数组元素将会覆盖相邻的局部变量,甚至覆盖前栈帧EBP及函数返回地址RET,从而造成程序的异常。

栈溢出修改相邻变量

void fun()
{
	char psaaword[6] = "ABCDE";
	char str[6];
	gets(str);
	srt[5] = '\0';
	if(strcmp(str,password)==0)
	{
		printf("OK.\n");
	}else
	{
		printf("NO.\n");
	}
}
int main()
{
	fun();
	return 0;
}
  • 由于c语言中没有越界检查,因此当用户输入的口令超过两个字节时,将会覆盖相邻的password数组。此时,password数组和str数组的内容就会是同一个字符串。因此,在不知道正确口令的情况下,只要输入13个字符,其中前五个字符与后五个字符相同,就可以绕过口令的验证了。
  • 如果用户增加输入字符串的长度,将会超过password数组的边界,从而覆盖前栈帧ESP,甚至是覆盖返回地址RET。当返回地址RET被覆盖后,将会造成进程跳转的异常。

栈溢出后修改返回地址RET

  • #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    void Attack()
    {
    	printf("Hello\n");//当该函数被调用成功时,说明溢出攻击成功
    	exit(0);
    }
    void fun()
    {
    	char password[6] = "ABCDE";
    	char str[6];
    	FILE *fp;
    	if(!fp=fopen("password.txt","r"))
    	{
    		exit(0);
    	}
    	fscanf(fp,"%s",str);
    	
    	str[5]='\0';
    	if(strcmp(str,password)==0)
    	{
    		printf("OK.\n");
    	}else
    	{
    		printf("NO.\n");
    	}
    }
    int main()
    {
    	fun();
    	return
    }
    
  • 如果在password文件中存入23俄国字符,程序运行结果将与从键盘输入一致。为了让程序在调用fun()函数返回后去执行所希望的函数Attack(),必须将password文件中的最后四个字节改为Attack()函数的入口地址。(用OllyDbg工具查看得到地址为0x0040100F),利用十六进制编译软件UItraEdit打开password修改最后四个字节。

  • 这样,运行该程序,Attack函数被正常执行。

栈溢出攻击

  • 攻击者通过缓冲区改写的目标不再是一个变量,而是栈帧高地址的EBP和函数的返回地址等值。通过覆盖程序中的函数返回地址和函数指针等值,攻击者可以直接将程序跳转到其预先设定或已经注入到目标程序的代码上去执行。
JMP ESP覆盖方法

由于动态链接库的装入和卸载等原因,windows进程的函数栈帧可能发生移位,也就是说shellcode在内存中的地址是动态变化的,所以只采用简单方式链接进行跳转是极有可能出错的

  • 所以,可以在覆盖返回地址时用系统动态链接库中某条处于高地址且位置固定的跳转指令所在的地址进行覆盖,然后再通过这条指令指向动态变化的Shellcode地址。
  • 在这种方法中,输入被攻击程序的字符串格式为NN…NNRSS…SS,其中N表示可以填入的一些无关的数据,R表示JMP ESP的地址,S表示Shellcode。
  • 当函数返回时,取出JMP ESP覆盖法攻击,攻击者需要做如下工作
    • 分析调试有漏洞的被攻击程序,活得栈帧的状态
    • 获取本机JMP ESP指令的地址
    • 写出希望运行的Shellcode
    • 根据栈帧状态,构造输入字符串
SEH覆盖方法

Windows异常处理机制所依赖的便是SEH结构体,他包含两个DWORD指针

  • SHE链表指针prev,用于指向下一个SEH结构
    • 异常处理函数句柄handler,用于指向一场函数处理的指针。
  • 当线程初始化时,会自动向栈中安装一个异常处理结构,作为线程默认的异常处理,这样多个异常处理程序就连结成了一个由栈顶向栈底延申的单链表,链表头部位置通过TEB(线程控制块)0字节偏移处的指针标识。
  • 如果发生异常,OS会中断程序,并且首先从TEB的0字节处去除最顶端的SEH结构地址,使用异常处理函数句柄所指向的代码来处理异常。如果该异常函数运行失败,则顺着SHE链表依次尝试其他的异常处理函数。(如果程序预先安装的所有异常处理函数均无法处理,系统将采用默认的异常处理函数,弹出错误对话框并强制关闭程序)
  • SEH覆盖方法就是覆盖异常处理程序地址的一种攻击方式。由于SHE结构存放在栈中,因此攻击者可以利用栈溢出漏洞设计特定的溢出数据,将SEH结构中异常函数入口地址覆盖为Shellcode的其实地址或可以跳转到Shellcode的跳转指令地址,从而导致程序发生异常时,Windows异常处理机制执行的不是预设的异常处理函数,而是Shellcode。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值