我正在尝试在 64 位 Linux 上用 C 实现格式字符串漏洞的简单示例。这是我的源代码:
void not_called() {
printf("Exploited\n");
}
int main(int argc, char **argv) {
// Buffer overflow vulnerability
char buffer[256];
gets(buffer);
// User may input the format string
printf(buffer);
}
我将以下字符串输入到程序中
AAAABBBB-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x-%x
结果是
AAAABBBB-8608002c-f458fe00-fbad2288-78252d78-252d7825-5e5c51a8-0-41414141-2d78252d-78252d78-252d7825-2d78252d
我可以将 AAAA 识别为 41414141
,但不能像我预期的那样识别后面的 BBBB,因为它是缓冲区中同一输入字符串的组成部分。
这是某种保护机制还是我误解了什么?我的目标是覆盖返回地址,并且我需要读取 8 个字节 (AAAABBBB),因为我在 64 位机器上工作。
利用字符串的伪代码看起来像这样
RETRNPTR%[decimal address of not_called - 8]u%[offset of RETRNPTR]$n
RETRNPTR是当前栈帧中存储返回地址的内存地址。
所以我最担心的是,8 个字节的 RETRNPTR 似乎并没有像我期望的那样连续存在于内存中。第二个问题是,%n 是 int 指针,意味着只写入 4 个字节。我也很困惑,AAAA 之前的那些值是从哪里来的。
最佳答案
首先,您询问的是具有未定义行为的代码;对于普通 C 程序员来说,代码的大部分行为确实应该被认为是未定义的。
现在,为什么你看不到BBBB
。我猜这是因为你在 x86-64 系统上运行这个程序。那里的调用约定是对堆栈上的值进行 64 位压入;但是 %x
打印 32 位 int
; 64 位堆栈值的 32 个最低有效位。要打印 64 位 long
值,请使用 %lx
。
(此外,在 x86-64 的 System-V API 上,前 6 个整数/指针参数根本不进入堆栈;它们位于 RDI
、RSI
、RDX
、RCX
、R8
和 R9
寄存器)。
例如我输入:
AAAABBBB %lx %lx %lx %lx %lx %lx %lx %lx %lx %lx
并得到输出
AAAABBBB 7f7c0a88f030 7f7c0a66b980 7f7c0a669980 7f7c0a88f031 786c2520786c2520 7ffc1456b6f8
100000000 4242424241414141 786c2520786c2520 786c2520786c2520
关于c - 格式化字符串漏洞,意外结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36428345/