跳到内容

不离开GitHub的安全研究:从代码扫描到通过代码空间和私有漏洞报告的CVE

这篇博客文章深入介绍了我们如何利用GitHub功能进行安全研究,包括代码扫描、CodeQL和Codespace。

不离开GitHub的安全研究:从代码扫描到通过代码空间和私有漏洞报告的CVE
作者

各位读者好!你有没有想过GitHub安全实验室进行安全研究?在本文中,您将了解我们如何利用GitHub产品和功能,如代码扫描、CodeQL、Codespace和私有漏洞报告。到我们结束时,您已经掌握了快速配置一个干净的临时环境的艺术,以便发现、验证和公开开放源码软件(OSS)中的漏洞。

当您浏览本文内容时,您会注意到我们涵盖了大量GitHub工具。如果您有任何反馈或问题,我们鼓励您与我们的社区讨论请放心,这篇文章旨在让读者能够访问,无论他们之前是否熟悉我们提到的工具。所以,让我们一起开始这段旅程吧!

找到一个有趣的目标

根据研究目的,“有趣”目标的概念可能对你们每个人都有不同的含义。为了找到一个“有趣”的目标,也为了让它变得有趣,你必须先写下一些过滤器,除非你真的想深入研究任何东西!从项目所用的语言来看,通过它所展现的表面(它是一个应用程序吗?一个框架?),每个方面都必须有一个明确的目标。

例如,通常其中一个方面是使用项目的人数(即发生漏洞时受影响的人数),这由GitHub提供依赖网络(例如,喷灯),但还不止于此:我们还对项目更新的频率、星星幸运的是,开源安全基金会(OpenSSF)的一些非常聪明的人已经在这个主题上做了一些繁重的工作。

OpenSSF关键性得分

OpenSSF创建了开源项目关键性得分,它“定义了项目的影响和重要性。它是一个介于0(最不重要)和1(最重要)之间的数字。”有关评分算法的详细信息,可以在ossf/关键性核心存储库或这个帖子推出几个月后,谷歌为排名前10万的GitHub存储库收集信息并在中共享这个电子表格.

在GitHub安全实验室内,我们不断分析OSS项目,目的是保持软件生态系统的安全,重点关注我们都依赖和依赖的高调项目。为了找到前者,我们将目标列表基于OpenSSF关键性得分。

流程的开始

我们发布了我们的护卫舰代码审查其中,我们使用PyYaml的默认值对用户控制的数据进行反序列化装载机。这是一个很好的项目,可以作为本文的运行示例,因为它的下载量超过160万次F类rigate集装箱在编写时以及设置过程的简单性。

原始版本
我们不会在这篇博客文章中发现新的漏洞。相反,我们将使用用户控制数据的反序列化 问题我们报道是为了说明这篇文章。

看看上面的电子表格,Frigate的得分约为16k,得分为0.45024,这还不算重要(>0.8),但在近两年前还不错!如果你好奇,想了解更多关于计算临界值的知识,那么继续计算护卫舰的当前分数ossf/关键性核心.

参与项目

一旦我们确定了目标,让我们通过以下两种方式分配存储库GitHub的UICLI(命令行界面).

gh repo fork blakeblackshear/护卫舰--仅限默认分支

分叉后,让我们回到执行审计的状态:(sha=9185753322cc594b99509e9234c60647e70fae6f)

使用GitHub的API更新引用:

gh api-X PATCH/repos/username/护卫舰/git/refs/heads/dev-Fsha=9185753322cc594b99509e9234c60647e70fae6f-F力=真

或使用吉特:

git克隆https://github.com/用户名/frigatecd护卫舰git结帐9185753322cc594b99509e9234c60647e70fae6fgit推送原点HEAD:dev--force

现在我们准备继续!

代码扫描和CodeQL

代码扫描是GitHub的解决方案,用于查找、分类和优先处理代码中现有问题的修复。

CodeQL提供的“安全”选项卡中的代码扫描警报
CodeQL提供的“安全”选项卡中的代码扫描警报
拉取请求警报
拉取请求警报

当代码扫描与像GitHub的CodeQL这样的静态分析工具“连接”时,奇迹就发生了,但我们马上就会实现。

代码QL是GitHub开发的静态代码分析引擎,用于自动化安全检查。CodeQL执行语义和数据流分析,“让您可以像查询数据一样查询代码。”CodeQL's learning curve at the start可能有点陡峭,但绝对值得付出努力,因为它的数据流库允许解决任何情况。

