谷歌Flank潜藏3年的Github Action供应链攻击

01

 简  介

Flank [1] 是谷歌 Firebase Test lab 开源在 Github 的一个项目,用于同时对多个安卓和IOS设备进行测试。2024年4月15号 AWS 安全工程师 Adnan Khan 公布了关于该项目代码仓库 Github Action CI/CD 存在漏洞的细节[2],漏洞在2020年于此 代码合并请求[3] 引入,3年多一直没人发现(这个仓库谷歌一直有赏金计划),谷歌把该漏洞归属为供应链漏洞,并给予该漏洞赏金 $7500 美刀(约 5w+ 人民币)。

利用该漏洞可以获得 Flank Github 代码仓库的写权限的 GITHUB_TOKEN 和谷歌云的账户密钥(看给的赏金大概能想到该密钥能进一步获取到的权限),该漏洞于2024年4月11号修复。

漏洞整体利用链图解(文章后面会附上复现环境和步骤~):

图片

另外,具有写权限的 GITHUB_TOKEN 可以用来发布 GitHub Release 以及 Release 附件,从而发布恶意的编译后二进制软件来达到供应链攻击的效果,原文作者由于是 Bug Bounty,渗透讲究点到为止,不过本文也会涉及这部分利用手段。

02

 背  景

Github Action

Github Action [4]用于在 Github 代码仓库中自动化、自定义和执行软件开发工作流程,也可用于持续集成持续部署流程(即 CI/CD),十分便于开发者使用,而不用专门去部署一套 Jenkins 之类的用于 CICD。具体表现在 Github 上,就是在代码仓库根目录建一个 .github 目录,里面放着一些定义自动化任务的 yaml/yml 文件,称之为 workflow (工作流),

图片

关于 .github 目录大家应该挺眼熟的,但一般我们都会忽略不太起眼的它,因为一般它不会存在什么特别的安全漏洞,但本文的重点就是里面的 workflow 。

 workflow 触发的方式很多,比如在 git push 代码到仓库时触发,亦或是在创建代码合并请求(Pull Request,下文简称 PR )触发等,触发后通过 Github Runner(执行器) 去执行相应的 workflow ,触发等方式多种多样,触发方式写法一般如下:

图片

上下 workflow 即是在代码 push 到 main 分支或者是 PR 入 main 时触发,运行结果输出 Hello World 

在本漏洞中,通过在 PR 评论区回复特定关键字触发存在漏洞的 workflow 。

Github Action Secrets

关于 Github Action secrets [6],比如我们给代码跑完单元测试后想要自动部署,那部署到相关环境需要的SSH或其他密钥肯定是不想明文放出来的,比如硬编码在仓库代码中,或者直接写在仓库配置文件中,这样大家就都能在 Github 仓库文件中看到了。

使用 secrets 的好处是,可以把这类密钥在跑 workflow 时,通过 Runner 环境变量的形式带进去。这样就解决刚刚说的问题了。此外,就算相关代码不小心把某个上下文变量日志给打了出来,secret 恰好包含在其中,Github Runner 显示的日志,也会把 secrets 脱敏显示,也就是说,就算我们主动 print($secret) ,他在 Runner 日志中显示的也是脱敏数据,如 ****** 。

以 GITHUB_ 开头的为 Github Runner 内置的一些环境变量或Secret [5],在 Action 中的 yaml 通过 ${{ secrets.GITHUB_TOKEN }} 即可引入,非常方便。

先献上存在漏洞的 workflow

https://github.com/Flank/flank/blob/v23.10.1/.github/workflows/run_integration_tests.yml

直接看漏洞存在和利用点可能没那么明显,下面来分析一下

03

 漏洞发现和利用

其实这类由 PR 引发漏洞,并且是有赏金计划的,一般在数日内就会被发现。因为多数赏金猎人,基本都是通过自动化的工具对 .github 目录里的文件进行批量检测,相关的工具有 gato [7] 和 gh-workflow-auditor [8],其中 gato 是原文作者是通过在上一家公司工作开源的自研工具。该漏洞是他对 gato 不断优化的 gato-x 版发现的,目前优化版 gato-x 还没开源出来,原作者还在尽可能的优化,然后在不久的将来放出来。

至于这个漏洞为啥一直没被发现的原因,他和普通的 Action 注入不太一样,例如下面这个流水线[9]

图片

如果攻击者在这个项目 Github 上新建一个 issue 的标题为 test" && ls / && echo " ,会直接造成流水线 runner 里的命令注入

图片

即,这种 Action 注入是执行命令时直接拼接了外部可控的变量。

而 Flank 触发流水线时并没有直接拼接可控变量,只是获取了 PR 的序号,

图片

