防止格式字符串漏洞

时间:2008-12-30 16:01:25

标签: string format

Windows系统中的“格式字符串漏洞”究竟是什么,它是如何工作的,以及如何防范它?

2 个答案:

答案 0 :(得分: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__)来做同样的事情。

答案 1 :(得分:2)

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

string s=getUserInput();
write(s)

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

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

输出:“03单位”。如果用户在第一个位置写了“%02d”...如果堆栈上没有参数,那么将获取其他内容。那是什么,如果这是一个问题取决于程序。

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

write("%s",s);

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

output(s);

一个link到维基百科的更多信息。