Job App Simulator
b01lersc
Task: an Apache CGI Bash application parses a form and checks graduation_year with [[ ... -lt 2026 ]], causing attacker input to be evaluated as arithmetic. Solution: inject an array subscript with command substitution, print /flag.txt through /proc/$PPID/fd/1, and leave the expression as 2026+a[0] so validation succeeds.
$ ls tags/ techniques/
$ cat /etc/rate-limit
Rate limit reached (20 reads/hour per IP). Showing preview only — full content returns at the next hour roll-over.
Job App Simulator — b01lers CTF 2026
Description
No official organizer description was included with the provided challenge files.
We are given an Apache CGI Bash application that accepts an application/x-www-form-urlencoded job application form. The goal is to turn the graduation_year validation into code execution and recover the real flag from /flag.txt.
Analysis
The important part of application.sh is the form parsing and the graduation year check:
declare -A form_data while IFS='=' read -r -d '&' key value && [[ -n "$key" ]]; do form_data["$(urldecode "$key")"]="$(urldecode "$value")" done <<<"$request_body&" if [[ "${form_data[graduation_year]}" -lt 2026 ]]; then echo "Invalid graduation year" return fi
At first glance this looks like a simple numeric comparison, but in Bash the operands of [[ x -lt y ]] are evaluated as arithmetic expressions. That means attacker-controlled input is not treated as a plain string here.
So if we control graduation_year, we can supply an arithmetic expression instead of a normal year. Bash arithmetic also understands array syntax such as a[0], and array subscripts can contain command substitution. This gives a payload shape like:
2026+a[$(command)0]
If $(command) produces no captured stdout, the expression becomes:
2026+a[0]
In arithmetic context an unset array element evaluates to 0, so the whole expression becomes 2026, which is not less than 2026. The validation therefore passes.
Why /proc/$PPID/fd/1 works
There is one catch: output written to normal stdout inside $(...) is consumed by the command substitution itself and inserted back into the arithmetic expression, which would corrupt it.
The fix is to write directly to the parent shell's file descriptor 1 instead:
/proc/$PPID/fd/1
...