然后通过 gh 命令切换到我们 PR 的代码上,这时才出现我们可控的部分

图片

即此时会切换到我们 PR 的代码,但此时它仍然没有拼接任何东西。特别是对于自动化工具而言,这里根本就不会检测出来,因为没有拼接可控的东西。由于 Github 上的 workflow 太多,一个个找和看,其实是不好找出来的。就像我们看存在问题的 workflow,一下子我们也没能太看出来存在什么问题,这就是为啥这个漏洞存在这么久才被发现。

原作者检测工具的设计目的就不太一样,他是扫描存在触发风险点的地方,然后在回过头来看是不是误报,尽管有接近70%的是误报。

在看整个 workflow 文件,在项目 PR 评论区回复 @flank-it 会触发 should_run_it  job,这个 job env 带有 GITHUB_TOKEN secret,并且该 token 有该项目的写权限(如果没有该项目的写权限,这个在评论区加个眼睛 👀 的 emoji 是加不上的)

图片

然后 should_run_it 运行结果 run_integration_tests 为 true 会触发 env 带有 GCLOUD_KEY secret  的 job

图片

到这里,还没讲到,Action 注入的,我们可控的恶意代码在哪呢?目前我们向此仓库发 PR,然后流水线中 gh checkout 我们的PR 切换到我们的代码。其实对于一般的流水线,都会有构建操作,即打包代码之类的,这里用的是 gradle 

图片

然后 gradle DSL(领域定义语言)是基于 Groovy的[10]!Gradle 5.0 后,还支持了 Kotlin 语言,也就是说我们可以执行通过任意代码执行,从而达到任意命令执行!从而达到就可以把这两个 secret 通过 curl 命令外带即可(非项目成员记得是看不到流水线运行结果的,所以不能像下面漏洞复现那样编码输出)。

恶意 PR

https://github.com/Flank/flank/pull/2481/files#diff-5625e3601fa0ad3a6a2824239e5a2fde71c149597d31394f9224a08c24be7b9d

然后作者为了规避 harden-runner [11]安全检测机制,只改了原仓库的 gradle,其他都是改 fork 到自己仓库的,因为在自己 fork 的仓库改,在原仓库也会留有 commit 信息(虽然最后还是告警了,原文还是有提到其他规避方法的)

由于执行 gradle 没有代入 secret 环境变量,这里需要用个 trick,即读取进程内存来获取 runner 里的 secret。因为就算是不同阶段的 job,一般都是在一个容器里执行。

图片

图片

03

 漏洞复现

环境搭建(可跳过)

搭建好的复现环境:https://github.com/tarihub/hack-flank-cicd

复现环境的项目配置(自己搭建就需要注意下,免得踩坑):

  • https://github.com/tarihub/hack-flank-cicd/settings/actions 需要在这里勾上 Workflow permissions 的 Read and write permissions 权限,不然小眼睛👀交互打不上(其实主要是模拟原项目给了 GITHUB_TOKEN 的写权限)

图片

  • secret 记得 base64编码一下,不然解码会失败

图片

复现步骤

先fork https://github.com/tarihub/hack-flank-cicd 项目过来,然后把 settings.gradle.kts 改为

图片

PS:这里的 pastebin 内容就是上面的 读取进程内存 处,用来读取 Runner 进程内存中存的 secret

commit 并 push 后发送 PR 到原仓库,在 PR 评论区留言 @flank-it 触发 Github Action

图片

运行过程,这里为了方查看所以直接输出

图片

正常情况下利用,由于非项目成员,看不到运行结果,所以需要用 curl 外带

图片

就得到 GCLOUD_KEY 和 GITHUB_TOKEN

图片

base64解码得 flag{GCLOUD_KEY} 

接下来,我们拿到具有写权限的 Github_TOKEN 就可以发布 release 附件了,一般项目都会有 release,所以我们先创建一个 release,创建好标签命名完标题保存即可

https://github.com/tarihub/hack-flank-cicd/releases/new

这里注意,获取到的 GITHUB_TOKEN 要在流水线运行结束前使用,否则 token 会失效,因此我们可以通过 sleep 等各种方式阻塞流水线的运行

根据 Github 文档[12],然后要获取 RELEASE_ID

图片

图片

然后通过接口增加/修改 release 附件即可

图片

图片

来到 Github Release 页面就看到我们的恶意附件就上传上去了

图片

至于 GCLOUD_KEY 的进一步利用,网上有很多文章介绍,这里就不进一步深入了

05

 总  结

该漏洞的修复,官方去除了在 PR 评论区留言触发流水线的方式,并且不会切换到 PR 部分对代码,只保留了定期触发流水线,这样攻击者就无法触发可控的攻击代码了。

https://github.com/Flank/flank/pull/2482

