在今年,阿里安全尝试通过比赛的策划和组织,来阐述我们站在生态、企业和基础设施的角度,看待的软件供应链可能存在或将出现的安全威胁。划分了三个形式的赛季框架以使得比赛形成对抗,但根本着眼点是安全风险的两个大的维度:底层系统和最基础软件设施风险,落到 Linux 系统 C 源码基础软件的恶意代码片段挖掘;企业员工办公与接入企业网络的终端设备风险,落到 Windows 环境软件 PE 二进制可执行程序文件的恶意代码和行为判定。
近期软件供应链相关的一些新闻和反思,也在逐步佐证我们的顾虑。 6 月份, Gentoo Linux 的 GitHub 被黑客控制,篡改了代码仓库的关键组件代码植入恶意破坏逻辑,所幸形式受限于采用新增提交的方式,所以方便进行回滚,但这种从系统基础软件上下手的威胁已浮出水面。 9 月,去年 6 月份 NotPetya 网络战的故事重新引起了公众注意,黑客通过财会软件 M.E.Doc 软件通过更新进行污染进一步扩大破坏,这种对特定目标受害者受众的办公软件进行攻击,也验证了针对终端执行攻击的末日场景。但是,直接针对互联网巨头服务进行污染乃至攻击的案例,到目前为止还没有被发现的迹象,却让人寝食难安。
在 9 月 27 日刚刚实施的最后一个赛季的唯一一场比赛中,我们结合阿里自己的场景、经验与外部视角,探讨了最后一块拼图:作为互联网企业,我们自身应用的安全,落到 Java 开发生态中三方组件、框架的扫描和检测的形式之上,以比赛论英雄。
本赛季将作为场景赛场设定为 Java 开发生态的企业应用环境:
以 Java 开发生态为主的大型互联网公司,特点有大量快速迭代的产品,以及多种多样的框架、二方中间件和组件、三方库包。人员的高流动性,广泛且多种形式引入的舶来代码和模块,甚至存在过历史问题的 IDE 不可信,将代码质量保证问题推向了完全不同于开源软件代码赛季、 Windows 客户端软件赛季的全新范畴和高度:仓库规模不是唯一问题,保证跟进源码迭代速度的安全扫描能力、全生态链路保障,才是考验。
具体分析,在企业场景下,认定风险主要有四类来源:
如之前两个赛季一样,比赛是由阿里安全作为中立策划与组织者,由红蓝双方对抗而成的比赛,其中蓝方设计攻击恶意与恶意行为,实现原始题目贡献;红方根据公开信息,针对性地实现自动化方法做恶意行为发现;而我们负责将有限且直接的恶意行为思路扩散、混淆形成接近真实风险问题规模的赛题,并引导、评定、评价恶意行为发现的方法与效果。
针对 Java 赛季,结合真实场景,具体题目形式介于前两个赛季之间:
· 类似于 C 源代码赛季,基于 Java 源代码工程作为载体,在其上直接插入 “ 恶意 ” 代码片段;题目从形式上,又分为两类:
· 类似于 PE 二进制赛季,发布题目以插入了题目的代码工程编译后二进制 jar 包形式为准:
本赛季的题目载体,根据设计需要覆盖的风险来源,包含了服务端公开使用率比较高的 Java 二方包(开源应用 / 组件,其中可能有数量不等的非官方新增代码),以及其它来源的开源服务端应用 / 框架 / 组件,均为 jar 包形式。载体本身的功能无限定。
题目数量上,本次最终采纳的题目,包含 90 道常规题目,一对一嵌入到 90 个小规模 jar 包;以及在 21 个 jar 包上针对性嵌入的共计 35 个进阶题目。考虑到二者难度比例,常规与进阶题目每个点分别计 1 分、 3 分,所以二者数量上约 3:1 比例,分数上占 90:105 。比赛时长根据题目数量与业界自动化分析能力吞吐量水平进行核定,最终定为 3 小时。
根据赛季场景设计, Java 源码题目和 C 源码题目有类似的地方,都是在服务器端执行应用中的污染,攻击目标也是服务端其它应用、敏感数据。但考虑到本次着眼于 Java 开发生态、互联网服务提供者场景,二者具有一定区分度,主要有:
恶意行为范畴,指的是约束恶意代码可以接受的关键行为特征。针对 Java 应用,则结合了 Java 应用安全真实案例和潜在风险,强调从真实攻击场景出发,不细化到具体的行为点,仅进行分类,因此将恶意行为做如下划分:
其中,扩散、潜伏和清理三项,是辅助类型恶意行为,单独不足以判定恶意,也不单独出成题目;可选地与其它几类恶意行为组合。
假定目标应用环境,即假设被污染代码执行的环境中,可能存在的其它软件环境,这些软件环境可被攻击。 Java 源代码赛季则选择完全发散,本赛季不限定这一列表。
注意,所谓目标应用环境,并非是指在这些基础应用自身代码中进行污染;而是指在某些任意的应用、二三方包代码中插入代码、以这些服务端基础应用攻击面为对象的恶意行为。
本次比赛,因各种客观原因,外部业界出题队有 2 支,分别是 r1ng3 以及 DiDi ;而在内部,本次出动了阿里安全团队的大量直接负责应用安全、漏洞分析和研究的专家、工程师全程参与了思路构成和题目集成,可以说是构筑了最贴近一线的攻击队伍。
相比之前两个赛季, Java 赛季为尽量扩充有效题目数量,我们对出题设定了尽量少的思路、目标限制,完全依据所有队伍和人员对于安全风险与比赛的个人认知,因此题目的质量高低是一个非常主观的评价;同时,因为如开篇所述, Java 赛季所反映的是目前还没有在野发现的新型威胁,作为题目贡献出来的攻击思路直接释放出来会面临一定程度的风险。基于以上两方面考量,我们本次的总结将不像系列前篇一样放出精选题目深入解析,仅做全局分析。
整体观察,在常规题目部分,因为要求 “ 恶意行为 ” 载荷能够具有载体无关性,且满足能够插入现有 Java 工程中任意函数的语法兼容性,所以对应于上一章所分类的恶意行为范畴,各支队伍提交的恶意行为的分布,主要集中在“窃取”和“篡改”两种类型,例如各类特殊目的的恶意代码执行,包括恶意代码作为载荷本身嵌入,如窃取秘钥、目标服务配置等敏感文件数据,挖矿,并与各种外传方式进行组合;远程获取真正恶意代码并以各种方式在本地注入或执行,包括系统层面生成 crontab 任务或 JVM 层面的注入;各类传统的 web 应用的后门、 webshell 植入;以及一定比例的从 C 赛季典型服务端恶意行为直接移植采用的题目。整体而言,在常规题目部分,所有蓝军队伍倾向于保证题目的充分数量,思路较为集中和单一,且部分赛前设计预想的恶意行为类型(如规模化基础设施破坏,双向攻击移动与扩散,攻击行为痕迹清理)很少或没有在本次题目中体现。这些题目虽然在保证真实性的前提下略显抽象,但是考虑到类似 Gentoo 代码库入侵篡改事件的场景,如果攻击者需要在获取代码权限的极短时间内完成批量化非定向恶意行为嵌入,那么这种简单、代码量极少的攻击载荷将是具有真实威胁且难以干净清除的渗透分子。
而观察进阶题目,组织方看到了各个出题队在真实的服务端应用安全的深厚经验积淀与对未知威胁思考的体现:
本次比赛,参与的解题队同样迎来了一定程度的锐减。最终总参与外部队伍数量为 5 支,根据赛后排名,北大库博作为在源代码扫描深耕细作具有代表性的队伍,本次依然毫无疑问获得了第一名,但各支队伍的提交和分数具有很强的特征,反映出了一定的差异性和后续合作可能。最终排名如下:
队伍排名 |
队伍昵称 |
队伍分数 |
正确题目数量 |
1 |
Sebot |
112 |
84 |
2 |
SecID |
81 |
29 |
3 |
holiday |
76 |
62 |
4 |
G15 |
50 |
40 |
5 |
雷芒 |
35 |
35 |
全程参与了所有分站赛的 SecID 队伍,以几乎全部精力押在进阶题目部分,从而实现较大收益,总分 81 分位居第二名;但从提交历史来看,这样的策略不可避免地涉及较大比例的人工分析投入。而其余队伍则基本全部优先批量处理常规题目、稳扎稳打,其中 Sebot 战队具有代表性,利用自研工具和规则沉淀,对常规题目部分实现了极高的解题率。以下就以他们提供的赛后 writeup ,对这种利用到极致的自动化分析思路进行剖析。
解题思路,主要分成三部分:
本次测试赛总得分为 112 分,纯自动化无人工参与的得分是 85 分,总用时 12 分钟。以下简单介绍一下,每一部分的解题思路。
由于目标题目为已编译 jar 形式,而现有的分析手段更多集中在 java 源码上,首先需要对目标题目自动化反编译。由于反编译存在失败的情况,选取了三个反编译软件对 jar 包进行反编译,并以函数为单位产生 AST, 将获取到的三种反编译结果进行自动结果整合,在整合过程中计算解析失败的 Binding 个数,并选取失效最少的解析程序,以尽可能减少由于反编译失败导致的自动化提取问题。
对反编译后的 java 源码格式以函数为单位进行分析,可以通过简单的结构独立性分析先将可疑的目标代码段从工程中提取出来。之后根据目标库函数(文件读写,网络流,字符串拼接操作等),目标字符串 (ip 地址,网址, shell 指令,需要转码的长乱码, etc/passwd 等危险路径 ) 等信息,对提取出的代码段进行正确性判定并排序。对于反编译可能导致独立性缺失的问题,另外设计了纯文本对恶意字符串匹配并打分的方式增加容错。
对于进阶题,整理了部分可能触发恶意行为的模式。首先对可疑的库函数,字符串等在全工程中搜索,对所有函数为单位进行纯字符串形式的初步打分并初筛。对初筛后的结果,通过抽象语法树,控制流图,数据流分析等分析手段,分析可疑变量的影响范围,进行语义结构上的打分。综合两次得分将找到的结果进行排序。
对 AST 和字符串匹配两类检测器的结果,进行优先级排序,也就是每个 Jar 给出了 1-10 个优先级的结果,如果两个检测器同时认为是第一名,那么人工基本不再去做确认,如果不是,设定阈值 15 分,第一是 10 分,第二是 9 分,以此类推,最终累加两个检测器针对同一答案的总得分。低于 15 分的需要人工确认。
至此,我们已经完成了软件供应链安全大赛全部三个赛季、六轮分站赛,在此作一简单回顾:
在整个分站赛阶段中,感谢内外部的支持,同时我们也在和所有蓝军、红军的思路创意一起成长,截止到目前,正是一个回过头梳理深化的阶段。在此之后,就将迎来我们的百万奖金决赛阶段。希望能够获得大家的关注和帮助,对结果我们也共同期待。