0

During manual SQL injection testing I came upon this.

Is there any way to bypass these filters that supposedly prevent a UNION based attack?

<?php
error_reporting(0);
include('db.inc.php');

$id=strtolower($_GET['id']);

$counter = 0;
if(strpos($id,"union")!=false){
    $counter++;
}
if(strpos($id,"select")!=false){
    $counter++;
}

if($counter==2) {
    echo "Go Away Get a Life";
}else{ 
echo "<font color=green size=4>Query Coming is : ".$id."<br/></font>"; 
$query = "SELECT username,password FROM admin WHERE username='".$id."' ORDER BY 1";

$result = mysql_query($query) or die(mysql_error());

while($row = mysql_fetch_array($result)){
    echo "Username : ".$row['username']."<br/>";
    echo "Password : ".$row['password']."<br/>";
}
}
?>

Also, what is the best way to prevent a UNION based SQLi attack?

  • 3
    Presumably id is an integer, so you could probably just cast it. In general, blacklists are doomed to failure, because you can't exhaust all possible inputs - the usual SQL Injection route is to actually add conditions (like = 0 OR 1=1), which would slip right through here. Really, though, you should be using parameterized queries, which should stop it cold. – Clockwork-Muse Aug 28 '14 at 11:19
  • yea ur rite.. there are two things of my concern.. one is there any way we can use union select.. and 2nd thing u answered for integer.. but what for if id is string..? – Rummy Khan Aug 28 '14 at 11:24
  • ... it would depend on things like encoding - historically some attacks have gotten through because they used Unicode encoding that the db helpfully parsed/realized, but that the application didn't bother with. Which is why the recommendation is to use parameterized queries - it doesn't care what the encoding is, it just stores it as a string). Of course, then you have to remove anything like HTML (that's a different attack)... – Clockwork-Muse Aug 28 '14 at 11:30
  • Agree mostly with Clockwork-Muse, bu parameterized queries are just one solution. If you ave to deal with text at all, then checking for most of the SQL keywords is a better approach - but no substitute for proper isolation of data from SQL code. – symcbean Aug 28 '14 at 11:36
  • thanks brother.. let me have a look at unicode attacks.. i never heard of it.. – Rummy Khan Aug 28 '14 at 11:47
3

You can exploit the != comparison of strpos’s return value and false as 0 != false is false:

var_dump(0 != false); // bool(false)

This is due to implicit type conversion to boolean, where 0 is converted to false.

So you only need to ensure one of the strpos returns 0, which means $id has to start with either union or select, for example:

id=union' union select 'foo', 'bar

Since strpos($id,"union") returns 0, strpos($id,"union")!=false is false, $counter gets incremented only once and the query is executed with the injected SQL.

  • im impressed with ur answer @Gumbo.. let me check it.. i understand ur answer fully.. but le me check it.. i love ur concepts.. – Rummy Khan Aug 31 '14 at 18:01
2

Theoretically, I think this can be bypassed using HPP (HTTP Parameter pollution), for example

?id=union select&id=union select ...

counter==2 will be bypassed this way.

One other way I think could be using comments like

un/**/ion+se/**/lect 

One other thing to note that to bypass this, we can proof the counter false using legitimate union select like in HPP or write union select in a way that it doesn't count like in 2nd example. I think the best way to use keyword filters is to use regular expressions.

Also double query injection is not considered.

  • bro.. thanx i was able to see how i can take this union select to my query.. but still query is not executing mean attacker is not successful at all.. – Rummy Khan Aug 28 '14 at 14:15
1

SQL Injection does not require the use of union or select . SQL injection means that the query structure itself has been altered by user input.

How about where $id is ' OR '1'='1?

This will make your query become

SELECT username,password FROM admin WHERE username='' OR '1'='1' ORDER BY 1

which means all records will be returned.

The solution is to use Prepared statements that treat variables as variables instead of part of the query structure.

  • And add casting to the id, as it must by an integer. – ThoriumBR Aug 28 '14 at 13:26
  • 1
    @ThoriumBR: That doesn't matter for the purposes of prepared statements, although it might be a good step in general to validate all parameters. – SilverlightFox Aug 28 '14 at 13:28
  • @Silverlight bro first question is how someone can still bypass these filters mean how can he take union select to my query.. and for 2nd part of the question thanx i will b using prepared statements.. – Rummy Khan Aug 28 '14 at 14:14
  • 3
    @RummyKhan, the point is that using a UNION is not the only (or even the most common) way to use SQL injection. Even if you improved your filter to perfect against the use of UNION, the above query would still work to get all passwords. – Chris Murray Aug 28 '14 at 15:15
  • thanx Chris Murray yea i know methods of SQLinjection.. and im agreed to you completely.. but still thats not the answer of my Question.. – Rummy Khan Aug 28 '14 at 15:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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