← 返回信息流
AI 资讯Hacker News·2 小时前

阴险C代码大赛:用看似正常的代码埋下陷阱

原标题:The Underhanded C Contest

速览

The Underhanded C Contest 是一项独特的编程竞赛,参赛者需提交一段表面上符合规范、实则包含隐蔽缺陷的C代码。比赛旨在揭示代码审查和安全审计中的盲点,强调软件安全的重要性。该赛事自2005年起不定期举办,吸引了全球程序员参与。

AI 深度解读

背景

The Underhanded C Contest("阴险 C 语言大赛")是一项历史悠久的编程竞赛,参赛者需要编写看似正常、实则暗藏后门的 C 代码,且这些后门要足够隐蔽,能逃过代码审查。2015 年的比赛结果已经公布,今年的题目聚焦于一个真实世界的应用场景——核核查(nuclear verification),由非营利组织 Nuclear Threat Initiative(NTI)赞助并参与设计。主办方还宣布将于 2 月 9 日在 Reddit 举办一场 AMA(Ask Me Anything)活动,供社区提问。

核心内容

赛事概况

2015 年的比赛共收到超过 40 份提交,整体质量较高,因此长名单(runners up)也比较长。今年的赛题源自核核查领域的真实问题,旨在强调在如此关键的安全应用领域中,软件开发需要更加严谨和审慎,也需要新的研究投入。

NaN 毒化攻击综述

约三分之一的提交作品使用了同一种技巧——NaN(Not a Number,非数字)毒化攻击。浮点变量在某些未定义运算(如 sqrt(-1.0)0/0)后会被设为 NaN,而 NaN 有两个关键性质:

  • 涉及 NaN 的运算结果通常也是 NaN;
  • 任何与 NaN 的比较运算结果都为 false

第二个性质是许多编程语言的语法限制所致:只有部分数据类型能持有"未定义"值。从数学上讲,如果 x 未定义,那么 y = ((int) x)y = (x >= 5) 也应该是未定义的,但整型和布尔型变量无法表达"未定义",这些表达式必须求出某个值。

基于此,NaN 毒化攻击的思路如下:

  1. 找到一种方式,当程序接收到特定异常输入时引入 NaN;
  2. 让 NaN 传播到最终的比较统计量中;
  3. 利用"NaN 比较返回 false"的特性,使判断逻辑反向成立,例如:return (detection_score < threshold ? 0 : 1);detection_score 为 NaN 时,< 比较返回 false,于是函数返回 1(即"匹配成功")。

攻击的精妙程度取决于如何引入 NaN。有些提交直接假设对手能将 NaN 塞进输入数据,但评委认为这不够现实。另一些提交则通过除法、开方、对数等运算,在异常输入下自然产生 NaN。

典型提交案例

Peter Eastman 的提交:在计算 Pearson 相关系数前,代码对基线做了减法,并将负值钳位到 0。如果被测弹头的某个数据点小于等于基线值,则相关系数计算退化为 0/0 == NaN,从而绕过检测。

Michael Dunphy 的提交:代码中加入了一个"零值/NaN/无穷大"检查,看似安全,但实际上 err 参数本应以引用(指针)传递,声明中却遗漏了 & 符号,导致错误标志永远无法被设置,检查形同虚设。

Sean Egan 的提交:先用 memset 将数组填充为 0xFF,再从文本文件解析数值。如果文件中包含无法解析为数字的条目(例如形似数字的 Unicode 字符),sscanf 会跳过该元素,而由 0xFF 字节构成的 double 值恰好是 NaN。

总体而言,NaN 毒化攻击大多未能进入最终短名单,原因包括:(1)假设对手能篡改输入;(2)浮点运算缺少检查过于显眼;(3)触发条件过于牵强。

关于现实性的注记

一份获奖提交需要满足:误报(false positive)可以在现实条件下被触发,且几乎不会意外发生。评委将提交分为几类:

  • 简单/不现实假设:例如直接假设对手能破坏输入数组。
  • 数据触发攻击(data-triggered):当输入特定类型的数据(如无尖峰或极端值)时触发 bug。
  • 环境触发攻击(environment-triggered):由计算机环境因素(如文件 uid、系统时钟)触发。例如 Sarah Newman 和 S. Gilles 的提交将 match() 函数并行化,当有人在计算过程中改变可用 CPU 数量时触发恶意行为。

评委特别讨论了环境触发攻击的现实性:在核核查场景中,被检查国是否被允许篡改计算机(如修改系统时钟或 CPU 数量)?一方面,环境层面的篡改可以非常隐蔽,可能不需要直接接触核查程序本身;另一方面,某些环境条件的改变可能超出对手的合理能力范围。

关键要点

  • 2015 年 Underhanded C 大赛聚焦核核查场景,由 NTI 赞助设计,强调安全关键软件的开发严谨性。
  • NaN 毒化攻击是今年最常见的技术路线,利用浮点 NaN 的比较特性绕过检测逻辑。
  • 攻击的现实可行性取决于触发方式:直接篡改输入被认为不够现实,而通过合法运算路径产生 NaN 更具隐蔽性。
  • 代码审查中的"红旗"(如无检查的浮点除法)容易被发现,因此高明的提交会引入看似有检查实则无效的代码来迷惑审查者。
  • 攻击可分为数据触发环境触发两大类,后者利用系统层面的变化(CPU 数量、时钟等)来激活后门。
  • 评委特别关注攻击的现实性——后门必须能在真实条件下被利用,同时又不能过于容易被意外触发。

意义与影响

这篇文章揭示了一个深刻的安全问题:在核核查等生死攸关的应用中,软件不仅是工具,更是信任的基石。攻击者不需要破坏整个系统,只需在浮点数处理中埋下一个几乎不会被审查发现的微妙漏洞,就能让核查程序"视而不见"。NaN 毒化攻击尤其值得所有程序员警惕——它利用了编程语言设计中一个看似无关紧要的语义细节(NaN 的比较行为),却能在安全关键系统中造成灾难性后果。

此外,环境触发攻击的讨论拓展了我们对"攻击面"的传统认知:威胁不一定来自输入数据本身,还可能来自操作系统、硬件配置甚至物理环境的变化。这提醒安全开发者,防御必须覆盖整个计算环境,而不仅仅是程序的输入输出边界。

查看原文 →underhanded-c.org