MySQL UDF and AppArmor

From Wikipedia:
AppArmor allows the system administrator to associate with each program a security profile which restricts the capabilities of that program. It supplements the traditional Unix discretionary access control (DAC) model by providing mandatory access control (MAC).

By default AppArmor is running out-of-box on
Ubuntu, openSUSE, Mandriva and a few other Linux distributions.
Ubuntu offers it as a package since Feisty release, and runs it by default since Gutsy release.

Since Ubuntu Hardy the MySQL 5.0 server package contains also an AppArmor profile file (/etc/apparmor.d/usr.sbin.mysqld) which limits MySQL server functionalities, like calling an UDF to execute commands.
The file is owned by root and has 644 permissions by default so only having root privileges on the box it is possible to write (i.e. with INTO OUTFILE clause in a SQL SELECT statement) on it in order to add a rule that allows command executions from an UDF.

Example:
$ sudo apparmor_status
[...]
1 processes have profiles defined.

0 processes are in enforce mode :

0 processes are in complain mode.

1 processes are unconfined but have a profile defined.

/usr/sbin/mysqld (5128)


$ mysql -u root -p mysql
Enter password:
[...]

mysql> SELECT sys_eval('id');
+----------------+
| sys_eval('id') |

+----------------+

||

+----------------+

1 row in set (0.12 sec)


mysql> select sys_exec('id');

+----------------+

| sys_exec('id') |

+----------------+

| 32512 |

+----------------+

1 row in set (0.01 sec)


mysql> exit

Bye


$ sudo /etc/init.d/apparmor stop

Unloading AppArmor profiles : done.


$ sudo apparmor_status
[...]
0 processes have profiles defined.

0 processes are in enforce mode :

0 processes are in complain mode.
0 processes are unconfined but have a profile defined.

$ 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('id');

+----------------+

| sys_exec('id') |

+----------------+

| 0 |

+----------------+

1 row in set (0.10 sec)

I am brainstorming with a friend on how to bypass AppArmor and we have come out with a couple of ideas so far.. And you? Feel free to get in touch with me in case you've any idea or technique to do that.

1 comments:

J.C. Denton said...

Check the mysql profile located in "/etc/apparmor.d" and make an evaluation then with auditd (check system log /var/log/audit/audit.log). Finally use "aa-genprof" to generate a new profile based on your analysis.