Reading And Writing Files Via SQL Injection

Although SQL is traditionally used to manipulate data within a database. Occasionally, it can be used to read and write system files. The ability to interact with the file system grants much further reach and can lead to further compromise.

Although there are several SQL database technologies, in this example I’ll be discussing how MySQL can interact with the file system and how this can be abused.

Enumerating The Current User’s Privileges

Before simply jumping into reading a file, it would be beneficial to understand the conditions which allow for a file to be read. To read system files, the current MySQL database user must have the FILE privilege.

SQL injection is often performed using the UNION operator, this allows for two SELECT statements to be joined together. The two SELECT statements would need to retrieve the same amount of columns otherwise this would result in an error.

The following example shows two SELECT statements, the first is selecting a single column “book_name” and the second statement is selecting the current user.

SELECT `book_name` FROM `books` WHERE `name`='Lord of the rings' UNION SELECT user()-- -

Once injected, the book_name contents would be retrieved along with the current database user, this would appear in the following format dbadmin@localhost.

After the current user has been identified, it is possible to enumerate what privileges they have. Any privileges are saved in the information_schema.user_privileges table. Due to the way MySQL stores privileges, it is not possible to make use of the user() function. When specifying which permissions we want to retrieve, the user or “grantee” must be provided in the following format ‘dbadmin’@’localhost’.

UNION SELECT GROUP_CONCAT(PRIVILEGE_TYPE) FROM information_schema.user_privileges WHERE grantee="'dbadmin'@'localhost'"-- -

The above statement would then return all of the specified user’s privileges as a single string, this is why the GROUP_CONCAT function was used. The output would then be similar to the example found below.


Reading System Files

From the initial privilege enumeration, it turns out that the dbadmin user has the FILE privilege, this means that system files can be read and returned, to do this the load_file function would be used.

UNION SELECT load_file("/etc/passwd")-- -

In the example above, the load_file function is retrieving the contents of the /etc/passwd file.

Writing A File

Along with the FILE privilege, to create and write to a file the user would need to have permission to write to the target destination. This type of vulnerability is often abused to create a web shell to achieve code execution.

MySQL includes a couple of ways to write to a file, the most common of these is INTO OUTFILE or INTO DUMPFILE. It’s important to note, when specifying the output file, the full path would need to be provided.

UNION SELECT "Hello arcan3 has write privileges" INTO OUTFILE "/var/www/html/hello.txt"-- -

Once executed, the query above writes the line “Hello arcan3 has write privileges” to a file called “hello.txt”, this is saved in the /var/www/html directory. However, if the following file cannot be found, it could be that the target location is owned by another user so it cannot be written to.

To verify whether the issue is due to an unwritable location, it could be worth trying another location such as /tmp or /dev/shm as these are usually writable by everyone. It would then be possible to use the load_file function to try and read the created file to test if this was successful.

Final Thoughts

Although SQL injection is typically used for data manipulation, it’s often worth investigating further. Whether it’s extracting user credentials, inserting data or indeed reading the contents of an SSH key. This really does highlight the value of enumeration within any penetration test.

Any application testing and exploitation should only be performed with prior approval from the owner. This information is intended for educational purposes.

Spread the love