转载

『功守道』软件供应链安全大赛·Java生态赛季总结

『功守道』软件供应链安全大赛·Java生态赛季总结

Last but not least

在今年,阿里安全尝试通过比赛的策划和组织,来阐述我们站在生态、企业和基础设施的角度,看待的软件供应链可能存在或将出现的安全威胁。划分了三个形式的赛季框架以使得比赛形成对抗,但根本着眼点是安全风险的两个大的维度:底层系统和最基础软件设施风险,落到 Linux 系统 C 源码基础软件的恶意代码片段挖掘;企业员工办公与接入企业网络的终端设备风险,落到 Windows 环境软件 PE 二进制可执行程序文件的恶意代码和行为判定。

近期软件供应链相关的一些新闻和反思,也在逐步佐证我们的顾虑。 6 月份, Gentoo LinuxGitHub 被黑客控制,篡改了代码仓库的关键组件代码植入恶意破坏逻辑,所幸形式受限于采用新增提交的方式,所以方便进行回滚,但这种从系统基础软件上下手的威胁已浮出水面。 9 月,去年 6 月份 NotPetya 网络战的故事重新引起了公众注意,黑客通过财会软件 M.E.Doc 软件通过更新进行污染进一步扩大破坏,这种对特定目标受害者受众的办公软件进行攻击,也验证了针对终端执行攻击的末日场景。但是,直接针对互联网巨头服务进行污染乃至攻击的案例,到目前为止还没有被发现的迹象,却让人寝食难安。

927 日刚刚实施的最后一个赛季的唯一一场比赛中,我们结合阿里自己的场景、经验与外部视角,探讨了最后一块拼图:作为互联网企业,我们自身应用的安全,落到 Java 开发生态中三方组件、框架的扫描和检测的形式之上,以比赛论英雄。

威胁定义

本赛季将作为场景赛场设定为 Java 开发生态的企业应用环境:

Java 开发生态为主的大型互联网公司,特点有大量快速迭代的产品,以及多种多样的框架、二方中间件和组件、三方库包。人员的高流动性,广泛且多种形式引入的舶来代码和模块,甚至存在过历史问题的 IDE 不可信,将代码质量保证问题推向了完全不同于开源软件代码赛季、 Windows 客户端软件赛季的全新范畴和高度:仓库规模不是唯一问题,保证跟进源码迭代速度的安全扫描能力、全生态链路保障,才是考验。

具体分析,在企业场景下,认定风险主要有四类来源:

  • 大量无条件信任的二方包、框架与源。这些外部基础组件,类似漏洞的风险,其在开发、分发环节也存在被攻破篡改的风险。
  • 对外部存在二次开发和定制的基础组件。二次开发不止可能引入碎片化、历史漏洞问题,还会导致这些代码失去一致性安全保证。
  • Ctrl-CCtrl-V 引入的外部威胁。当前代码由 GitHub 等公开代码借鉴而来的情况在开发实践中不可避免,如果存在蓄意发布的暗藏恶意的代码可能被直接引入。
  • 大量人员流动引入的代码隐患。快速迭代中人员流动,一方面不利于代码规范的维持,一方面也引入了 本身的不确定因素。

比赛设定

如之前两个赛季一样,比赛是由阿里安全作为中立策划与组织者,由红蓝双方对抗而成的比赛,其中蓝方设计攻击恶意与恶意行为,实现原始题目贡献;红方根据公开信息,针对性地实现自动化方法做恶意行为发现;而我们负责将有限且直接的恶意行为思路扩散、混淆形成接近真实风险问题规模的赛题,并引导、评定、评价恶意行为发现的方法与效果。

赛题形式

针对 Java 赛季,结合真实场景,具体题目形式介于前两个赛季之间:

·     类似于 C 源代码赛季,基于 Java 源代码工程作为载体,在其上直接插入 恶意 代码片段;题目从形式上,又分为两类:

  • 常规题目。在这样的题目形式下,恶意代码与载体本身没有任何关联,不依赖于载体的逻辑,也不干预载体原本功能,因此恶意代码存在的位置可能是任意载体、任意代码上下文之间。
  • 进阶题目。这种形式下,恶意行为本身与载体工程和代码具有交互性、关联性,并借用载体本身的逻辑、接口、库、函数调用序列等,因此有较强的真实攻击性、隐蔽性。