学习代码QL
如果你有兴趣通过练习和其他方式更多地了解静态分析的世界,请继续学习@西尔维亚·布丁辛斯卡CodeQL零到英雄系列。您可能还想加入GitHub安全实验室松弛实例与CodeQL工程师和社区一起闲逛。

创建CodeQL工作流文件

GitHub工程师在使CodeQL分析在一键式时尚然而,为了了解幕后发生的事情(因为我们是研究人员😎), 我们将进行手动设置。

大规模运行CodeQL
在这种情况下,我们在预存的基础上使用CodeQL。如果您有兴趣大规模运行CodeQL来搜索跨存储库的零日漏洞及其变体,请随时了解有关多基因变异分析事实上,安全实验室已经做到了一些工作一次在1k多个存储库上运行CodeQL!

要创建工作流文件,请执行以下步骤:

  1. 访问您的叉子

    出于安全和简单的原因,我们将删除现有的GitHub Actions工作流,这样我们就不会运行不需要的工作流。为此,我们将使用github.dev公司(GitHub的基于web的编辑器). 对于这种不需要审查、重建或测试的代码更改,只需浏览到/.github/工作流,按.(点)键一次,就会在浏览器中弹出VS代码编辑器。

    从GitHub.dev中的项目中删除GitHub Actions工作流

    并推动更改:

    通过Github.dev上的“提交并推送”按钮推送更改。

  2. 启用GitHub操作(可选)

    前往GitHub Actions选项卡,单击“I understand my workflows,go ahead and enable them”。注意,这可能会如果您以前删除了所有工作流,则会显示。

  3. 前往“安全”选项卡

  4. 点击“代码扫描”
  5. 点击“配置扫描工具”
  6. 在CodeQL分析中,单击“设置”,然后单击“高级”

    现在,您将被引导到GitHub的UI文件编辑器,其中包含一个自定义工作流文件(其源代码位于操作/启动-工作流)对于CodeQL操作。您可以通过查看在push.branches上战略矩阵语言值。

行动文件
如果您不熟悉GitHub操作,请参阅文档了解工作流的基础知识。

乍一看,我们可以看到分析将为工作流中定义的每种语言运行的作业。这个分析工作将:

  1. 克隆存储库
  2. 初始化CodeQL

    在这一步中,github/codeql-action/init将下载本地不可用的最新版本的CodeQL或CodeSQL包。

  3. 自动生成

    自动构建步骤将尝试自动构建工作区中的代码(步骤1),以便填充数据库以供以后分析。如果它不是一种编译语言,它就会成功并继续下去。

  4. 分析

    将调用CodeQL二进制文件以最终确定CodeSQL数据库并对其运行查询,这可能需要几分钟的时间。

使用安全实验室的社区QL包进行高级配置

使用CodeQL的默认配置(默认工作流),您已经发现了有影响力的问题。我们的CodeQL团队确保默认查询被设计为具有非常低的误报率,以便开发人员可以放心地将其添加到CI/CD管道中。然而,如果您是GitHub security Lab这样的安全团队,您可能更喜欢使用一组不同的审核模型和查询,这些模型和查询的误报率较低,或者使用针对特定目标或方法定制的社区驱动模型。考虑到这一点,我们最近发布了CodeQL社区包使用它就像在工作流文件中使用一行程序一样简单。

正如README所述,我们只需要添加一个包装中的变量初始化CodeQL步骤:

-name:初始化CodeQL用途:github/codeql-action/初始化@v2具有:语言:${{matrix.language}}包:githubsecuritylab/codeql-${{matrix.language}}-queries

完成后,我们就可以保存文件并浏览结果了!有关自定义扫描配置的更多信息,请参阅文档.我觉得最有趣的是使用自定义配置文件.

浏览警报

几分钟后,结果将显示在“安全”选项卡中;让我们挖吧!

存储库警报的可用筛选器
存储库警报的可用筛选器

代码扫描警报剖析

虽然您可能认为在本地运行CodeQL会更容易,但代码扫描提供了额外的内置机制,以避免重复警报、确定优先级或消除它们。此外,单个警报页面提供的信息量可以为您节省大量时间!

CodeQL发现的用户控制数据反序列化的代码扫描警报
CodeQL发现的用户控制数据反序列化的代码扫描警报

几秒钟后,这个视图就回答了几个问题:什么、在哪里、何时以及如何。尽管我们可以看到水池周围有几条线,但我们需要看到整个流程,以确定是否要继续进行开采。为此,请单击显示路径.

