软件漏洞分析入门(三)

漏洞防护机制探索分析

GS安全编译机制

实际上,在之前的实验中,我们已经看到了GS的影子,这次实验我们将深入探讨一下这个GS保护机制

代码我们依然用之前用过的密码程序为例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PASSWORD "1234567"

int verify_password(char *password){
	int authentication;
	char buffer[8];
	authentication=strcmp(password, PASSWORD);
	strcpy(buffer,password);
	return authentication;
}

int main(){
	int valid_flag=0;
	char password[1024];

	while(1){
		printf("please input password:  ");
		scanf("%s",password);

		valid_flag=verify_password(password);
		if(valid_flag)
		{
			printf("incorrect password!\n\n");
		}
		else
		{
			printf("congratulations! you have passed the verification\n\n");
			break;
		}
	}
	system("pause");
}

GS 编译保护机制的原理是为每个函数调用增加了一个 security cookiesecurity cookieEBP 之前,而在 .data 内存区域还存在一个 security cookie 的副本,如果我们按照之前的步骤溢出覆盖掉函数的返回地址,那么这个 security cookie 将也会被覆盖掉,在函数返回之前,系统先将这个 security cookie 和内存存放的副本比较,如果两者不一致,则说明 security cookie 被破坏了,系统会立即抛出异常中止程序运行

VS 7.0 之后,所有的 VS 都默认启用了 GS。现在我们把这个 GS 关掉,然后对比一下

image-20220516203354228

我们把这个关掉GS的版本程序拖到 IDA 里面分析

image-20220516203832848

我们对比一下一下默认的版本和关掉GS后的版本

GS 在调用函数前会多生成一个 security cookie

image-20220516210555918

在函数返回前多一个步骤:检查 security cookie

扫描二维码关注公众号,回复: 15236980 查看本文章

image-20220516211608719

RTC机制

RTC是 Visual Studio 在编译程序时的一个安全选项

image-20220530204359699

RTC机制的原理是调用了VS的 CheckStackVars 函数相关功能,CheckStackVars 是微软开发的一个用来检查局部数据是否访问越界的功能,在数组的初始化阶段,会在数组之间填充 CCint 3 作为数组数据边界来保护缓冲区溢出,在程序运行阶段,一旦有数组缓冲区发生了溢出,_RTC_CheckStackVars 便会检查数组的前后边界有没有改变,一旦发生了改变,程序将抛出异常并提示哪一个数组发生了溢出

和GS对照实验一样,我们也同样分别编译一个打开了RTC检查的程序以及一个没打开的程序

image-20220530205844670

我们把两个程序分别拖到 IDA 里面去静态分析一下

image-20220530210021666

相比原版,RTC机制在初始化阶段多了两个地方,sub esp, 40Ch 这一步是为RTC多引入的函数分配栈空间,将预留的栈空间全部初始化为 cc

image-20220530210831276

在 main 函数内部,每次在涉及到数组的操作之前,都会调用 __RTC_CheckEsp 来对 esp,堆栈,寄存器的正确性进行安全检查,比如在 scanf 函数把我们输入的数据存到 Str1 也就是 Password 数组里面之前,就会调用一次

image-20220530211518125

在程序其他函数的数组操作之前,也同样会有这个 __RTC_CheckEsp 的检查

image-20220530212313407

在程序的结尾处,相比原来的程序,RTC机制又调用了 _RTC_CheckStackVars 函数用上文所说的方式对数组的边界进行了检查,防止数组缓冲区的溢出

image-20220530212957148

下面我们用 x32DBG 来动态调试一下这两个程序,到内存里面去看看RTC的作用

我们先来看看没有RTC保护的程序

在main函数处先打个断点,直接运行到此处

image-20220531185905055

在scanf函数之后打个断点,找一下input进去的数据存在哪儿

image-20220531190302172

输入 777777

image-20220531190429155

这里 ebp+408 的位置就 password 在内存里的位置

image-20220531190650150

image-20220531190726783

我们去转去内存里面看一看

image-20220531191119173

我们接着动态调试一下打开了RTC的程序,可以看到RTC机制让程序 “凭空” 多出来好几个函数,这些函数就是前面提到的保护函数

image-20220531191338256

我们也同样输入 777777 之后转去内存里面看看 password 的结构

image-20220531192109727

可以明显看出来,相比不开RTC的原版程序,password 在内存的位置附近多了很多 cc ,这这就是之前提到过的,在数组之间初始化填充 cc 来保护缓冲区溢出以及数据的越界访问就是RTC的一种工作方式


GS和RTC机制现如今基本上已经成为了编译程序的默认选项,而在windows平台上这类机制对标的就是Linux的canary机制,安全机制由浅入深,现在去各个CTF平台去做做PWN的题目会发现,NX,canary这种级别的防护基本上也都是默认开启的,由此看来,GS和RTC的原理分析还是很重要的,只有学会了原理,在以后绕过这类安全机制的时候才能融会贯通

猜你喜欢

转载自blog.csdn.net/SimoSimoSimo/article/details/125157760