Rusty Proxy

Bitskrieg CTFby smothy

rusty-proxy - Web

Points: 439 | Flag: BITSCTF{tr4il3r_p4r51n6_15_p41n_1n_7h3_4hh} | Solved by: Smothy @ 0xN1umb

too easy

what we got

zip file with source for a Rust reverse proxy + Flask backend. docker-compose setup, pretty standard stuff.

backend (server.py) has three routes:

  • / - index
  • /api/status - status page
  • /admin/flag - the flag lol

the rust proxy sits in front and forwards requests to the backend. but it blocks /admin:

rust
fn is_path_allowed(path: &str) -> bool {
    let normalized = path.to_lowercase();
    if normalized.starts_with("/admin") {
        return false;
    }
    true
}

so to_lowercase() means we cant just do /Admin or /ADMIN. case tricks are out. ok cool what else we got

the solve

ngl this was a one-shot solve lmao

the proxy checks the raw path string but never URL-decodes it. Flask on the backend? yeah it decodes URLs automatically because thats what WSGI servers do.

so the bypass is literally just URL-encoding one character in "admin":

/%61dmin/flag

%61 = a in URL encoding. the proxy sees /%61dmin/flag, lowercases it to /%61dmin/flag (percent encoding stays the same obv), checks if it starts with /admin — nope! forwards it through.

Flask receives /%61dmin/flag, decodes it to /admin/flag, routes it to the flag endpoint. gg

bash
$ curl http://rusty-proxy.chals.bitskrieg.in:25001/%61dmin/flag
{"flag":"BITSCTF{tr4il3r_p4r51n6_15_p41n_1n_7h3_4hh}"}

crack the code

thats it. thats the whole challenge. classic proxy vs backend path parsing mismatch. the flag even says it — "trailer parsing is pain in the ahh" fr fr

lowkey the rust code was actually pretty solid for everything else (header validation, chunked encoding handling, connection pooling) but they forgot the one thing that matters — normalize your paths before you check em

could also do stuff like /%2561dmin (double encoding), /./admin/flag, or even /%41dmin/flag (%41 = A, which Flask would decode then match case-insensitively). but the simplest %61 worked first try so why overcomplicate it

flag

BITSCTF{tr4il3r_p4r51n6_15_p41n_1n_7h3_4hh}


smothy out ✌️