Misc CTF - GraphQL Injection
This seventh challenge aims to demonstrate a more than 20 years old bug: the infamous SQL injection. A perfect challenge for beginners.
Despite being the source a numerous data breach and exploitation every years, this vulnerability is still commonly found in a lot of web apps.
Tl;Dr: Exploiting a SQL Injection on the shop website allows to retrieve a table entry containing the flag.
Alright! Let’s get into the details now!
Recon
Opening the challenge display the following website:
A simple e-commerce website, you can browse through products, add items to card and place an order. Nothing more.
Let’s dig a bit.
Browsing through the product pages we notice the elements
parameter in the URL, probably used for pagination ?
Let’s see if we can make any type of injection through this parameter before moving to the cart and order function.
SQL Injection Vulnerability
Inputing random value as parameter returns the following message:
When appending a classical AND 1=1 SQL injection to the elements parameters, the page don’t display errors but load the results normally:
To make sure we have a valid SQL Injection let’s try a sleep function injection:
1 |
|
Good since the request took 5 seconds to proceed, we now are 100% sure we have a valid SQL injection here. Let’s see what we can retrieve from the database using this vulnerability.
Getting to know the current database
To start off let’s see how to we can manually exploit the SQL injection vulnerability to exfiltrate data. In a second part we will see how to ease the task with automated exploitation tools.
To retrieve informations from the database we are going to use an UNION
attack . Here is a nice explanation of the process:
The UNION keyword lets you execute one or more additional SELECT queries and append the results to the original query. For example:
SELECT a, b FROM table1 UNION SELECT c, d FROM table2
This SQL query will return a single result set with two columns, containing values from columns a and b in table1 and columns c and d in table2.
The first thing we need to do to perform an UNION
attack is to determine the number of columns returned from the original query (the products listing query).
You can do so using two different methods:
ORDER BY
clauses injection
This method consist in injecting an ORDER BY
clauses with incremental column index until an error is returned. The advantage of ORDER BY
is that we can specify columns index number. This way we don’t have to know the exact column name.
Let’s give it a try.
First using ORDER BY 1
:
Looks alright, no error. Let’s do the same for ORDER BY 2
, ORDER BY 3
, and so on…
Arriving at ORDER BY 4
we finally get the error:
Behind the scene, the database returns an error, such as:
The ORDER BY position number 4 is out of range of the number of items in the select list.
We now gained the knowledge that the current table contains 3 columns (id
, name
, price
maybe ?)
UNION SELECT
injection
This second method involves submitting a series of UNION SELECT
payloads specifying a different number of null
values every-times.
If the number of nulls does not match the number of columns, the database returns an error, such as:
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
Again let’s give it a try:
First, using UNION SELECT NULL
:
We get an error, meaning the table have more than one column.
Let’s do the same for UNION SELECT NULL,NULL
, UNION SELECT NULL,NULL,NULL
, and so on…
Arriving at UNION SELECT NULL,NULL,NULL
we don’t get any errors:
We now confirmed in a different way that the current table contains 3 columns.
Extracting data using SQL Injection
Alright we now have all the informations we need to start extracting actual data from the database.
Let’s see how we can use UNION
attack to do so.
First, we are going to use the following query to get all the databases and tables used by the website:
1 | SELECT table_schema, table_name FROM INFORMATION_SCHEMA.TABLES |
Embed it inside our UNION
query gives the following payload:
1 | UNION SELECT table_schema,table_name,NULL FROM INFORMATION_SCHEMA.TABLES |
This query should now be able to retrieve all the databases and its table name.
Let’s give it a try:
Well… This surely looks broken but looking in the details we have all the informations we need, check the source code :
1 |
|
See what’s going here ? The “normal” shop SQL query request for the product id
and price
, using the id
in chop-<product-id>
as <div>
identifier and showing price
in <p>
tag.
In our union query, the store SQL query gets replaced by our UNION
query. The chop id
is replaced by table_schema
and price
by table_name
.
While this is not very readable we still gets all the informations we need. We now know that the only database is ctf
and contains one table: chop
.
Let’s continue our enumeration to get a list of each columns name in the chop
table. We can do so using:
1 | SELECT column_type,column_name,NULL FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='chop'-- |
Let’s give it a try:
Awesome, we were close with our guessing. Here is all the informations we collected so far:
- Database:
ctf
- Table:
chop
- Columns:
id
,price
,image_url
With that in mind let’s list all the lines in this chop
database to see if we can find juicy informations:
1 | UNION SELECT id,price,image_url FROM chop-- |
Hey what’s this last product with price to $0 and broken image ?
Let’s check the source code:
1 | <div id="chop-109" data-id="109" data-price="0" onclick="addToCart(this)"> |
Bingo!
The easy way - SQLMap
You noticed it. The manual way is not really easy nor fast to operate.
Thankfully (or unfortunately depending on the point of view) [SQLMap](https://github.com/sqlmapproject/sqlmap)
, an open source tools, allows to automate all step of a SQL Injection.
Let’s have a look at what it is capable on our Chop Shop:
1 |
|
Well that took only a bit more than 30 seconds. SQLMap can also extract all databases and tables:
1 | $ sqlmap -u "http://192.168.1.21:8080/?elements=9" --tables |
And extract databases content:
1 |
|
SQLMap also features:
- Support to enumerate users, password hashes, privileges, roles, databases, tables and columns.
- Automatic recognition of password hash formats and support for cracking them using a dictionary-based attack.
- Dump database tables entirely.
- Download and upload any file from the database server underlying file system when the database software is MySQL, PostgreSQL or Microsoft SQL Server.
- Execute arbitrary commands and retrieve their standard output.
- And the list continue…
As you can see SQLMap is an extremely complete and powerful tool, allowing anyone with little to no real knowledge to perform advanced SQL injection attacks.
That’s why it’s very important to be aware of the risks of SQL Injection and why it’s still one of the most common and dangerous vulnerability.
Mitigation
Primary defenses against SQL Injections:
- Use of Prepared Statements (with Parameterized Queries)
- Use of Stored Procedures
- Whitelist Input Validation
- Escaping All User Supplied Input
Additional Defenses:
- Enforcing Least Privilege
- Performing Whitelist Input Validation as a Secondary Defense
References
- SQL Injection Software Attack | OWASP Foundation
- SQL Injection Prevention Cheat Sheet | OWASP
- Query Parameterization Cheat Sheet | OWASP
- What is SQL Injection? Tutorial & Examples | Web Security Academy
- SQL injection UNION attacks | Web Security Academy
Real Life Example
- SQL injection in labs.data.gov via User-agent | HackerOne
- SQL injection on U.S. Dept Of Defense | HackerOne
- SQL Injection Extracts Starbucks Enterprise Accounting, Financial, Payroll Database | HackerOne
That’s it folks! As always do not hesitate to contact me for any questions or feedbacks!
See you next time ;)
-hg8