The objective of this challenge is to access and read the /flag.html file hosted on an Nginx server. However, the server is protected by an advanced firewall that leverages eBPF (Extended Berkeley Packet Filter) technology.
This firewall inspects all network trafficāboth ingress and egressāand blocks any packet containing the keyword "flag" or the "%" symbol. Participants must devise a method to bypass these restrictions to successfully retrieve the contents of the file.
From this setup, it is clear that requests are limited to a maximum of three characters. Any request containing the keyword "flag" will be dropped by the firewall. Furthermore, attempts to bypass the restriction using encoding are also blocked, since encoded strings inherently include the "%" symbol, which is filtered as well
Solution
No-Quotes
uoftctf{w0w_y0u_5UcC355FU1Ly_Esc4p3d_7h3_57R1nG!}
Overview/Idea
The login mechanism is flawed: the source code reveals that SQL queries are constructed in an unsafe manner, leaving the application vulnerable to SQL Injection.
After successfully bypassing authentication, the application continues to expose insecure functionality through its template rendering engine. Improper handling of template functions introduces a Server-Side Template Injection (SSTI) vulnerability, which can be leveraged to execute arbitrary commands on the server.
Source Code Analysis
The WAF in this challenge only filters single(') and double quotes("), which can be bypassed using hex encoding, and since the SQL input is directly inserted into the query, authentication can be bypassed with a backslash escape (\) and a crafted UNION SELECT payload.
After login, insecure template rendering allows classic SSTI injection because the dot(.) operator is not blocked, so a payload such as {{ config.__class__.__init__.__globals__.os.popen('/readflag').read() }} can be used, encoded into hex to avoid quote restrictions.
Step 1: Bypassing the Request Filter
The firewall blocks any packet containing the keyword "flag" or the "%" symbol. To avoid detection:
- Split the request into smaller parts so that the forbidden keyword never appears in a single packet.
- Example:
-- GET /f
-- lag.html
Since neither packet contains the blocked keyword, the firewall allows them through.
When Nginx reassembles the packets, it correctly interprets the request as GET /flag.html.
Step 2: Handling the Response
The firewall also inspects outgoing traffic. If the response contains the word āflagā, it will be blocked. To bypass this:
- Force the server to send the response in small chunks, ensuring that the forbidden keyword does not appear in a single packet.
- This can be achieved using the HTTP Range header, which allows requesting specific byte ranges of the file.
By retrieving the file in byte-sized chunks, the response avoids containing the blocked keyword in any single packet, allowing the participant to reconstruct the full contents of /flag.html.