On MySQL it is possible to create a User-Defined Function to execute commands on the underlying operating system. Marco Ivaldi demonstrated that some years ago. His raptor_udf2.c works well, but it has two limitations:
- It is not MySQL 5.0+ compliant because it does not follow the new guidelines to create a proper UDF.
- It calls C function system() to execute the command and returns always integer 0.
I recently came across an open repository of MySQL User-Defined Functions maintained by Roland Bouman and other developers. One of their codes kept my attention: lib_mysqludf_sys (version 0.0.2) which implements three different functions to interact with the underlying environement:
sys_exec: executes an arbitrary command, and can thus be used to launch an external application.sys_get: gets the value of an environment variable.sys_set: create an environment variable, or update the value of an existing environment variable.
- It is MySQL 5.0+ compliant and it compiles on both Linux as a shared object and on Windows as a dynamic-link library.
- It returns the exit status of the executed command.
The patched source code can be found on sqlmap subversion repository here and a single patch file for the original lib_mysqludf_sys version 0.0.2 is available here.
Usage example:
$ wget --no-check-certificate https://svn.sqlmap.org/sqlmap/trunk/sqlmap/extra/mysqludfsys/lib_mysqludf_sys_0.0.3.tar.gz
$ tar xfz lib_mysqludf_sys_0.0.3.tar.gz
$ cd lib_mysqludf_sys_0.0.3
$ sudo ./install.sh
Compiling the MySQL UDF
gcc -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o /usr/lib/lib_mysqludf_sys.so
MySQL UDF compiled successfully
Please provide your MySQL root password
Enter password:
MySQL UDF installed successfully
$ mysql -u root -p mysql
Enter password:
[...]
mysql> SELECT sys_eval('id');
+--------------------------------------------------+
| sys_eval('id') |
+--------------------------------------------------+
| uid=118(mysql) gid=128(mysql) groups=128(mysql) |
+--------------------------------------------------+
1 row in set (0.02 sec)
mysql> SELECT sys_exec('touch /tmp/test_mysql');
+-----------------------------------+
| sys_exec('touch /tmp/test_mysql') |
+-----------------------------------+
| 0 |
+-----------------------------------+
1 row in set (0.02 sec)
mysql> exit
Bye
$ ls -l /tmp/test_mysql
-rw-rw---- 1 mysql mysql 0 2009-01-16 23:18 /tmp/test_mysql
UPDATE on January 25, 2009: Roland Bouman uploaded to the MySQL User-Defined Functions repository my patched version of lib_mysqludf_sys. He also updated its manual page. You can now get version 0.0.3 also from his repository.
PacketStormSecurity.org and milw0rm.com mirrored it here and here.

8 comments:
awesome! Thank you Bernardo! I love it... :)
Welcome Ulisses
Yeah, but unfortunately not quite useful from an attacker's viewpoint, because /usr/lib is usually writable by root only. In most cases if you can create root-owned files, then you wouldn't need those mysql udf functions.
Useful or not is an opinion. Take into account that on a few old configurations /etc/cron.d/mysql file is writable by the mysql user and/or mysqld runs as root, in both cases an attacker could append a 'chmod 666 to /usr/lib' (i.e. through a SQL injection with INTO OUTFILE) since the cron process is executed as root. On Windows the library path is writable simply because the mysql daemon process runs as SYSTEM.
Thank you very much!
I have a problem, when I use it. For example, when I install it, I get the following error message:
=============
(errno: 22 /usr/lib/mysql/plugin/lib_mysqludf_sys.so: cannot restore segment prot after reloc: Permission denied)
=================
After I disable SELinux, I can install it.
When I run “select sys_eval('id');”, the result is empty. After I disable SELinux, I can run “select sys_eval('id');” and get the result.
Is it possible to use the UDF without disabling SELinux?
You need root access on the system to install it because it is copied to /usr/lib folder.
You can not run either of the functions within MySQL when SELinux is enabled for security reasons, the same happens with AppArmor if it has been initialized with a MySQL profile ruleset, for details check this other blog post.
It would be possible to install/run the functions with SELinux and AppArmor enabled only if you instruct them to allow MySQL process to call system(), popen(), etc.
nice collection
Great blog and nice post I am trying to maintain a list of cute blogs. Thanks and nice collection of blogs. I’m going to have to browse through those. it’s nice I can come and read your blog.
ccna ccent
Post a Comment