Mur*_*ray 5 c stack-overflow md5 buffer-overflow stack-smash
作为安全CS课程的一部分,我班的任务是利用漏洞利用堆栈/缓冲区溢出来击败密码检查。带有漏洞的代码如下:
#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;
}
Run Code Online (Sandbox Code Playgroud)
我了解经典的“堆栈粉碎”原理(我认为),并且这里存在一个明显的溢出漏洞,该漏洞correct_hash可以通过在提示时输入长度超过15个字符的密码来覆盖数组的前14个字节。但是,我不知道如何利用此功能使memcmp检查通过,从而完成挑战。我发现/尝试过的一些东西:
设置password为等价是correct_hash行不通的,因为password使用MD5()进行了哈希处理(无论如何都不可能将两者相等),因为scanf它将一个唯一的ASCII NUL字符精确地插入到它可用的30个空格中,这意味着两个数组永远不会等价。NUL另外(据我所知)字符不能在中间插入scanf字符串)。
用覆盖最大字节数scanf(将始终附加一个NUL字符)意味着的最后3个字节correct_hash将始终为0x00 0x91 0xeb。尝试随机生成一个16个字符的密码,然后将其散列为最后3个字节/字符的密码(由于使用了MD5,因此计算上很容易),但是由于使用strlen(password)(会给出一个值)而无法正常工作的29,而不是只在击中整理长度计数方便的东西像16感谢NUL在调用字符)MD5()。这意味着对MD5()Hash 的调用不会对16个字符的密码进行哈希运算以产生预期的输出,而是对16个字符进行哈希运算,password然后对13个字符进行哈希运算。correct_hash,产生不同的最终哈希值。
0x00 0x91 0xeb。我不确定通过随机MD5哈希计算来找到它是多么可行,但是这并不给我机会。一些注释(在上面的解释中提到):
scanf限制为29个字符串,但会附加一个ASCII NUL字符,从而总共可以覆盖30个字符(password数组中的16个字符,数组中的14 个字符correct_hash)。
NUL不能通过ASCII 字符输入,scanf因此对strlen(password)的调用MD5()(如果使用了最大密码长度)将为29。
所以这里的问题是,我还能怎么做呢?我错过了一些非常明显的东西吗?随机生成是可行的解决方案,还是唯一的解决方案?
该解决方案必须使用缓冲区溢出(否则,我想我可以执行类似preload a的操作memcmp,该操作始终返回0),并且必须作为shell脚本可执行(如果有任何关联)。
只是为了将评论合并到这里的答案中:
问题的关键是,它scanf会很乐意接受零字节作为字符串的一部分,并且不会将其视为空格(因此,不会停止将更多字节读入字符串)。
重定向文件或使用echo -ne "\x00" | program等。重定向输入文件可能是这里的首选方式。
我使用的最后一个命令是:echo -ne "\x49\x5a\x4e\x52\x48\x49\x41\x56\x5a\x43\x54\x52\x51\x4c\x4??3\x00\x81\xae\xf3\xd??f\xa2\x45\xb1\x57\x1??9\xb3\xa9\xb8\x7d\x0??0\x91\xeb" | ./vulnerable其中第一组 16 个字节(直到并包括第一个\x00)是一个随机生成的字符串,它在散列时生成第二组 16 个字节,并带有所需的\x00\x91\xeb结尾。无论如何都没有复制最后 3 个字节,但我将它们留在了显示字符串和哈希中。