#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/md5.h>
int main(int argc, char **argv) {
char correct_hash[16] = {
0xd0, 0xf9, 0x19, 0x94, 0x4a, 0xf3, 0x10, 0x92,
0x32, 0x98, 0x11, 0x8c, 0x33, 0x27, 0x91, 0xeb
};
char password[16];
printf("Insert your password: ");
scanf("%29s", password);
MD5(password, strlen(password), password);
if (memcmp(password, correct_hash, 16) == 0) {
printf("Correct Password!\n");
} else {
printf("Wrong Password, sorry!\n");
}
return 0;
}
我理解了经典的“堆栈溢出”原理(我想),并且在这里存在明显的溢出漏洞,即在提示输入密码时,如果输入的密码长度超过15个字符,则可以覆盖
correct_hash
数组的前14个字节。然而,我不明白如何利用这一点使memcmp
检查通过,从而完成挑战。我已经发现/尝试了一些事情:
将
password
设置为等同于correct_hash
是行不通的,因为password
使用MD5()
进行哈希处理(两者相等是不可能的,因为scanf
将在可用的30个空间中插入precisely一个唯一的ASCIINUL
字符,这意味着两个数组永远不可能相等。此外,据我所知,NUL
字符不能在scanf
字符串的中间插入)。用
scanf
覆盖最大数量的字节(它将始终附加一个NUL
字符)意味着correct_hash
的最后3个字节将始终是0x00 0x91 0xeb
。尝试随机生成一个16个字符的密码,然后将其哈希为具有这些最后3个字节/字符的内容(由于使用MD5,这是相当容易的),但由于在调用MD5()
时使用了strlen(password)
(它会给出一个值为29而不是像16这样方便的值,因为只有在遇到NUL
字符时才完成长度计数)这意味着,与其将16个字符的密码哈希以产生预期输出,不如将MD5()
的调用哈希从password
中取出16个字符,然后再取出13个字符从correct_hash
中取出13个字符,从而产生不同的最终哈希值。- 为了解决这个问题,我认为人们必须找到一个29个字符的字符串(称之为S),其中S的前16个字符哈希为一个字符串R,该字符串由S的最后13个字符组成,后跟
0x00 0x91 0xeb
。我不确定通过随机MD5哈希计算找到这个字符串的可行性,但我不喜欢我的机会。
- 为了解决这个问题,我认为人们必须找到一个29个字符的字符串(称之为S),其中S的前16个字符哈希为一个字符串R,该字符串由S的最后13个字符组成,后跟
一些注意事项(上面的解释中提到):
scanf
指令只能读取29个字符的字符串,但会附加一个ASCIINUL
字符,从而使总共可以覆盖30个字符(来自password
数组的16个字符和correct_hash
数组的14个字符)。ASCII
NUL
字符无法通过scanf
输入,因此在调用MD5()
时,如果使用最大密码长度,则strlen(password)
将为29。
所以问题来了,我还有别的方法吗?我错过了非常明显的东西吗?生成随机数是可行的解决方案,甚至是唯一的解决方案吗?
解决方案必须使用缓冲区溢出(否则我想我可以做一些类似于预加载永远返回0的memcmp
之类的事情),并且必须作为shell脚本执行(如果这有任何相关性)。
char password[16]; ... scanf("%29s", password);
并不是在利用漏洞,而是故意制造漏洞。 - Weather VaneNUL
字节并不容易。 - chqrlieecho -ne "\x00" | program
这样的命令。 - Ctxecho -ne "\x49\x5a\x4e\x52\x48\x49\x41\x56\x5a\x43\x54\x52\x51\x4c\x43\x00\x81\xae\xf3\xdf\xa2\x45\xb1\x57\x19\xb3\xa9\xb8\x7d\x00\x91\xeb" | ./vulnerable
。其中第一组 16 个字节(包括第一个\x00
)是随机生成的字符串,当哈希时生成第二组 16 个字节,并以所需的\x00\x91\xeb
结尾。最后的 3 个字节没有被复制,但我将它们留在那里以显示字符串和哈希值。 - Murray