格式化字符串利用,意外结果
Format String Exploit, unexpected result
我正在尝试在 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,因为它是缓冲区中同一输入字符串的组成部分。
这是某种保护机制还是我误解了什么?我的目标是覆盖 return 地址,我需要读取 8 个字节 (AAAABBBB),因为我在 64 位机器上工作。
利用字符串的伪代码看起来像这样
RETRNPTR%[decimal address of not_called - 8]u%[offset of RETRNPTR]$n
RETRNPTR是当前栈帧中存放return地址的内存地址。
所以我最担心的是,RETRNPTR 的 8 个字节似乎并不像我预期的那样连续存在于内存中。第二个问题是,%n 是 int 指针,意味着只写入了 4 个字节。我也很困惑,AAAA 之前的那些值来自哪里。
首先,您询问的是具有未定义行为的代码;代码的大部分行为确实应该被普通的 C 程序员认为是未定义的。
现在,至于你为什么看不到BBBB
。我想这是因为你是 运行 x86-64 系统上的这个程序。那里的调用约定是对堆栈中的值进行 64 位推送;但是 %x
打印 32 位 int
; 64 位堆栈值的 32 个最低有效位。要打印 64 位 long
值,请使用 %lx
.
(此外,在 System-V API 上,对于 x86-64,前 6 个 integer/pointer 参数根本不进入堆栈;它们在 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
我正在尝试在 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,因为它是缓冲区中同一输入字符串的组成部分。
这是某种保护机制还是我误解了什么?我的目标是覆盖 return 地址,我需要读取 8 个字节 (AAAABBBB),因为我在 64 位机器上工作。
利用字符串的伪代码看起来像这样
RETRNPTR%[decimal address of not_called - 8]u%[offset of RETRNPTR]$n
RETRNPTR是当前栈帧中存放return地址的内存地址。
所以我最担心的是,RETRNPTR 的 8 个字节似乎并不像我预期的那样连续存在于内存中。第二个问题是,%n 是 int 指针,意味着只写入了 4 个字节。我也很困惑,AAAA 之前的那些值来自哪里。
首先,您询问的是具有未定义行为的代码;代码的大部分行为确实应该被普通的 C 程序员认为是未定义的。
现在,至于你为什么看不到BBBB
。我想这是因为你是 运行 x86-64 系统上的这个程序。那里的调用约定是对堆栈中的值进行 64 位推送;但是 %x
打印 32 位 int
; 64 位堆栈值的 32 个最低有效位。要打印 64 位 long
值,请使用 %lx
.
(此外,在 System-V API 上,对于 x86-64,前 6 个 integer/pointer 参数根本不进入堆栈;它们在 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