0day安全:软件漏洞分析技术-第二章-突破密码验证程序(一)

发布于:2022-10-14 ⋅ 阅读:(804) ⋅ 点赞:(0)

突破密码验证程序

实验目的

  • 本节实验研究怎样用非法超长密码去修改buffer的临界变量authenticated从而绕过密码验证程序

C编写密码验证程序

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

int verify_password (char *password)
{
	int authenticated;
    char buffer[8];
	authenticated = strcmp(password,PASSWORD);	//strcmp比较两个字符,若相等返回0
	strcpy(buffer,password);    //over flowed here
    return authenticated; 
} 
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("Congratulation! You have passed the verification!\n\n");
			break;
		}
	}
	return 0;
}

程序运行状态:
程序运行状态

准备知识

  • 在C语言中定义一个字符串 char 变量名[索引号] = ‘字符串’;
  • C语言规定在内存中用 '\0 ’ 来截断字符串,而 ‘\0’ 代表空字符(NULL),占用一个字节;
  • 若char password[8],定义了一个8个字符的字符串password,实际字节是7个,有一个被截断符 ‘\0’ 占用了;
  • 只要输入的password超过7个字符,就会发生溢出,直接修改邻接变量,甚至破坏栈帧中的其他重要数据;

栈帧布局

在这里插入图片描述

IDA静态分析

在这里插入图片描述

  • 用流程图观察函数和分支点在内存的位置
  • 双击计入调用验证函数的位置

在这里插入图片描述

  • 简单的分析下,调用完strcpy函数后将程序返回值赋给了eax寄存器
  • 记录下分支点和调用验证函数的内存地址,之后的动态分析会用到

Ollydbg

  • 在分支点和调用验证函数的内存地址前后,按上F2打上断点进行下一步分析

在这里插入图片描述

  • 点击运行可以发现程序停在断点处,执行strcpy函数,栈中的dest是目的地址,src是要复制的字符串

  • 并且观察栈中的情况,此时栈中只有我们写入的数据而已
    在这里插入图片描述

  • 点击下一步运行,发现栈中dest的目的地址替换成了我们刚刚的字符串

  • 而此时eax的值等于栈中0x0061FA64的值,即是函数的返回值1

  • 这个是在之前strcmp比较后得出的,字符串不等于1234567就返回1

在这里插入图片描述

  • 通过这里的观察我们可以发现栈中的分布,我们试着写超过7的字符串
  • 发现栈中值被修改成了我们输入字符串的ASCII编码,且eax寄存器的值,即函数返回值被修改了
  • eax的值变成7474,因为超过了buffer数组定义的8个字符,第9个和第10个的值就被写入邻栈(栈溢出)

在这里插入图片描述

  • 现在我们已经知道只要超过buffer规定的数组值,就可以修改eax寄存器中的值,若eax中的值为0时验证成功,反之,验证不成功;我们利用段溢出将恰好把eax的值改为0,就可以通过验证
  • 而字符串数据最后都有结束标志NULL(0),当我们输入8个字符填满buffer数组,作为结尾的NULL就会被刚好写入eax的内存地址中,将值变为0x00000000
  • 如下图,当输入8个字符时,第9个字节0x00将eax的高位字节0x00000001修改为0x00000000

在这里插入图片描述

  • 经过调式,我们即使不知道密码的值,只要输入一个为8个字符的字符串,那么隐藏的截断符0x00,就能修改eax低字节的1覆盖为0,从而绕过程序!修改邻接变量的值

在这里插入图片描述

  • 题外话:严格说来,并不是任何 8 个字符的字符串都能冲破上述验证程序。由代码中的authenticated=strcmp(password,PASSWORD),我们知道 authenticated 的值来源于字 符串比较函数 strcmp 的返回值。按照字符串的序关系,当输入的字符串大于“1234567” 时,返回 1,这时 authenticated在内存中的值为 0x00000001,可以用字串的截断符 NULL 淹没 authenticated 的低位字节而突破验证;当输入字符串小于“1234567”时(例如, “0123”等字符串),函数返回-1,这时 authenticated 在内存中的值按照双字-1 的补码 存放,为 0xFFFFFFFF,如果这时也输入 8 个字符的字符串,截断符淹没 authenticated 低字节后,其值变为 0xFFFFFF00,所以这时是不能冲破验证程序的。

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到