危険がデンジャー、MySQLのFile_priv

こんにちは、DBAのたなかです。
先月末くらいにAmazon RDSに触る機会があって初めて気付いたのですが、
RDSのrootはいくつか権限をREVOKEされています。
SUPERがないからSET GLOBALで設定できない話はよく聞いていたのですが、FILEもありません。
どうせシェルがないからLOAD DATA INFILE使えないし、FILE権限なんてあってもしょうがない…なんて思ってませんか?
FILE権限ってPaaS側にとっても結構デンジャーなんです。
今日はそんなおはなし。
【DBサーバーのファイルが読み取れる】
基本ですかね。
mysql> SELECT LOAD_FILE('/etc/hosts');
..
LOAD_FILEで読み込むのはサーバー側のファイルです。
mysqldの実行ユーザーが読めるファイルなら何でも読みます。
$HOMEのパスさえわかれば、.ssh/authorized_keyとか読めちゃいますね。
【ファイルが書き込める】
上書きはできないことになっているので既存のファイルが壊れることはないんですが、新しいファイルは書き込めます。
mysql> SELECT 'Hello, World!!' INTO OUTFILE '/tmp/mysql'; shell> cat /tmp/mysql
Hello, World!!
勿論サーバー側に置かれます。
$HOME/.profileとか置かれたら結構惨事になる気がします。
【頑張れば任意のファイルを実行させられる】
上2つの絡め技と、mysqlスキーマへのINSERT権限(PaaSだろうとrootにはあると思う)が必要ですが、極めつけデンジャーです。
open($fd, "< ./sql/udf_example.so");
binmode($fd);
..
$stmt= $conn->prepare("SELECT ? INTO DUMPFILE 'plugin-dir/aaa.so'");
$stmt->execute($bin);
コンソールからはバイナリファイルを綺麗に流し込めなかったので、Perlで叩きました。
たとえばソースコードに入っているudf_example.ccをコンパイルして作った.soファイルの中身をリモートから流し込みます。
mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME 'aaa.so';
myfunc_intはudf_example.ccで定義されているUDFです。
mysqlスキーマへのINSERT権限があれば、このCREATE FUNCTIONはあっさり通って、myfunc_intはどのユーザーからも関数として叩けるようになります。
UDFのインターフェイスは公開されている(し、大体MySQLはオープンソースだし)ので、「任意のスクリプトや実行ファイルを叩くUDF」の作成もそこまで難しくはありません。
更に、ここまで全部SQLだけでやっているので、SQLインジェクションと上手くかみ合えばコンソールすら要りません。
すごく危険ですね!
そのままのrootとか、危ないよ、というお話しでした。