简单的万能密码

简单的万能密码

在web中存在诸如’ or 1=1–类似的万能密码,其实现原理是sql的闭合,导致执行逻辑永真,于是绕过登录密码的限制。

同理,在c语言的项目中也可能会出现同样的问题。

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define PASSWORD "password"

int main() {
int nFlag = 0;
char szBuffer[8] = { 0 };
char szPassWord[12] = { 0 };
while (true) {
printf("请输入密码:");
scanf("%s", szPassWord);
nFlag = strcmp(PASSWORD, szPassWord);
strcpy(szBuffer, szPassWord);
if (!nFlag) {
printf("Hello World(Flag=%d)\n", nFlag);
system("pause");
exit(0);
}
}
return 0;
}

显而易见,在strcmp后有一个很奇怪的strcpy。它将一个大字符串覆盖到小字符串中会出现数组越界的问题。当攻击者构造一个长度足够长的字符串并将其赋值给szBuffer时,数组越界并覆盖到了nFlag,使得条件永真,条件判断失效。

正常情况下的数组内容

当输入小于数组szBuffer长度的内容的时候,即正常情况下的内存布局如图:

正常情况的结果

字符串结尾的’\0’正是万能密码的关键。

众所周知,strcmp函数比较两个字符串的内容,返回值如下:

1
2
3
如果返回值 < 0,则表示 str1 小于 str2。
如果返回值 > 0,则表示 str2 小于 str1。
如果返回值 = 0,则表示 str1 等于 str2。

当输入纯数字时,由于数字的ascii码比字母小,所以返回值>0,结果为1。当对nFlag取反时即变为假,此时的逻辑为正常逻辑。

那么,当攻击者构造了一个足够长的数组以至于可以覆盖掉nFlag的内容会发生什么呢?

经过构造后的数组

构造后的数组

可以看出,字符串的结尾’\0’覆盖掉了本应属于nFlag的位置,导致nFlag=0,逻辑判断成立,最简单的万能密码完成。

当strcmp的返回值为负数时的情况

如题,当字符串大于PASSWORD的值的时候回出现什么问题呢?

负数的问题

由此可见,没有办法对负数的条件进行修改。由于用户无法直接输入真正的’0’,导致高三位的ff无法被覆盖,取反后仍然是零。没办法对负数进行绕过。