我已经玩过这段代码了
#include <stdio.h>
#include <string.h>
void authenticated(void) {
printf("Authenticated\n");
fflush(stdout);
}
void authenticate() {
char buf[200];
char auth = 0;
printf("%p\n", &auth);
fflush(stdout);
fgets(buf, 200, stdin);
printf(buf);
fflush(stdout);
if (auth) {
authenticated();
}
}
int main(void) {
authenticate();
return 0;
}
编译时
gcc test.c -o test -fno-stack-protector -m32
我在这里按照本指南https://www.ayrx.me/protostar-walkthrough-format编写任意地址。
通过使用此输入
AAAA%6$p
我得到AAAA0x41414141
作为输出。现在使用打印的auth
地址作为输入
\xff\xff\xff\xff%x%x%x%x%x%x%n
我得到了Segmentation Fault
没有完全用auth
来理解这个主意,但这绝对是错误的:
fgets(buf, 200, stdin);
...
printf(buf);
printf
的第一个参数是一个控制字符串,永远不能来自用户的输入。可能有一个误解,就是printf
只是在输入上打印一个字符串。这不是真的。它从第一个参数开始执行“命令”,并且仅逐字打印那些未被识别为命令的字符。
简单的解决方法可能是:
printf("%s", buf);
这里“命令参数”包含一个“命令”:打印一个字符串,并将该字符串作为第二个参数传递。
类似地,可以使用:
puts(buf);
但是它另外在buf
的末尾添加了换行符。
我也将您的printf("Authenticated\n");
替换为puts("Authenticated");
。因为它的字符串文字中没有命令,所以它更快,更有效,但主要是更易读。
在一般流程中,printf使用fmt确定参数的类型,并将其复制到其输出。除非您对输出或输出控制结构的位置有一定的了解,否则尝试将随机堆栈字符串或其他类似内容塞入其中不会有太多的运气。