纵观漏洞从发现到利用整条利用链还是相当精彩的,原来 Github Action CI/CD 还能这样利用,平常审计代码都是直接跳过 Github Action 的… 又一次感受到公有云的安全难做,有时候这些密钥真不知道怎么就泄漏出去了。

因此,广大开发者使用 Github Action 时也请注意,当 workflow 带有 secret 时,注意避免各种形式让未授权人员在 Github runner 中执行外部可控的代码或逻辑,也应该部署 harden-runner [11]等相关工具,防止以及监测可能的异常 workflow,从而保障开源代码的安全。

06

 参考链接

[1] https://github.com/Flank/flank

[2] https://adnanthekhan.com/2024/04/15/an-obscure-actions-workflow-vulnerability-in-googles-flank

[3] https://github.com/Flank/flank/pull/1409

[4] https://docs.github.com/zh/actions

[5] https://docs.github.com/zh/actions/security-guides/using-secrets-in-github-actions

[6] https://docs.github.com/zh/enterprise-cloud@latest/actions/security-guides/automatic-token-authentication#about-the-github_token-secret

[7] https://github.com/praetorian-inc/gato

[8] https://github.com/TinderSec/gh-workflow-auditor

[9] https://cycode.com/blog/github-actions-vulnerabilities/

[10] https://docs.gradle.org/current/dsl/index.html

[11] https://github.com/step-security/harden-runner

[12] https://docs.github.com/zh/rest?apiVersion=2022-11-28

本文作者:

tari,首批 CSA CCPTP 认证专家、CSA 大中华区云渗透测试工作组成员

审校:

李鑫,CSA大中华区云渗透测试工作组组长

梁嘉荣,CSA大中华区研究协调员

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/13417.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

02 VUE学习:模板语法

模板语法 Vue 使用一种基于 HTML 的模板语法,使我们能够声明式地将其组件实例的数据绑定到呈现的 DOM 上。所有的 Vue 模板都是语法层面合法的 HTML,可以被符合规范的浏览器和 HTML 解析器解析。 在底层机制中,Vue 会将模板编译成高度优化的…

开发vue3,真的可以不用ref/reactive了,也不需要ref.value

什么是Cabloy-Front? Cabloy-Front 是一款支持 IOC 容器的 Vue3 框架。不用ref/reactive,不用ref.value,不用pinia 与UI库的配合 Cabloy-Front 可以搭配任何 UI 库使用,并且内置了几款 UI 库的项目模版,便于开箱即用…

免费SSL证书签发安装指南

一、签发 1.选择证书颁发机构(CA):首先,你需要找到一个提供免费SSL证书的CA。有些CA会提供永久免费的SSL证书,而有些则可能只提供有限时间的试用证书,如JoySSL就提供永久免费证书。 2.生成CSR&#xff08…

WPF 鼠标拖拽平移

效果 xaml <ScrollViewer x:Name"scrollViewer" HorizontalScrollBarVisibility"Hidden" VerticalScrollBarVisibility"Disabled" Background"#FFF1ADAD"PreviewMouseDown"ScrollViewer_OnPreviewMouseDown"PreviewMou…

Electron学习笔记(一)

文章目录 相关笔记笔记说明 一、轻松入门 1、搭建开发环境2、创建窗口界面3、调试主进程 二、主进程和渲染进程1、进程互访2、渲染进程访问主进程类型3、渲染进程访问主进程自定义内容4、渲染进程向主进程发送消息5、主进程向渲染进程发送消息6、多个窗口的渲染进程接收主进程发…

白鲸开源CEO郭炜在2024 DataOps发展大会上获聘专家

2024年5月15日&#xff0c;白鲸开源CEO郭炜在2024 DataOps发展大会上被正式聘任为DataOps专家&#xff0c;并获得了荣誉证书。本次大会由中国通信标准化协会主办&#xff0c;中关村科学城管委会提供支持&#xff0c;大数据技术标准推进委员会&#xff08;CCSATC601&#xff09;…

iisnginx环境一次奇怪的跨域问题解决经过

跨域问题描述&#xff1a; iis网站跨域、nginx 网站跨域 都已配置&#xff0c;访问接口依然出现跨域问题。 错误提示&#xff1a; ccess to XMLHttpRequest at ‘https://xxx.com/gameapi/preserve/get/status’ from origin ‘https://cdn.xxx.com’ has been blocked by CO…

GO语言核心30讲 实战与应用 (io包,bufio包,os包,网络服务,http,性能分析)

原站地址&#xff1a;Go语言核心36讲_Golang_Go语言-极客时间 一、io包中的接口和工具 1. strings.Builder、strings.Reader 和 bytes.Buffer 这些类型实现了 io 包的很多接口&#xff0c;目的是什么&#xff1f; 是为了提高不同程序实体之间的互操作性。 程序实体是指比如网…