·     类似于 PE 二进制赛季,发布题目以插入了题目的代码工程编译后二进制 jar 包形式为准:

  • 为了防止包含恶意代码的工程直接被进行源码层面比对、发现额外新增的题目代码,对题目进行一定程度混淆加花,编译为 jar 包。采用的混淆方案保证不以干扰 jar 包反编译为目的,所以解题队也仍然可以使用反编译后的源码扫描能力。

赛题环境

本赛季的题目载体,根据设计需要覆盖的风险来源,包含了服务端公开使用率比较高的 Java 二方包(开源应用 / 组件,其中可能有数量不等的非官方新增代码),以及其它来源的开源服务端应用 / 框架 / 组件,均为 jar 包形式。载体本身的功能无限定。

题目数量上,本次最终采纳的题目,包含 90 道常规题目,一对一嵌入到 90 个小规模 jar 包;以及在 21jar 包上针对性嵌入的共计 35 个进阶题目。考虑到二者难度比例,常规与进阶题目每个点分别计 1 分、 3 分,所以二者数量上约 3:1 比例,分数上占 90:105 。比赛时长根据题目数量与业界自动化分析能力吞吐量水平进行核定,最终定为 3 小时。

赛题范围

根据赛季场景设计, Java 源码题目和 C 源码题目有类似的地方,都是在服务器端执行应用中的污染,攻击目标也是服务端其它应用、敏感数据。但考虑到本次着眼于 Java 开发生态、互联网服务提供者场景,二者具有一定区分度,主要有:

  • C 源代码赛季假定的是 Linux 开源基础组件,运行在系统底层,攻击目标以系统自身数据、其它基础软件为主,以服务端场景后台应用为辅;而 Java 赛季以各类服务端应用为主。
  • C 源代码赛季基于的一个原则是,不可以使用漏洞类攻击行为;而 Java 应用安全很多围绕漏洞展开,题目本身也可能以历史或未知漏洞为关键、以语言特定的方式引入。
  • C 源代码当中限定的恶意行为较为严格,且以循序渐进的方式引导攻防双方能力逐步升级; Java 赛季相关参与方基本具有成熟的扫描能力或人工分析专家经验,在划定范围之外鼓励进行脑洞发散。

恶意行为范畴

恶意行为范畴,指的是约束恶意代码可以接受的关键行为特征。针对 Java 应用,则结合了 Java 应用安全真实案例和潜在风险,强调从真实攻击场景出发,不细化到具体的行为点,仅进行分类,因此将恶意行为做如下划分:

  • 摸排。采集目标环境、应用、输入输出等敏感信息并泄漏,为入侵做准备。
  • 破门。渗透进入,拿到控制权或留下后续真正攻击的入口、跳板。
  • 窃取。窃取关键数据(用户数据资产,内部代码)泄漏。
  • 篡改。在尽量不被发觉的前提下修改关键配置、代码、数据。
  • 破坏。类似 NotPetya 以战为目的,充分扩散后集中的最大破坏行为。
  • 扩散。类似蠕虫行为,但还可能包含从服务端向终端的 逆向 横向移动。
  • 潜伏。长期隐匿并断续侵害,或等待时机发起破坏。
  • 清理。隐藏行为反侦察,破坏行为反分析。

其中,扩散、潜伏和清理三项,是辅助类型恶意行为,单独不足以判定恶意,也不单独出成题目;可选地与其它几类恶意行为组合。

假定目标应用环境

假定目标应用环境,即假设被污染代码执行的环境中,可能存在的其它软件环境,这些软件环境可被攻击。 Java 源代码赛季则选择完全发散,本赛季不限定这一列表。

注意,所谓目标应用环境,并非是指在这些基础应用自身代码中进行污染;而是指在某些任意的应用、二三方包代码中插入代码、以这些服务端基础应用攻击面为对象的恶意行为。

蓝方分析:出题队与题目赏析

蓝方队伍组成

本次比赛,因各种客观原因,外部业界出题队有 2 支,分别是 r1ng3 以及 DiDi ;而在内部,本次出动了阿里安全团队的大量直接负责应用安全、漏洞分析和研究的专家、工程师全程参与了思路构成和题目集成,可以说是构筑了最贴近一线的攻击队伍。

