Hacker News 中文摘要

RSS订阅

暗箱操作C语言竞赛 -- The Underhanded C Contest

文章摘要

2015年Underhanded C竞赛结果公布,共收到40多份高质量作品。本届挑战聚焦核验证领域的现实问题,由核威胁倡议组织合作设计,强调安全软件开发需严谨细致。

文章总结

好的,这是根据您提供的英文内容,用中文重新陈述的文章主要内容,保留了关键细节,并删减了与主题无关的部分。


2015年“阴险C语言大赛”结果综述

2015年“阴险C语言大赛”的主题是核武器核查中的真实问题,由“核威胁倡议”组织合作设计。参赛者需要编写一个名为match()的函数,该函数用于比较一个待测核弹头的伽马射线能谱与一个参考能谱,并输出“是”或“否”的匹配结果。挑战的核心在于,参赛者需要让这个看似正常的函数,在特定条件下(由“东道国”人为制造)错误地将一个明显不匹配的假弹头判定为“匹配”。

本次大赛收到了超过40份高质量作品。评委们评选出了优胜者和若干荣誉提名。以下是获奖作品的核心思路和亮点:

核心攻击手法:NaN投毒

许多参赛作品(约三分之一)都利用了浮点数中的“非数字”(NaN)特性。NaN通常由未定义的数学运算(如0/0或负数开平方)产生,其关键特性是:任何涉及NaN的计算结果通常也是NaN,且任何与NaN的比较结果都为假。

攻击者通过以下步骤实现“投毒”: 1. 在程序中引入一个NaN值。 2. 让这个NaN值传播到最终的比较统计量中。 3. 利用比较语句(如 return (detection_score < threshold ? 0 : 1);)的特性,由于NaN与任何值的比较都为假,从而使得函数错误地返回“匹配”结果。

评委们认为,直接假设东道国能篡改输入数据来引入NaN的方式不够现实。更受青睐的是那些通过特定输入数据(如极值)触发计算错误(如除以零)来产生NaN的作品。

关于攻击的现实性

评委将攻击分为两类: * 数据触发型攻击:由输入数据的特定特征(如某个能谱通道值极高)触发。这类攻击更受青睐,因为它不依赖外部环境。 * 环境触发型攻击:由计算机环境因素(如系统时钟、文件权限、CPU数量)触发。这类攻击的现实性存在争议,但评委认为不能完全排除其可能性。

荣誉提名作品亮点

  • Philipp Klenze:利用泊松分布计算概率,当某个通道的计数值达到约1686时,计算会因数值过大而溢出,产生NaN。这种通过物理上可实现的“强峰值”来触发攻击的方式非常巧妙。
  • Ghislain Lemaur:将NaN漏洞隐藏在日志记录代码中。通过精心构造的日志消息长度,触发缓冲区溢出,覆盖了用于存储指数的变量,导致后续计算产生NaN。触发条件是东道国修改日志文件的用户ID。
  • Josh Lospinoso:一个简单的拼写错误。在检查无穷大的函数isinf()中,漏写了字母'i',变成了sinf()(正弦函数)。当输入数据极大导致溢出时,本应返回“不匹配”的代码,因错误地调用了正弦函数而可能返回“匹配”。
  • Stephen Dolan:利用浮点数精度限制。当某个差值远大于其他差值时,后续的累加操作会因精度不足而无效,导致最终计算结果为零,从而错误匹配。
  • Stephen Oman:利用负数漏洞。代码通过计算扫描开始和结束时间差来归一化数据。如果东道国篡改系统时钟,使结束时间早于开始时间,时间差变为负数,导致所有能谱数据被取反。负数的峰值面积在后续比较中会始终满足匹配条件。

优胜者:Linus Åkesson

Linus Åkesson的作品是本次大赛的冠军,其攻击手法极为精妙且隐蔽。

核心漏洞:类型混淆。代码的头文件中将float_t类型定义为double(8字节),但另一个源文件在包含标准数学库math.h后,float_t被默认定义为float(4字节)。由于两个文件没有同时包含这两个头文件,导致match()函数将8字节的double数组传递给了一个期望接收4字节float数组的函数。

攻击效果:当函数错误地解析数据时,每个8字节的double值会被拆分成两个4字节的float值。由于能谱数据是整数且数值不大,其有效信息集中在double的高位,被错误解析后,第一个float会是一个被“压缩”后的值,而第二个float几乎总是0。这种“压缩”效应使得不同大小的数值(如10和1000)在转换后变得非常接近。

攻击实现:东道国只需在假弹头中保留极少量裂变材料,使其能谱通过总能量检测,同时加入其他能产生强信号的材料。这些强信号位于能谱的“右半部分”,而由于类型混淆,函数只处理了数组的前半部分(即“左半部分”),右半部分被忽略。最终,经过“压缩”后的待测能谱与参考能谱看起来非常相似,从而被错误地判定为匹配。

获奖理由: 1. 现实可行:攻击完全由输入数据触发,无需篡改计算机环境。 2. 代码隐蔽:除了类型定义上的混淆,其余代码(包括滤波、归一化、相关性计算)都极其标准、清晰,毫无可疑之处。 3. 构思巧妙:深入利用了浮点数的底层位表示,并利用了数据本身是整数的特性。 4. 简洁高效:整个程序仅60多行代码,看起来非常无辜。

最终,Linus Åkesson因其作品在隐蔽性、现实性和巧妙性上的完美结合,被评选为2015年“最阴险的C语言程序员”。

评论总结

根据评论内容,主要观点如下:

  1. 对比赛起源的认可(评论2,评分None):评论者指出该比赛受Daniel Horn的混淆C语言投票计数程序启发,该程序能在特定日期错误计票,且测试时不易发现。关键引用:"The contest was initially inspired by Daniel Horn’s Obfuscated V contest... a simple program to count votes, that somehow miscounts the votes on election day" 和 "a short program to simply count characters in a text file can be made to fail, and fail only on one specific day, so that the bug isn't noticed in testing"。

  2. 对浮点精度问题的关注(评论3,评分None):评论者提到核威胁倡议和FP不确定性案例,并分享了自己审计核物理相关代码时遇到的类似问题。关键引用:"Interesting that the case they were using was the Nuclear Threat Initiative and FP uncertainties" 和 "I've audited some, ah, nuclear-physics-related code that had an issue due to FP uncertainties"。

  3. 简短致敬(评论1,评分None):仅以"RIP"表达对逝去内容的哀悼,未展开具体观点。

总体来看,评论主要围绕比赛起源的巧妙设计(投票计数的隐蔽错误)和浮点精度在核物理等关键领域的实际影响展开,未出现明显观点对立。