Alice and the Literal Escape


Alice and the Literal Escape

Captain-explorer Alice sets sail on the Star Wind for a crossing into the unknown!

Two security locks protect the cargo hold: the Quartermaster checks that only the ship’s mousses embarked ‘from the deck’ have access to the administration bridge.

The Logbook records every cargo in the hold; a strange process converts your notes into a record.

Flag is located in flag.txt

Introduction

This challenge is a medium WEB challenge from the ECW 2025 CTF. At the start of the challenge, we get the website sources, so it’s a white-boxed challenge:

Code

X-Forwarded-For - whitelist ip bypass

As you can see, only the 127.0.0.1 remote IP address can access to that API. They’re properly using the whitelist instead of the blacklist, so thats good.

But, when you try to inject 127.0.0.1 in the X-Forwarded-For header, it works.

Header injection

And we now have access to that website properly.

Website content

We can see a big textarea here, waiting our text. From the sources, we know that we’ll need to do an SQL injection.

SQLi

Don’t forget that we need to read the flag in the flag.txt file.

Let’s analyse a bit the code:

import psycopg2, subprocess, textwrap, os, json

conn = psycopg2.connect("dbname=postgres")
PSQL = ["psql", "-d", "postgres", "-q"]

@app.post("/cargo/upload")
async def cargo(request: Request, note: str = Form(...)):
    sql = f"INSERT INTO notes VALUES('"+note+"');"
    proc = subprocess.run(
            PSQL,
            input=sql,
            capture_output=True,
            text=True
        )
        reply = json.dumps({
            "rc": proc.returncode,
            "out": proc.stdout,
            "err": proc.stderr,
        }, indent=2, ensure_ascii=False)

First of all, we try to open a new connection to postgress with psycopg2, but we never use it.

The INSERT INTO SQLi is executed in a subprocess. Which means we are in the psql process, and not a basic SQL connection.

Which will allows us to execute some custom commands of psql, such as \l to list the existing databases.

SQLi

We can also execute any shell command such as cat flag.txt simply by putting a \! at the start of the psql instruction.

'); \! cat flag.txt #

Flag

Flag: ECW{st4rlit_carg0_manif3st}

We could also try to read the file using an old classic SQLi method with lo_import(“/app/flag.txt”), lo_get, and pg_largeobject. Unfortunately, the SQL process does not have sufficient rights to read the file via SQL queries. Because, they’ll be executed with the postgres user, but the psql process was start with root, so we were able to read the file.