>假设我有以下程序:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
char buf [100];
snprintf ( buf, sizeof buf, argv [1] ) ;
buf [ sizeof buf -1 ] = 0;
printf ( "%s n" , buf ) ;
return 0 ;
}
如果我编译并运行它:
gcc test.c -o test
./test %p%p%p
(nil)0x4006d00x7f67e05b7ab0
我可以看到堆栈值,这意味着它受到格式字符串漏洞的影响。
现在,让我们稍微修改一下上面的代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main (int argc, char **argv)
{
char buf [100];
printf ( "%s n" , argv[1] ) ;
return 0 ;
}
如果我重新编译并重新运行它,漏洞就消失了:
gcc test.c -o test
./test %p%p%p
%p%p%p
为什么会这样,与第一个例子有什么变化?
另外,在第一个示例中,printf中的%s不应该将buf视为字符串吗?为什么此类代码仍然受到格式字符串漏洞的影响?
如果您希望第一个片段的输出与第二个片段匹配,则只需使用与printf
相同的格式说明符,即:
snprintf ( buf, sizeof buf, "%s", argv [1] );
^^^^
在这种情况下,argv[1]
字符串不被视为其他一些参数的格式化模板,您只需将%p%p%p
写入buf
。
您是否打算复制字符串?我问是因为snprintf
自动终止缓冲区,您不需要手动设置空终止符(这通常在使用strncpy
时完成(:
strncpy ( buf, argv [1], sizeof buf );
buf [ sizeof buf - 1 ] = 0;
您询问的是格式字符串漏洞。每当用户提供的字符串用作任何*scanf
或*printf
函数的格式时,就会发生格式字符串漏洞。
在第一个片段中,漏洞与snprintf
.在第二个片段中,您的printf
具有格式字符串"%s"
。它不是由用户提供的,因此没有漏洞。尝试
printf(buf);
snprintf ( buf, sizeof buf, argv [1] ) ;
您刚刚滥用了 snprintf,因为您没有传递参数以匹配您的格式字符串%p%p%p
。
所以你只有一个 UB。
例如,您应该(使用相同的格式字符串(
snprintf ( buf, sizeof buf, argv [1], argv[0], buff, "Hello, Show where string literals are stored" ) ;