浏览器插件Video Speed Controller(视频倍速播放),与网页自身快捷键冲突/重复/叠加的解决办法

浏览器插件Video Speed Controller&#xff08;视频倍速播放&#xff09;&#xff0c;与网站自身快捷键冲突/重复/叠加的解决办法 插件介绍问题曾今尝试的办法今日发现插件列表中打开Video Speed Controller的设置设置页面翻到下面&#xff0c;打开实验性功能。将需要屏蔽的原网…

网络工程师----第三十一天

DNS&#xff1a; DNS含义&#xff1a;DNS 是 Domain Name System&#xff08;域名解析系统&#xff09; 端口号&#xff1a;DNS为53&#xff08;UDP&#xff09; 域名的层次结构&#xff1a; 域名的分级&#xff1a; 域名服务器&#xff1a; 域名解析过程&#xff1a; 递归查…

PHP xdebug

使用场景 一台MAC上安装了phpstorm&#xff0c;虚拟机安装了对应的web程序&#xff0c;需要调试。 坑点&#xff0c;网上教程太多&#xff0c;不如看官网&#xff0c;需要按照xdebug版本来配置php.ini https://www.jetbrains.com/help/phpstorm/2023.3/configuring-xdebug.htm…

【Java】HOT100+代码随想录 动态规划(上)背包问题

目录 理论基础 一、基础题目 LeetCode509&#xff1a;斐波那契数 LeetCode70&#xff1a;爬楼梯 LeetCode746&#xff1a;使用最小花费爬楼梯 LeetCode62&#xff1a;不同路径 LeetCode63&#xff1a;不同路径ii LeetCode343&#xff1a;整数拆分 LeetCode96&#xff1a;不…

vue uniapp 小程序 判断日期是今天(显示时分秒)、昨天、本周的周几、超出本周显示年月日

效果图&#xff1a; util.js /*** 转换时间*/ const messageFormat (datetime) >{ let result "";let currentTime new Date();if(isToday(datetime)){result datetime.substring(11,16);}else if(isYesterday(datetime)){result "昨天";}else if(…

操作系统磁盘管理类问题

例题&#xff1a;在磁盘上存储数据的排列方式会影响1/0服务的总时间。假设每个磁道被划分成10个物理块&#xff0c;每个物理块存放1个逻辑记录。逻辑记录R1,R2....R10存放在同一个磁道上&#xff0c;记录的排列顺序如下表所示&#xff1a; 假定磁盘的旋转速度为10ms/周&#xf…

VMware虚拟机-安装程序无法自动安装virtual machine......_windows server 2008 R2

系统版本&#xff1a;windows server 2008 R2 问题-安装程序无法自动安装virtual machine… 在使用虚拟机安装windows server 2008 R2系统中&#xff0c;安装VMware Tools工具安祖啊寄给你失败&#xff0c;提示安装程序无法自动安装virtual machine…&#xff0c;必须手动安装…

从源头到洞察:大数据时代的数据提取与分析实战指南

随着科技的飞速发展&#xff0c;大数据已经成为现代社会的核心驱动力之一。从商业决策到科学研究&#xff0c;从政策制定到个人生活&#xff0c;数据无处不在&#xff0c;影响着我们的每一个决策。然而&#xff0c;如何从海量的数据中提取有价值的信息&#xff0c;并转化为深刻…

List类

什么是 List 在集合框架中&#xff0c; List 是一个接口&#xff0c;继承自 Collection 。 Collection 也是一个接口 &#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下所示&#xff1a; List 中提供了好的方法&#xff0c;具体如下&#xff1a; List…

Conda 常用命令大全

Conda 常用命令大全 配置源conda配置清华源pip配置清华源pip配置阿里源 环境管理创建一个新的虚拟环境列出虚拟环境激活虚拟环境退出虚拟环境删除虚拟环境复制某个虚拟环境 conda包管理列出全部包安装包卸载包 pip包管理列出全部包安装包卸载包 其他命令查询 conda 版本查看环境…

C语言详解:数组指针

数组指针是指针 int* p[10] 这是指针数组的写法 &#xff0c;因为【】的优先级比*高&#xff0c; 所以为了解决优先级问题&#xff0c;加&#xff08;&#xff09; int(* p)[10]&arr;//数组的地址要存起来 说明p是指针&#xff08;首先与*结合&#xff09;&#xff0c…

哈希表法快速求解最长连续序列 | 力扣128题详细解析

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容&#xff0c;和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣&#xff01; 推荐&#xff1a;数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航&#xff1a; LeetCode解锁100…