0
<?php
/*
CREATE TABLE `message` (
`remote_addr` TEXT NOT NULL ,
`user_agent` TEXT NOT NULL ,
`name` TEXT NOT NULL ,
`text` TEXT NOT NULL
) ENGINE = MYISAM ;
INSERT INTO `message` (`remote_addr`, `user_agent`, `name`, `text`) VALUES('127.0.0.0', 'Fire Walk With Me', 'test name',
'test text');
INSERT INTO `message` (`remote_addr`, `user_agent`, `name`, `text`) VALUES('127.0.0.0', 'Abandon all hope, ye who enter
here', 'test name2', 'test text2');
*/
$link = mysql_connect("localhost", "root", "");
mysql_select_db("positive", $link);
$ip = $_SERVER["REMOTE_ADDR"];
if(isset($_SERVER["HTTP_X_REAL_IP"])) {
$ip = $_SERVER["HTTP_X_REAL_IP"];
}
$ip = addslashes($ip);
$user_agent = addslashes($_SERVER["HTTP_USER_AGENT"]);
$ip = substr($ip, 0, 15); // max length 15
if(isset($_POST["name"]) && isset($_POST["text"])) {
$text = addslashes($_POST["text"]);
$name = addslashes($_POST["name"]);
$query = mysql_query("INSERT INTO `message` (`remote_addr`, `user_agent`, `name`, `text`) VALUES('{$ip}',
'{$user_agent}', '{$name}', '{$text}');", $link);
}
$query = mysql_query("SELECT * FROM `message`;", $link);
echo("<table>");
while($row = mysql_fetch_assoc($query)) {
echo("<tr><td>{$row["name"]}</td><td>{$row["text"]}</td></tr>");
}
echo("</table>");
?>

I'm trying to find SQL Injection in this code. I tried different methods but I didn't succeed. The clue is "Try to find logical errors in this example of code". I know that there is a possibility that DB has GBK (or something else) encoding and we can use multibyte character to broke the statement. But it is not appropriate in this case.

I don't understand why do we do addslashes on $ip. It seems unnecessary. Maybe it is a clue.

closed as off-topic by Steffen Ullrich, A. Hersean, LvB, Tom K., Xander May 13 at 17:44

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions asking us to break the security of a specific system for you are off-topic unless they demonstrate an understanding of the concepts involved and clearly identify a specific problem." – Steffen Ullrich, A. Hersean, LvB, Tom K., Xander
If this question can be reworded to fit the rules in the help center, please edit the question.

1

h/t to @Peter for helping iron out the details

The trick is that add_slashes is applied to the IP address and then it is truncated to 15 characters. Imagine injecting this into $_SERVER["REMOTE_ADDR"] or $_SERVER['HTTP_X_REAL_IP'] (the 15th character is a single quote):

12345678901234'

add_slashes turns it into this:

12345678901234\'

Which is truncated to this:

12345678901234\

Aka, now you have a lone trailing slash that will escape the single quote that was supposed to end the value for the IP address in the query. You have now modified the query itself. The opening quote of the user agent value now closes the IP address value, and anything in your user agent is inserted into the query directly without being inside any quotes. You'll just have to make sure you build a valid query when you are done. Injecting data into $_SERVER['REMOTE_ADDR'] is difficult because, although you can spoof it on the TCP request, this will break the handshake and the HTTP request will never happen. However, setting $_SERVER['HTTP_X_REAL_IP'] is as simple as setting a header on the request. So something along these lines would work (this is a hastily thrown together example without testing):

curl 'https://target.com' \
    -H "X-REAL-IP: 12345678901234'" \
    --user-agent '1,1,1); INSERT INTO message (name) SELECT 
 CONCAT(Host,User,authentication_string) from mysql.user; --'

Note that this particular example is only possible because of the use of the old mysql_query bindings. The mysqli library explicitly disallows having more than one query in each execute statement.

  • How would you set REMOTE_ADDR to an arbitrary string by spoofing an IP address? Presumably it's treated as a 32 bit number that is formatted as a dotted decimal by the PHP runtime. I can see this working if IPv6 is enabled, but not with IPv4, where you only have a 32 bit number to play with. – Peter May 4 at 7:11
  • @Peter I know that you can spoof the IP at the TCP level. I am making an assumption about being able to add arbitrary strings into it. I suspect it is possible. I could be wrong. However, that is the only clear logic error here (at least that I see), and the only other option would be encoding mangling which the OP has already said is not the answer. Therefore, either arbitrary string injection is possible, or this question is badly written. I'll do some digging later when I have time! – Conor Mancone May 4 at 11:12
  • @Peter I've updated my answer. After some more digging I've realized that injecting data directly into $_SERVER['REMOTE_ADDR'] isn't anywhere near simple. My suspicion is that this was the intended vulnerability, but whoever wrote this example forgot that the IP address is the only part of the request that is actually hard (although not impossible) to spoof. – Conor Mancone May 4 at 12:19
  • I think its more likely that the intended solution is about the X-Real-IP header (which is trivial to manipulate), although that assumes a misconfiguration (or absence) of a proxy server. In that case you are right on the money when noting that the substr call undermines the addslashes call, if course. – Peter May 4 at 12:45
  • I'm less familiar with $_SERVER['HTTP_X_REAL_IP']. It isn't available on my test server, and some quick googling didn't show much about spoofing it. I may do some more digging and add some notes about it. – Conor Mancone May 4 at 13:34
-2

Both the remote_addr and user_agent fields are getting sent to the SQL engine without being parsed. Try inserting your SQL queries in the User-Agent field as a GET or POST parameter.

/endpoint?HTTP_USER_AGENT='
/endpoint?HTTP_X_REAL_IP='

The following code asks the server if the _SERVER element is set.

if(isset($_SERVER["HTTP_X_REAL_IP"])) {
    $ip = $_SERVER["HTTP_X_REAL_IP"];
}

This is the vulnerable code that triggers the SQL query and thus the injection:

$query = mysql_query("INSERT INTO `message` (`remote_addr`, `user_agent`, `name`, `text`) VALUES('{$ip}',
'{$user_agent}', '{$name}', '{$text}');", $link);
}

That can mean a GET, POST, or COOKIE parameter. Setting this parameter: HTTP_X_REAL_IP in your http request to ', as I mentioned above, will trigger the SQL errors. Why don't you try it?

  • The use of add_slashes would prevent simple attacks like that, and setting a GET/POST parameter wouldn't be reflected in the user agent anyway. – Conor Mancone May 4 at 3:24
  • As you can see, HTTP_X_REAL_IP isn't being passed through add_slashes. Please change your vote as my answer is correct, I just tested it. – leaustinwile May 4 at 8:21
  • 2
    The $ip variable is passed through add_slashes after the HTTP_X_REAL_IP is copied into it. Also, that is a parameter from the$SERVER array. It is populated from the HTTP request headers, not the GET/POST data. Sorry. This just won't work. – Conor Mancone May 4 at 10:56

Not the answer you're looking for? Browse other questions tagged or ask your own question.