软件漏洞分析入门(二)

栈缓冲区初步调试

本次实验包含64位和32位的反汇编分析,主要内容是调试验证栈缓冲区溢出之后栈数据的变化、执行流程的变化

本次实验用的工具包含 IDA pro 以及 x64dbgx32dbg (没用 ollydbg 是因为分析x64的反汇编太复杂了)

编译栈溢出实验代码

下面这是一段在各种软件安全教材中高频出现的经典代码

//stack_over_ret.c

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
    
    
	int authenticated;
	char buffer[8];
	authenticated=strcmp(password,PASSWORD);
	strcpy(buffer,password);//over flowed here!	
	return authenticated;
}
main()
{
    
    
	int valid_flag=0;
	char password[1024];
	FILE * fp;
	if(!(fp=fopen("password.txt","r")))
	{
    
    
		exit(0);
	}
	fscanf(fp,"%s",password);
	valid_flag = verify_password(password);
	if(valid_flag)
	{
    
    
		printf("incorrect password!\n");
	}
	else
	{
    
    
		printf("Congratulation! You have passed the verification!\n");
	}
	fclose(fp);
	system("pause");
}

IDA 分析

这段代码需要在同目录下有一个 password.txt 文件作为输入
我们先实验一下,文件内如果是正确的密码,窗口提示正确,

image-20220409223715034

编译文件,拖到 IDA 里 逆向,各种函数的跳转流程非常清晰

发现在箭头的地方产生了判断语句的分支

image-20220409224836773

动态调试

找到分支位置之后,去 x64dbg 里调试,直接定位到定位的位置

image-20220410001226631

image-20220410001310935

image-20220410001325831

mov     [rbp+6B0h+var_6AC], eax ;eax存的是密码检测函数的返回值
cmp     [rbp+6B0h+var_6AC], 0   ;将函数返回值和0比较
jz      short loc_140011AD8     ;如果是0则正确,不是0则错误

知道这个判断的位置之后,可以来动态修改判断的分支,绕过这个判断分支
我们把这个 je 改成 jne 就可以使错误的密码也能通过验证

我们把密码文件改成错误的 5555555

image-20220410002235278

定位到 je 指令处,把 je 机器码从 74 0E 编辑为 75 0Ejne

image-20220410002613672

成功绕过

利用栈溢出控制执行流程

password.txt 内容改为 7777777,方便定位

image-20220410024151883

找到栈中 7777777 的位置

image-20220410024243266

我们让 password 越界溢出,执行程序看看会怎样

image-20220410030912129

程序直接崩溃了

image-20220410024616570

我们可以看到,越界的 “7” 直接往后填充了

image-20220410031018271

接下来的部分我们换成x86,32位的程序进行分析(因为64位的程序函数调用的并不像32位一样直接进栈,参数超过)

还是先放到 IDA 里面

image-20220410233250930

x64dbg 里找到最关键的 verify_pasword 函数入口,写个注释

image-20220410233517736

password.txt010 editor 打开,后面用 nop0x90 填充,一直填充到返回地址附近

image-20220410234555147

nop 已经接近返回地址了

image-20220410234735896

接着往后填充,把返回地址填充为 00D81182

image-20220410234936454

image-20220410235110362

可以看到返回地址处已经改成了想要的 00D81182

image-20220410235409945

栈溢出的保护机制

如果当读者跟着笔记的操作步骤一步一步实验,会发现到最后不论怎么样都不会实验成功,这是因为系统和编译器在编译程序的时候会默认启用一些针对栈溢出的保护机制,让栈溢出的漏洞不那么容易利用。关于这些保护机制,我们在下一期笔记中会继续探讨。

猜你喜欢

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