用户控制数据警报反序列化的流程步骤
CodeQL发现的用户控制数据反序列化的代码扫描警报

在这个视图中,我们可以看到漏洞流从用户可控制的节点(在CodeQL-fu中,RemoteFlowSource)开始,该节点在没有消毒剂的情况下流向已知的PyYaml接收器。

挖掘警报

仅仅查看警报页面和流路径还不足以猜测这是否会被利用。同时新建配置显然是我们可以控制的,我们不知道装载机那个山药装载正在使用。一种风俗装载机可以继承很多装载机类型,所以我们需要确保继承的装载机允许自定义构造函数。

def load_config_with_no_duplicates(raw_config)->dict:定义加载_配置_无重复项(raw_config)->dict:“”“获取配置以确保不允许重复密钥。”“”类PreserveDuplicatesLoader(yaml.loader.loader):通过...return yaml.load(raw_config,PreserveDuplicatesLoader)

然而,我们知道CodeQL使用数据流进行查询,因此它应该已经检查了装载机类型,对吗?

社区帮助CodeQL变得更好

当我们写关于护卫舰审计,我们遇到了一个针对我们刚刚帮助修复的漏洞的新警报!

政客伯尼·桑德斯(Bernie Sanders)的模因(Meme)写道:“我再一次请你帮我解决问题。”

我们的修复建议是更改装载机yaml.loader公司。装载机yaml.loader公司。安全装载机,但事实证明,尽管CodeQL占了已知的安全装载机,它不考虑继承这些类的类。因此,代码扫描没有关闭我们报告的警报。

安全世界是巨大的,每天都在发展。也就是说,支持每个查询存在的每个源、消毒剂和接收器是不可能的。安全性需要开发人员和安全专家之间的协作,我们鼓励使用CodeQL的每个人以以下任何形式进行协作,以将其带回社区:

  • 在中报告假阳性github/codeql:CodeQL工程师和社区成员正在积极监视这些。当我们遇到之前解释的假阳性时,我们打开了github/codeql#14685.
  • 为安全实验室建议新型号CodeQL社区包:无论你是倾向于通过制作一个引入新模型或查询的拉取请求,还是通过打开一个Issue来分享你的模型或查询概念,你都已经对研究界产生了巨大的影响。此外,该存储库还由CodeQL工程师监控,因此您的建议可能会影响到主存储库,从而影响到大量用户和企业。你的参与比你想象的更有影响力。
CodeQL模型编辑器
如果您有兴趣了解如何使用CodeQL支持新的依赖项,请参阅CodeQL模型编辑器。模型编辑器旨在帮助您对标准CodeQL库不支持的代码库的外部依赖项进行建模。

既然我们确信这个问题的可利用性,我们就可以进入开发阶段了。

GitHub代码空间

代码空间横幅

代码空间是GitHub的云、即时和可定制开发环境解决方案,基于Visual Studio代码。在本文中,我们将使用codespace作为我们的开发环境,因为它具有安全(隔离)和短暂的特性,因为我们只需单击鼠标即可创建和删除代码空间。尽管此功能有自己的演员表,我们将每月使用免费的120个核心小时。

创建代码空间

只需单击一个按钮,即可在GitHub.dev上创建新的代码空间

当我说“我们只需点击一下就可以创建和删除代码空间”时,我并不是在开玩笑。只需转到“代码”,然后单击“在设备上创建代码空间”。幸运的是,护卫舰维护人员已经帮助我们开发了一个自定义的设备容器配置,用于与VSCode(以及代码空间)无缝集成。

自定义设备容器配置
有关的更多信息.devcontainer文件自定义,请参阅文档.

加载后,我建议您关闭当前的浏览器选项卡,使用VSCode和远程资源管理器扩展。有了这样的设置,我们就有了一个具有内置端口转发的完全集成环境。

为调试和利用而设置

在进行安全性研究时,准备好调试的完整设置可能会改变游戏规则。在大多数情况下,利用该漏洞需要分析应用程序如何处理和响应您的交互,这可能是不调试就不可能.

调试

在创建代码空间后,我们可以看到它失败了:

生成错误
生成错误

考虑到设备容器配置,我们可以猜测它不是为代码空间而设计的,而是为地方的VSCode安装不应在云中使用。单击“View Creation Log”(查看创建日志)可以帮助我们发现Docker正在尝试查找一个不存在的设备:

错误:对于护卫舰-devcontainer-无法启动服务devcontainer:在添加自定义设备“/dev/bus/usb”时收集设备信息时出错:没有此类文件或目录

