我正在寻找找出为什么strncpy被认为是不安全的。是否有人对此有任何形式的文档或使用它的漏洞利用示例?
我正在寻找找出为什么strncpy被认为是不安全的。是否有人对此有任何形式的文档或使用它的漏洞利用示例?
Answers:
看一下这个网站; 这是一个相当详细的解释。基本上,strncpy()
不需要NUL终止,因此容易受到各种攻击。
\0
通常写为“ NUL”,以避免与NULL
指针混淆。
最初的问题显然是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
。
PS接受的答案中链接的CERT文档专用于:证明典型的无能的滥用strncpy
功能(作为的“安全”版本)不安全strcpy
。绝不打算声称它strncpy
本身是不安全的。
strncpy
不安全”时,他们的意思是“它没有成功之道”。没错
Git 2.19(Q3 2018)的路径发现,很容易滥用系统API函数,例如strcat()
; strncpy()
; ...,并禁止在此代码库中使用这些功能。
请参阅Jeff King()的commit e488b7a,commit cc8fdae,commit 1b11b64(2018年7月24日)和commit c8af66a(2018年7月26日)。(由Junio C Hamano合并--在commit e28daf2中,2018年8月15日)peff
gitster
banned.h
:标记strcat()
为禁止该
strcat()
函数具有与相同的所有溢出问题strcpy()
。
另外,由于每次后续调用都必须遍历现有字符串,因此很容易以偶然的平方结束。最后一个
strcat()
调用在f063d38中消失了(守护进程:重新生成时使用cld-> env_array,2015-09-24,Git 2.7.0)。
通常,strcat()
可以用动态字符串(strbuf
或xstrfmt
)替换,也可以用xsnprintf
长度限制的替换。