MySQL connect file read

Howdy, guys. Today I want to tell you about MySQL & MariaDB protocol feature which can help you read files from client.

It works on all platforms and all versions of MySQL/MariaDB server.

Overview.

For testing purposes I’m install instance of MySQL server. I was used a Wireshark as traffic analyzer tool and tcpdump for capture.
I’m connect to my server from mysql client with –enable-local-infile option and run LOAD DATA LOCAL INFILE ‘/etc/passwd’ INTO TABLE test FIELDS TERMINATED BY ‘\n’; query.

MySQL local data infile
MySQL local data infile

Let’s see in depth how LOCAL DATA INFILE query works.
1. Client connects to TCP 3306 port
2. Server send greeting packet with protocol thread id, version, type of mysql authentication etc.

MySQL greeting packet
MySQL greeting packet

3. Next packet from client is authentication packet with username, password, database. There is client capabilities binary mask with Can Use LOAD DATA LOCAL option (remember –enable-local-infile).

MySQL auth packet
MySQL auth packet

4. After that there are some packet with client specified queries like: ”’show databases”’, ”’select @@version_comment limit 1”’ etc.

MySQL packets with specified queries
MySQL packets with specified queries

5. And now we can see packet from client with our query with LOAD DATA LOCAL INFILE ‘/etc/passwd’ INTO TABLE test FIELDS TERMINATED BY ‘\n’

Local data infile packet
Local data infile packet

Look at the server response packet

Local data infile server response
Local data infile server response

This packet is say to our client: “Hey client, please read the /etc/passwd file and send to it me I’ll see what I can do for you”.
What’s happens if we are craft packet like this manually and send to client? That’s right we’ll read file from client machine.

Exploit.

To exploit this you need:
1. Greet MySQL client
2. Wait for query packet (03)
3. Answer with local data file request (0c 00 00 01 fb 2f 65 74 63 2f 70 61 73 73 77 64). First two bytes is size of packet (0c). Next 6 bytes is packet number (00 00 01). Next two bytes is packet type (fb) and then filename (2f 65 74 63 2f 70 61 73 73 77 64 /etc/passwd).

You can find pseudo MySQL server for this feature exploitation here https://github.com/Gifts/Rogue-MySql-Server. Thanks to Gifts from Positive Techonoliges for share that. Read files are written to mysql.log.
For successfully exploitation you need at least one query to server. Fortunately most of mysql clients makes at least one query like ‘SET names “utf8” or something.

Here you can see my fork which working with latest MySQL versions. Edit source code and specify files to read.

Read file through adminer
Read file through adminer

Exploit different clients.

  • PHP

PHP has some mysql client extensions like mysql, mysqli, pdo. All of them are exploitable instead of PDO. In PDO load data local is disabled by default. If you try to read file then you receive an error message.

For enable exploitation you can set PDO::MYSQL_ATTR_LOCAL_INFILE to true in connect options http://php.net/manual/en/ref.pdo-mysql.php#pdo.constants.mysql-attr-local-infile. But neither developers enable this option of course.
Look closer at mysqlnd library. Mysqlnd – MySQL native driver for PHP is a drop-in replacement for the MySQL Client Library (libmysql) for the PHP script language.
Mysqlnd is default PHP driver from 5.4 version. If PHP running with that library you can use wrappers during exploitation.

Edit MySQL exploit
Edit MySQL exploit

I was created simple code for testing purposes:

And try to read Yandex start page through resource filter php://filter/convert.base64-encode/resource=http://ya.ru:

mysqlnd PHP wrapper read
mysqlnd PHP wrapper read

It’s working very well 😉 Move next.

  • Python

If server uses MySQLdb as client library the exploit doesn’t work. local_infile connect option is required to set up. But with mysql.connector exploit working very well.

 

That’s all for now. You can try to check for successful exploitation in other language by yourself. Have nice day and good luck.