蓝方题目赏析

相比之前两个赛季, Java 赛季为尽量扩充有效题目数量,我们对出题设定了尽量少的思路、目标限制,完全依据所有队伍和人员对于安全风险与比赛的个人认知,因此题目的质量高低是一个非常主观的评价;同时,因为如开篇所述, Java 赛季所反映的是目前还没有在野发现的新型威胁,作为题目贡献出来的攻击思路直接释放出来会面临一定程度的风险。基于以上两方面考量,我们本次的总结将不像系列前篇一样放出精选题目深入解析,仅做全局分析。

整体观察,在常规题目部分,因为要求 恶意行为 载荷能够具有载体无关性,且满足能够插入现有 Java 工程中任意函数的语法兼容性,所以对应于上一章所分类的恶意行为范畴,各支队伍提交的恶意行为的分布,主要集中在“窃取”和“篡改”两种类型,例如各类特殊目的的恶意代码执行,包括恶意代码作为载荷本身嵌入,如窃取秘钥、目标服务配置等敏感文件数据,挖矿,并与各种外传方式进行组合;远程获取真正恶意代码并以各种方式在本地注入或执行,包括系统层面生成 crontab 任务或 JVM 层面的注入;各类传统的 web 应用的后门、 webshell 植入;以及一定比例的从 C 赛季典型服务端恶意行为直接移植采用的题目。整体而言,在常规题目部分,所有蓝军队伍倾向于保证题目的充分数量,思路较为集中和单一,且部分赛前设计预想的恶意行为类型(如规模化基础设施破坏,双向攻击移动与扩散,攻击行为痕迹清理)很少或没有在本次题目中体现。这些题目虽然在保证真实性的前提下略显抽象,但是考虑到类似 Gentoo 代码库入侵篡改事件的场景,如果攻击者需要在获取代码权限的极短时间内完成批量化非定向恶意行为嵌入,那么这种简单、代码量极少的攻击载荷将是具有真实威胁且难以干净清除的渗透分子。

而观察进阶题目,组织方看到了各个出题队在真实的服务端应用安全的深厚经验积淀与对未知威胁思考的体现:

  • 从植入恶意代码的目标载体来看,所有队伍均默认选择直接针对服务端 Java 后台服务应用或处理用户数据的关键组件,包括: mysql-connector spring-webmvc tomcat Jetty jedis fastjson spring-boot Elasticsearch javamail jenkins incubator-dubbo OkHttpClient nanohttpd 。在这些目标上直接进行代码篡改,显然将具有最大的攻击面影响;从业务场景和攻击逻辑上讲,直接面向有针对性的数据和处理逻辑,能够形成真实且完整的攻击链路;从思路形成角度分析,针对这些开源应用和组件的攻击,反映了蓝方从攻击者角度,审视这些生产环境自用的外来代码时,最大的安全风险担忧。但是这样的选择也有弊端:选取的目标较为重型,往往受到更多关注和审计,植入代码问题较难实现隐藏;攻击思路与载体功能强相关,没能实现我们预判中,软件供应链上攻击的 顾左右而言他 的攻击移动效果。
  • 从恶意代码形成的预期行为来看,多数题目选择了具有以小博大、持久化的思路,即植入的代码在正常的应用处理外部数据逻辑分支之余添加旁路,从而实现对恶意用户数据的解析和代码执行,这满足了攻击影响最大化、降低代码突兀度以规避检查的目的;其余题目则主要选取了保守的敏感数据(包括应用本身吞吐的待处理数据,和系统或外部应用的无关数据)窃取外传,以及释放 webshell 这两种思路。
  • 从恶意代码本身的实现形式来看,存在部分题目充分利用了 Java 灵活的语言特性以及载体本身的功能与特殊性,巧妙地构造、实现攻击行为,实现了少量 0 解题率的经典题目,具有漏洞一般的隐蔽性。这部分出于对题目攻击性的传播控制不做举例说明。

红方分析:解题队战况与分享

本次比赛,参与的解题队同样迎来了一定程度的锐减。最终总参与外部队伍数量为 5 支,根据赛后排名,北大库博作为在源代码扫描深耕细作具有代表性的队伍,本次依然毫无疑问获得了第一名,但各支队伍的提交和分数具有很强的特征,反映出了一定的差异性和后续合作可能。最终排名如下:

