sqlmap 项目剖析(III)

 

0x00 TL;DR

sqlmap 使用一种极其巧妙的方式组合生成一个完整的 payload,一个完整的 payload 由如下几个部分组成:

<prefix> <test> <comment> <suffix>

其中 prefix、comment、suffix 作为 boundary,boundary 用于闭合注入点的前后部分;test 则是最终如果闭合成功后必然执行的语句。

' AND EXTRACTVALUE(9559,CONCAT(0x5c,0x716b626b71,(SELECT (ELT(9559=9559,1))),0x717a626b71)) AND 'WBCc'='WBCc 为例,其中 ' 为 prefix、AND 'WBCc'='WBCc 为 suffix,这条语句中不存在 comment,AND EXTRACTVALUE(9559,CONCAT(0x5c,0x716b626b71,(SELECT (ELT(9559=9559,1))),0x717a626b71)) 为 test。

从上面的解析可以发现 prefix 与 suffix 是具有通用性的,与 target 使用哪个数据库或测试时使用哪种 sql 注入方式无关,而 test 是与目标数据库、注入类型强关联的。

因此 sqlmap 将 prefix 与 suffix 单独作为 boundaries 保存,而 test 和 comment 则根据注入方式和数据库的不同被划分为六个文件,对应如下:

 

0x01 test

一个完整的 test 具有的字段如下:

<test>
    <title></title>
    <stype></stype>
    <level></level>
    <risk></risk>
    <clause></clause>
    <where></where>
    <vector></vector>
    <request>
        <payload></payload>
        <comment></comment>
        <char></char>
        <columns></columns>
    </request>
    <response>
        <comparison></comparison>
        <grep></grep>
        <time></time>
        <union></union>
    </response>
    <details>
        <dbms></dbms>
        <dbms_version></dbms_version>
        <os></os>
    </details>
</test>

1.0 title

当前测试的标题,需要能够体现这个测试的注入类型、注入位置等。

1.1 stype

当前测试对应的注入方式,共有五个可选值。

  • 1 – 布尔注入
  • 2 – 报错注入
  • 3 – 内联注入
  • 4 – 堆叠注入
  • 5 – 延时注入
  • 6 – 联合注入

1.2 level

当前测试的等级,级别越高发送的请求数越多,共有五个可选值。

  • 1 – 请求量小于100
  • 2 – 请求量在100到200之间
  • 3 – 请求量在300到500之间
  • 4 – 请求量在500到1000之间
  • 5 – 请求量大于1000

1.3 risk

当前测试的威胁级别,级别越高产生的威胁越大,共有三个可选值。

  • 1 – 低级威胁(无威胁)
  • 2 – 中级威胁(使用延时的 payload 会造成数据库性能损失)
  • 3 – 高级威胁(使用带有 OR 的 payload 可能会造成数据库数据损失)

1.4 clause

当前测试的 payload 在哪个字段生效,共有十个可选值。

  • 0 – 总是生效
  • 1 – 仅在 where 和 having 语句中生效
  • 2 – 仅在 group by 语句中生效
  • 3 – 仅在 order by 语句中生效
  • 4 – 仅在 LIMIT 语句中生效
  • 5 – 仅在 OFFSET 语句中生效
  • 6 – 仅在 TOP 语句中生效
  • 7 – 仅在 table 字段上生效
  • 8 – 仅在 column 字段上生效
  • 9 – Pre-WHERE (non-query)

1.5 vector

当前测试的 payload 模板,没有实际作用(?),只是说明 payload 的具体格式。

1.6 request

注入测试时所发送的请求中的具体信息。

1.6.0 payload

填充到 <test> 中的具体 payload,其中具有一些模板值,后续会在发包前进行替换。

1.6.1 comment

填充到 <comment> 中的注释。

1.6.2 char

union注入测试暴力破解列数时所使用的字符。

1.6.3 columns

union 注入测试时对应的列范围。

1.7 response

此字段指定当前 test 根据什么来判定是否注入成功。

1.7.0 comparison

使用相似度比对算法来判定注入是否存在,False Page 会使用 comparison 指定的 payload 进行发包后与 True Page 进行相似度比对从而判定是否存在注入。

1.7.1 grep

使用正则匹配的方式来判定是否注入成功。

1.7.2 time

使用响应延时的方式来判断是否注入成功。

1.7.3 union

在 union 注入时使用 unionTest 函数来判断是否注入成功。

1.8 details

此字段用于指定当前 test 如果注入成功了可以推断出的信息。

1.8.0 dbms

指定可以推断出的数据库名称,即当前注入成功了可以推断出后端使用的是什么数据库。

1.8.1 dbms_version

指定可以推断出的数据库版本,即当前注入成功了可以推断出后端数据库的版本(一个范围而非固定值)。

1.8.2 os

指定可以推断出的操作系统名称,即当前注入成功了可以推断出后端的操作系统名称。

 

0x02 boundary

一个完整的 boundary 具有的结构如下:

<boundary>
    <level></level>
    <clause></clause>
    <where></where>
    <ptype></ptype>
    <prefix></prefix>
    <suffix></suffix>
</boundary>

其 level、clause、where 三个字段与 test 的意义相同,下面不再重复解释。

2.0 ptype

测试参数的类型,共有六个可选值。

  • 1 – 没经过转义的数字(int 型)
  • 2 – 被单引号包裹的字符串
  • 3 – 被单引号和其它符号()、%)包裹的字符串
  • 4 – 被双引号包裹着的字符串
  • 5 – 标识符(比如 table-name、column-name…)

2.1 prefix

填充到 <prefix> 中的具体值,用于闭合前面的语句。

2.2 suffix

填充到 <suffix> 中的具体值,用于闭合后面的语句。

 

0x03 示例解析

上面介绍了 test 与 boundary 的具体结构以及各个字段的具体含义,也了解了在 sqlmap 中是由这两部分组合生成的完整 payload,实际进行注入测试时也是如此,下面笔者通过一个具体的示例演示两者是如何进行组合的。

示例 boundary:

<boundary>
    <level>1</level>
    <clause>1</clause>
    <where>1,2</where>
    <ptype>2</ptype>
    <prefix>'</prefix>
    <suffix> AND '[RANDSTR]'='[RANDSTR]</suffix>
</boundary>

示例 test:

<test>
    <title>AND boolean-based blind - WHERE or HAVING clause</title>
    <stype>1</stype>
    <level>1</level>
    <risk>1</risk>
    <clause>1,8,9</clause>
    <where>1</where>
    <vector>AND [INFERENCE]</vector>
    <request>
        <payload>AND [RANDNUM]=[RANDNUM]</payload>
    </request>
    <response>
        <comparison>AND [RANDNUM]=[RANDNUM1]</comparison>
    </response>
</test>

笔者这里选取的 test 是 boolean-blind 中的,在进行注入测试时会发出两个请求分别对应 True Page 与 False Page。

其中 True Page 所使用的完整 payload 如下:

' AND 1122=1122 AND 'xxx'='xxx

False Page 所使用的完整 payload 如下:

' AND 1122=8923 AND 'xxx'='xxx

从上面这一部分结合 boundary 与 test 即可看出每个部分是由哪个字段进行填充的。

上面这个 payload 可以用于测试单引号包裹的 SQL 注入点,比如:

SELECT * FROM users where username='$_GET["injection"]';

 

0x04 Reference

(完)