3

Windows 系统中的“格式字符串漏洞”到底是什么,它是如何工作的,我该如何防范?

4

2 回答 2

4

最简单的格式字符串攻击是这样的:

char buffer[128];
gets(buffer);
printf(buffer);

那里也存在缓冲区溢出漏洞,但重点是:您正在将不受信任的数据(来自用户)传递给printf使用该参数作为格式字符串的(或其表亲之一)。

也就是说:如果用户输入“%s”,你就有了信息泄露漏洞,因为printf会将用户输入视为格式字符串,并尝试将堆栈中的下一个内容作为字符串打印。就好像你的代码说printf("%s");. 由于您没有将任何其他参数传递给printf,因此它将显示任意内容。

如果用户键入“%n”,则可能会受到特权提升攻击(至少是拒绝服务攻击),因为 %n 格式字符串会导致printf将目前打印的字符数写入下一个位置在堆栈上。因为你没有给它一个放置这个值的地方,它会写到任意的地方。

printf这一切都很糟糕,这也是您在使用和堂兄弟时应该非常小心的原因之一。

你应该做的是:

printf("%s", buffer);

这意味着用户的输入永远不会被视为格式字符串,因此您可以免受特定攻击向量的影响。

在 Visual C++ 中,您可以使用__Format_string注释告诉它验证printf. %n默认情况下是不允许的。在 GCC 中,您可以__attribute__(__printf__)用于同样的事情。

于 2008-12-30T16:23:12.247 回答
2

在这个伪代码中,用户输入一些要打印的字符,比如“hello”

string s=getUserInput();
write(s)

这按预期工作。但是由于 write 可以格式化字符串,例如

int i=getUnits();
write("%02d units",i);

输出:“03 个单位”。如果用户首先写了“%02d”怎么办......因为堆栈上没有参数,所以会获取其他东西。那是什么,以及这是否是一个问题取决于程序。

一个简单的解决方法是告诉程序输出一个字符串:

write("%s",s);

或使用另一种不尝试格式化字符串的方法:

output(s);

包含更多信息的维基百科链接。

于 2008-12-30T16:21:36.260 回答