缓冲区漏洞千千种,这次遇到实验才来讲一讲我想明白的题目。
利用栈溢出漏洞破解口令
源码:
#include<stdio.h> #include<string.h> #define PASSWORD "1234567" int verify_password(char* password) { int authenticated=0xEEEEEEEE; char buffer[8]; printf("My stack looks like: %p %p %p %p %p %p %p %p %p "); authenticated=strcmp(password,PASSWORD); printf("My stack looks like: %p %p %p %p %p %p %p %p %p "); //printf("flag的值为:%d ",authenticated); strcpy(buffer,password); printf("%s ",buffer); printf("My stack looks like: %p %p %p %p %p %p %p %p %p "); //printf("覆盖以后flag的值为:%d ",authenticated); return authenticated; } int main() { int valid_flag=0x0; char password[8]; printf("please input password:"); scanf("%s",password); //printf("传的值为:%d ",verify_password(password)); valid_flag=verify_password(password); //printf("传完之后flag的值为:%d ",valid_flag); if (valid_flag) { printf("incorrect password! "); } else { printf("Congratulation! You have passed the verification! "); } }
1.首先,观察一下程序,能判断造成栈溢出的代码是
strcpy(buffer,password);
把执行到调用verify_password函数的堆栈来画一下
2.来分析一下代码的作用
(注:strcpy比较的是ASCII值,数字输入时虽然是“数字”,但是它是字符串)
我们能够使用strcpy覆盖并修改return给main函数的值,让main函数误以为我们输入了正确的密码。
看下面代码知判断密码正确的flag值为0,否则为不正确(包括大于0和小于0),因此我们就要return给valid_flag一个0。
3.首先运行
输入12个2,因为buffer最多存8个字节,会溢出4字节到紧接着的堆栈,字符串结尾还有00(' ')也要存储
flag值被结束符00覆盖了,因此被误认为输入正确
4.特殊情况
如果输入12个1为什么会认为输入错误呢?
首先strcpy是逐位比较,遇到不同位相减返回值的,输入12个1,遇到第二位2时,1-2=-1,因此返回-1(16进制存的是补码为FFFFFFFF)
因为return的值即flag位的数为负数,存储时补码占4字节,虽然字符串有结束符00,但是还远远不能覆盖,返回的值不为0,因此被判断为输入错误
实际上只要输入的字符为12位,且第一个不同位的ASCII值比预设密码的那位ASCII值大就能绕过密码的判断了。