First things first
Are you even allowed and authorized to test and mess around with this? You might need a written proof for your own sake in case it turns bad. Make sure you're not doing this live on some production server, use a test server instead.
Back to the basics
A classic way to demonstrate SQL injections:
$id = isset($_GET['id']) ? $id : -1; // Set default value if id isn't set
$stmt = $db->query('SELECT * FROM articles WHERE id=' . $id);
$results = $stmt->fetchAll();
fancy_display($results);
To get all the rows, we might use 0 OR 1=1
. The final query will look like this SELECT * FROM articles WHERE id=0 OR 1=1
. Since 1=1
is always true it will return all rows from articles.
This is usually not what we want unless we want to stress the server in some way. So we tend to use UNION
to reach other tables: 1 UNION SELECT ALL 1, 2, username, hash from users
.
What about injecting an INSERT after SELECT?
SQL injection is really about modifying the original SQL query in unintended ways. The query needs to be valid to be successful. Following our previous example, you can't just mix an INSERT with a SELECT in one query:
SELECT * FROM articles WHERE id=1 ALSO INSERT INTO articles (title, content) VALUES ("foo", "bar")
Note that ALSO is just an imaginary keyword, well since it's not supported. Another attempt would be to use to separate queries by separating them with ;
:
SELECT * FROM articles WHERE id=1; INSERT INTO articles (title, content) VALUES ("foo", "bar")
Most of the times this won't work. The second query gets ignored, because the underlying code needs to specify it's using "multiple queries" also known as "stacked queries". In PHP for example, one needs to use mysqli::multi_query
instead of mysqli::query
. Most applications use the later equivalant. You might want to read a previous answer of mine.
Injecting an INSERT statement
So the other legit way is to try and find a vulnerable code that uses INSERT
:
// Registration page
// Got credentials via $_POST
$username = 'foo';
$password = 'bar'; // not hashed, so bad
$db->query('INSERT INTO users (username, password, admin) VALUES ("' . $username . '", "' . $password . '", 0)');
The final query will look like:
INSERT INTO users (username, password, admin) VALUES ("foo", "bar", 0)
We change the flow by using a different password: bar", 0), ("haxors_admin", "easy", 1)--
. The final query will look like this:
INSERT INTO users (username, password, admin) VALUES ("foo", "bar", 0), ("haxors_admin", "easy", 1)--", 0)
Everything after --
gets commented and thus effectively ignored. We just added an admin user. Note that this scenario is very simple to demonstrate the attack.
sqlmap joins the fun
sqlmap is an automation tool to find SQL vulnerabilities and exploit them. Apart from data exfiltration, it also has options for OS takeover like --os-shell
or --os-cmd
.
Under the hood, it will check if stacked queries are supported. If it is, it will either use sys_exec
or sys_eval
to execute those commands. If it isn't, it will try to use a web backdoor (for example a php backdoor) to execute those commands. The backdoor is created by injecting INTO OUTFILE
: trick the query to write to a writable folder. Now if MySQL doesn't have the rights to write to that folder, it won't be created. Thus the attack fails. This attack vector is better explained in the sqlmap usage wiki. More on this in Advanced SQL injection to operating system full control (whitepaper).
Conclusion
In your case, stacked queries aren't supported and MySQL doesn't have enough rights. Which explains why the attack failed. Aside from learning purposes, I would advise to not bother further and start fixing vulnerabilities.