Appeler un script shell avec mysql en cli sur ubuntu 12.04 en 64 bits avec lib_mysqludf_sys

Au programme aujourd’hui, une fonction de mysql que je n’ai jamais encore touché, les UDF (User Define Functions). Cela permet de rajouter des fonctions disponibles dans les commandes mysql, et précisément dans mon cas de faire un appel système à partir d’une commande mysql.

Pour certaines raisons comme la sécurité, le core de mysql ne permet pas de faire une telle opération.

Heureusement il existe une bibliothèque de plusieurs udf sur www.mysqludf.org avec la librairie qui nous intéresse.

En prenant une Ubuntu server 12.04 LTS en 64bits vous serez surement confronté à ces messages d’erreur :

Can't open shared library 'lib_mysqludf_sys.so' (errno: 0 /usr/lib/mysql/plugin/lib_mysqludf_sys.so: cannot open shared object file
ERROR 1126 (HY000): Can't open shared library 'lib_mysqludf_sys.so' (errno: 0 /usr/lib/mysql/plugin/lib_mysqludf_sys.so: wrong ELF class: ELFCLASS32)

J’ai donc forker le projet github de Jasny pour le rendre compatible avec une installation de mysql avec apt-get sur une ubuntu 64bits.

Voila les grandes lignes pour l’installation :

apt-get update
apt-get install make gcc libmysqlclient15-dev
wget https://github.com/zephilou/lib_mysqludf_sys/archive/master.zip
unzip master.zip
cd lib_mysqludf_sys-master/
./install.sh

Ce qui devrait donner :

Compiling the MySQL UDF
gcc -m64 -fPIC -Wall -I/usr/include/mysql -I. -shared lib_mysqludf_sys.c -o /usr/lib/mysql/plugin/lib_mysqludf_sys.so 
MySQL UDF compiled successfully
Please provide your MySQL root password
Enter password: 
MySQL UDF installed successfully

A partir de là un petit test :

mysql> select sys_exec('ls / > /tmp/sortie.txt');
ERROR 1305 (42000): FUNCTION sys_exec does not exist

Ce qui est plutôt normal puisque mysqld n’a pas été redémarré.

/etc/init.d/mysql restart
mysql -u root -p
mysql> select sys_exec('ls / > /tmp/sortie.txt');
+---------------------------------+
| sys_exec('ls / > /tmp/sortie.txt') |
+---------------------------------+
|                           32512 |
+-------------------------------

On peut ce dire que tout roule mais en fait non, le fichier n’a pas été crée :

ls: cannot access /tmp/sortie.txt: No such file or directory

En fait il s’agit de l’action de apparmor sur le processus mysql, et pour s’en convaincre il suffit de le désactiver.

mv /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/.usr.sbin.mysqld
/etc/init.d/apparmor restart
/etc/init.d/apparmor status

On recommence donc :

mysql> select sys_exec('ls / > /tmp/sortie.txt');
+---------------------------------+
| sys_exec('ls / > /tmp/sortie.txt') |
+---------------------------------+
|                               0 |
+---------------------------------+
1 row in set (0.00 sec)
ls -l /tmp/sortie.txt 
-rw-rw---- 1 mysql mysql 129 Sep 25 13:17 /tmp/sortie.txt

En conclusion, même si les fonctionnalités de lib_mysqludf_sys sont sympathiques, cela pose 2 réels problèmes de sécurité :

  • La désactivation de apparmor n’est pas vraiment une bonne idée
  • En cas d’injection Isql sur votre application les dégâts sont énormes puisque cela confère un accès système