我正在寻找找出为什么strncpy被认为是不安全的。 是否有人对此有任何形式的文档或使用它的漏洞利用示例?
-
据我了解,strcpy是不安全的,而strncpy是该版本的安全版本。
-
名称上没有_s。不能没有_s ...
-
如果您使用的是c ++,请不要使用它,而应使用std :: string。
-
strncpy并非被设计为strcpy的安全版本,但为此滥用了它。有关说明,请参见此处:lysator.liu.se/c/rat/d11.html。现在人们可以争论strncpy的设计是否错误。历史是C委员会的借口:)如果您需要安全版本的strcpy,我建议您使用其他功能。
-
这些都是strncpy和strcpy的好答案,但是我真的对strncpy_s更感兴趣。
-
这不是唯一不安全的方法,首先是不能保证结果被nul终止的错误设计。
-
@stimms:当您说"对strncpy_s更感兴趣"时,您是说strncpy_s()可能是不安全的,还是为什么strncpy()与strncpy_s()相比是不安全的? strncpy_s()是strncpy()的"安全"版本,它所做的一切(不同于strncpy())都要求您指定目标缓冲区的长度。
-
@Tim我确实在寻找"为什么与strncpy_s()相比,strncpy()不安全?"
-
阅读这些内容:strlcpy和strncpy。写得很好。
-
我听说strcpy在Windows版本中并不安全,但Linux版本更好。
-
@马克·W:那是完全不正确的理解。 strncpy不是strncpy的安全版本。 strncpy与strcpy完全无关。
-
我对strncpy()主题的咆哮:the-flat-trantor-society.blogspot.com/2012/03/
-
刚发现这篇有趣的文章:lwn.net/Articles/507319关于strlcpy不被glibc接受,并指出应根据情况对字符串大小进行检查。
看一下这个站点;这是一个相当详细的解释。基本上,strncpy()不需要NUL终止,因此容易受到各种攻击。
-
好点子。因此,即使使用strncpy,也要确保缓冲区以 0结尾。
-
+1,但要注意的是strncpy仅在您忘记手动添加空终止符时才不安全。如果您记不起,请考虑包装函数,该函数总是在调用strncpy之后将最终字符设置为 0。
-
@ojrac,我认为包装器至少在Microsoft C运行时用户名为strncpy_s()。还有_wcsncpy_s(),适合广泛使用char的爱好者。
-
@RBerteig,请注意,MS strncpy_s和company不是1:1 strncpy替换,因为它们不会将缓冲区零填充。尽管IMHO strl *功能更通用,更快捷,但它们还是更好的脚本。 @ojrac,它仍然很容易被滥用,因为您必须记住两者并复制(bufsize-1)而不是(bufsize),或者将" rm -Rf / a"转换为" rm -Rf /"。
-
@jbcreix:也不保证strncpy用零填充缓冲区。
-
" NULL终止"不正确。 ASCII字符\0通常写为" NUL",以避免与NULL指针混淆。
-
@克里斯·卢茨:指出,纠正,谢谢。
-
@Billy ONeal,opengroup.org / onlinepubs / 007908775 / xsh / strncpy.html,opengroup.org / onlinepubs / 009695399 / functions / strncpy.html和C1x草案不同意您的看法。除非ANSI C另有说明,否则非零填充不是标准行为。再说一次,微软根本不支持C。他们所拥有的只是一个C ++编译器。
-
该链接已死。它在其他地方可用吗?
-
那个特定的利用方法对于这个答案并不关键。您可以通过Google找到几个等效的漏洞。例如,请参阅探索针对strncpy的相邻内存。
-
@ Sionide21:我已经编辑了答案,但是正在审核中。以下是链接:blogs.msdn.com/b/oldnewthing/archive/2005/01/07/348437.aspx
-
与其他答案相同的问题。 strncpy是转换功能,不是安全字符串复制功能。它将零终止的字符串转换为固定字符串。固定字符串通常不以零结尾,这就是为什么strncpy的结果通常不应该以零结尾的原因。仅仅因为不称职的代码编写者经常滥用strncpy来进行"安全字符串复制",而这是基于strncpy固有的某些"不安全性"主张的基础。
-
@Chris Lutz:NUL和NULL之间的差异与两者之间的潜在混乱无关。 ASCII空字符早于C宏NULL。在ASCII中,控制字符通常缩写为两个或三个大写字符,因此空字符的缩写为NUL。而且,实际上,U + 0000的正式Unicode名称为" NULL",与公共C宏巧合。
最初的问题显然是strcpy(3)不是内存安全操作,因此攻击者提供的字符串可能比缓冲区长,这将覆盖堆栈上的代码,并且如果精心安排,可以执行攻击者的任意代码。
但是strncpy(3)的另一个问题是,它不会在每种情况下都在目标位置提供空终止。 (想象一个源字符串长于目标缓冲区。)将来的操作可能会期望在大小相等的缓冲区之间符合C nul终止的字符串,并且在将结果复制到第三个缓冲区时会在下游发生故障。
使用strncpy(3)比strcpy(3)更好,但是像strlcpy(3)这样的东西仍然更好。
-
strncpy并不比strcpy好。 strlcpy在可用的地方很有用,在没有的地方很容易重写。
为了安全地使用strncpy,必须(1)手动将空字符粘贴到结果缓冲区上;(2)事先知道缓冲区以空值结尾,然后将(length-1)传递给strncpy,或者(3)知道缓冲区永远不会使用不会将其长度绑定到缓冲区长度的任何方法进行复制。
重要的是要注意,strncpy将对缓冲区中的所有内容进行零填充(超过复制的字符串),而其他受长度限制的strcpy变体则不会。在某些情况下,这可能会导致性能下降,但在其他情况下,这会带来安全优势。例如,如果使用strlcpy将" supercalifragilisticexpalidocious"复制到缓冲区中,然后再复制" it",则缓冲区将保存" it ^ ercalifragilisticexpalidocious ^"(使用" ^"表示零字节)。如果将缓冲区复制为固定大小的格式,则多余的数据可能会随之标记。
该问题基于"已加载"的前提,这使问题本身无效。
最重要的是,strncpy不被视为不安全,也从未被视为不安全。可以附加到该功能的唯一"不安全性"主张是C内存模型和C语言本身普遍不安全的广泛主张。 (但这显然是一个完全不同的话题)。
在C语言领域中,strncpy固有的某种"不安全性"的误导性信念源于使用strncpy进行"安全字符串复制"的普遍可疑模式,即该功能无法执行且从未执行过旨在。这样的用法确实很容易出错。但是,即使您在"容易出错的高度"和"不安全的"之间打上等号,仍然是使用问题(即缺乏教育问题)而不是strncpy问题。
基本上,可以说strncpy的唯一问题是一个不幸的命名,这使新手程序员假定他们了解此函数的作用,而不是实际阅读规范。一个不称职的程序员在看函数名称时会假定strncpy是strcpy的"安全版本",而实际上这两个函数是完全不相关的。
例如,可以对除法运算符提出完全相同的主张。众所周知,关于C语言的最常提出的问题之一是"我假设1/2将评估为0.5,但我却得到了0。为什么?"但是,我们并不认为除法运算符不安全是因为语言初学者往往会误解其行为。
再举一个例子,我们不会将伪随机数生成器函数称为"不安全的",仅仅是因为不称职的程序员通常对它们的输出不是真正随机的事实感到不满意。
strncpy函数就是这样。就像初学者要花时间了解伪随机数生成器实际做什么一样,花时间也要花些时间来了解strncpy实际做什么。需要花费时间来了解strncpy是转换函数,该函数旨在将零终止的字符串转换为固定宽度的字符串。需要花费时间来了解strncpy与"安全字符串复制"完全无关,并且不能被有意义地用于此目的。
当然,语言学生学习strncpy的目的通常比用除法运算符解决问题要花费更长的时间。但是,这是针对strncpy的任何"不安全"声明的基础。
附言链接在接受的答案中的CERT文档专门致力于:证明典型的不称职滥用strncpy功能作为strcpy的"安全"版本的不安全性。绝不是要声明strncpy本身是不安全的。
-
当人们说" strncpy不安全"时,他们的意思是"它没有成功之道"。没错
Git 2.19(Q3 2018)的pathc发现,滥用strcat()之类的系统API函数太容易了; strncpy(); ...,并禁止在此代码库中使用这些功能。
请参阅Jeff King(peff)的提交e488b7a,提交cc8fdae,提交1b11b64(2018年7月24日)和提交c8af66a(2018年7月26日)。
(由Junio C Hamano合并-gitster-在commit e28daf2中,2018年8月15日)
banned.h: mark strcat() as banned
The strcat() function has all of the same overflow problems as strcpy().
And as a bonus, it's easy to end up accidentally quadratic, as each subsequent call has to walk through the existing string.
The last strcat() call went away in f063d38 (daemon: use
cld->env_array when re-spawning, 2015-09-24, Git 2.7.0).
In general, strcat() can be replaced either with a dynamic string
(strbuf or xstrfmt), or with xsnprintf if you know the length is bounded.
-
这个答案对之前的答案有什么帮助?
-
@chqrlie只是在OP运行9年之后的一个例子,这些功能仍然非常危险(并且补丁说明了原因),以至于C代码库(例如,这里的Git禁止)禁止了这些功能。