如果用户可控制的输入被当做格式化字符串参数提交给一个接受可能被滥用的格式说明符的函数(如C语言中的printf系列函数),就会产生格式化字符串漏洞。这些函数接受的参数数量不定,其中可能包含不同的数据类型,如数字和字符串。提交给函数的格式化字符串中包含的说明符告诉函数:变量参数中应包含何种数据,以及这些数据以什么格式表示。
例如,下面的代码输出一条包含以十进制表示的count变量值的消息:
最危险的格式说明符为%n。这个说明符不会导致什么数据被打印。相反,它使已经输出的字节数量被写入到以相关变量参数提交给函数的指针地址中。例如:
它输出:
如果格式化字符串中的说明符比提交给函数的变量参数多,而函数又无法探查到这一点,那么它就会继续处理调用栈中的参数。
如果攻击者能够控制提交给printf之类函数的全部或部分格式化字符串,他就可以利用上述行为重写进程内存的重要部分,并最终执行任意代码。由于攻击者控制着格式化字符串,所以他能够控制函数输出的字节数量以及栈上被输入的字节数量重写的指针。这样,攻击者就能够重写一个已保存的返回地址或者一个指向异常处理器的指针,进而控制代码执行,就像在栈溢出中一样。
查找格式化字符串漏洞
在远程应用程序中探查格式化字符串漏洞的最有效方法是,提交包含各种格式说明符的数 据,并监控应用程序的任何反常行为。与不受控制地触发缓冲区溢出漏洞可能造成的后果一样,在一个易受攻击的应用程序中探查格式化字符串漏洞可能会导致系统崩溃。