队伍排名

队伍昵称

队伍分数

正确题目数量

1

Sebot

112

84

2

SecID

81

29

3

holiday

76

62

4

G15

50

40

5

雷芒

35

35

全程参与了所有分站赛的 SecID 队伍,以几乎全部精力押在进阶题目部分,从而实现较大收益,总分 81 分位居第二名;但从提交历史来看,这样的策略不可避免地涉及较大比例的人工分析投入。而其余队伍则基本全部优先批量处理常规题目、稳扎稳打,其中 Sebot 战队具有代表性,利用自研工具和规则沉淀,对常规题目部分实现了极高的解题率。以下就以他们提供的赛后 writeup ,对这种利用到极致的自动化分析思路进行剖析。

典型源码扫描解题思路

解题思路,主要分成三部分:

  • 第一部分,反编译并建立解析模型。
  • 第二部分,根据解析模型,进行检测分析,并给出可能性优先级。在此部分,采用了三种假设,并对应三种策略, 1 )假设反编译并解析全部正确 2 )假设反编译部分正确 3 )假设不能反编译。由此,对三种情况都做了相应的检测器,即:基于 ASTChecker, 基于字符串的 Checker 以及基于 classChecker 以防止出现 PE 比赛无法反汇编成功的情况。
  • 第三部分,结果自动合并技术,针对两类检测针对某一项目的检测结果,进行打分评估,并给出优先级评价。

本次测试赛总得分为 112 分,纯自动化无人工参与的得分是 85 分,总用时 12 分钟。以下简单介绍一下,每一部分的解题思路。

反编译

由于目标题目为已编译 jar 形式,而现有的分析手段更多集中在 java 源码上,首先需要对目标题目自动化反编译。由于反编译存在失败的情况,选取了三个反编译软件对 jar 包进行反编译,并以函数为单位产生 AST,  将获取到的三种反编译结果进行自动结果整合,在整合过程中计算解析失败的 Binding 个数,并选取失效最少的解析程序,以尽可能减少由于反编译失败导致的自动化提取问题。

检测器

对反编译后的 java 源码格式以函数为单位进行分析,可以通过简单的结构独立性分析先将可疑的目标代码段从工程中提取出来。之后根据目标库函数(文件读写,网络流,字符串拼接操作等),目标字符串 (ip 地址,网址, shell 指令,需要转码的长乱码, etc/passwd 等危险路径 ) 等信息,对提取出的代码段进行正确性判定并排序。对于反编译可能导致独立性缺失的问题,另外设计了纯文本对恶意字符串匹配并打分的方式增加容错。

对于进阶题,整理了部分可能触发恶意行为的模式。首先对可疑的库函数,字符串等在全工程中搜索,对所有函数为单位进行纯字符串形式的初步打分并初筛。对初筛后的结果,通过抽象语法树,控制流图,数据流分析等分析手段,分析可疑变量的影响范围,进行语义结构上的打分。综合两次得分将找到的结果进行排序。

结果自动合成

AST 和字符串匹配两类检测器的结果,进行优先级排序,也就是每个 Jar 给出了 1-10 个优先级的结果,如果两个检测器同时认为是第一名,那么人工基本不再去做确认,如果不是,设定阈值 15 分,第一是 10 分,第二是 9 分,以此类推,最终累加两个检测器针对同一答案的总得分。低于 15 分的需要人工确认。

To be continued…

至此,我们已经完成了软件供应链安全大赛全部三个赛季、六轮分站赛,在此作一简单回顾:

  • 系统环境与底层软件基础设施 -C 赛季, 512-630 日, 《上篇》 《下篇》
  • 办公环境与开发运维终端软件 -PE 赛季, 77-818 日, 《上篇》 《下篇》
  • 线上环境与服务应用软件生态 -Java 赛季, 825-930 日,《本章》。

在整个分站赛阶段中,感谢内外部的支持,同时我们也在和所有蓝军、红军的思路创意一起成长,截止到目前,正是一个回过头梳理深化的阶段。在此之后,就将迎来我们的百万奖金决赛阶段。希望能够获得大家的关注和帮助,对结果我们也共同期待。

原文  https://www.anquanke.com/post/id/161629
正文到此结束
Loading...