我们需要前往docker-compose.yml公司文件(/工作空间/护卫舰/码头组合yml)并评论以下内容:

  • 这个设备财产
  • 这个部署财产
  • 这个/开发/总线/usb体积

然后,我们去/工作区/护卫舰/.devcontainer/post_create.sh并拆下第5-9行。

更改后,我们可以成功重建容器:

重建容器
重建容器

重建后,我们可以在端口转发部分看到6个端口。然而,护卫舰API(我们通过nginx瞄准的API)并没有激活。为了解决这个问题,我们可以通过进入“运行和调试”(左侧)面板并单击绿色(类似于播放)按钮来开始调试护卫舰。

运行和调试

开采

内置端口转发功能允许我们使用网络相关软件,如Burp套件教程Caido公司就在我们的本地的主机,因此我们可以发送以下请求:

POST/api/config/save HTTP/1.1主持人:127.0.0.1:53128内容物长度:50!!python/object/apply:os.popen-触摸/tmp/pwned

使用调试设置,我们可以分析如何新配置流向山药装载并创建/tmp/pwned文件。

分析`newconfig`如何流向`yaml.load`并创建`/tmp/pwned`文件。

现在我们有了一个有效的漏洞来证明该漏洞,我们准备向项目报告它。

私有漏洞报告

Meme中,一位老妇人举起眼镜,眯着眼看笔记本电脑屏幕。

由于许多原因,报告开放源码项目中的漏洞从来都不是一个容易的主题:找到与维护人员沟通的私人方式,获得他们的答复,以及就漏洞所涵盖的许多主题达成一致,在基于文本的渠道上是相当具挑战性的。这就是为什么私有漏洞报告(PVR)解决了:一个单一的、私有的、交互式的地方,在这里,安全研究人员和维护人员共同努力,使他们的软件更加安全,使他们依赖的消费者更加了解。

结束循环
由私有漏洞报告生成的已发布咨询可以包含在GitHub咨询数据库使用自动向最终用户披露您的报告依赖者!

请注意,GitHub选择了以opt-in的方式引入此功能,这与我们的开发人员第一理念相一致。此方法授予项目维护人员自主决定是否希望参与此报告体验的权利。也就是说,告诉您最喜欢的维护人员启用PVR!你可以在我们打开的问题当我们找不到安全和私有的方法报告漏洞时。

发送报告

一旦我们验证了漏洞并构建了概念验证(PoC),我们就可以使用私有漏洞报告与护卫舰维修人员私下沟通。

护卫舰储存库中安全咨询页面的屏幕截图,突出显示“报告漏洞”按钮。

此功能允许使用特殊值,如受影响的产品、自定义CVSS严重性、将CWE链接并使用定义的角色分配积分、确保准确的文档和正确的识别,这对于协作和有效的安全社区至关重要。

用于报告漏洞的表单的屏幕截图。这些字段包括标题、描述、受影响的产品、严重性和弱点。

报告后,它允许两端(报告者和维护者)在聊天中协作,并在一个临时的私有分叉中一起编码请求CVE通常只需两天时间即可创建。

GitHub问题评论的屏幕截图,说明已针对报告的漏洞发布CVE。该评论包括CVE的编号和CVE列表的链接。

有关PVR的更多信息,请参阅文档.

已发布报告示例
已发布报告示例

GitHub和安全研究

在当今的技术驱动环境中,GitHub是安全研究人员的宝贵资源。通过将代码扫描、代码空间和私有漏洞报告等工具无缝集成到平台中,研究人员可以有效地识别和解决端到端的漏洞。

这一全面战略不仅使研究变得更容易,而且还加强了全球网络安全社区。GitHub通过提供一个安全、协作和高效的平台来发现和处理潜在的威胁,为经验丰富的安全专业人员和有抱负的研究人员提供了强大的力量。它是提高安全性和跟上不断变化的威胁形势的目标。

快乐的编码和研究!

GitHub安全实验室的使命是激励和帮助社区保护我们所有人都依赖的开源软件。了解有关他们工作的更多信息.

从GitHub了解更多信息

安全

安全

安全的平台,安全的数据。让安全成为您的首选所需的一切。
ReadME项目

ReadME项目

来自开发人员社区的故事和声音。
GitHub Copilot公司

GitHub Copilot公司

不要单飞。免费试用30天。
在GitHub工作!

在GitHub工作!

查看我们当前的职位空缺。