Semi-automatic-mode-sqlmap

First Post:
Last Update:
Word Count: 3.6k
Read Time: 15min

半自动模式 SQLMAP

剽窃一下GoRequest的图

很难想象 已经到了 2024 年了 居然还有中文的 sqlmap 大水文

很难想象有些人的垃圾的程度啊

Basic Intro

SQLMAP 算是开源 Hacktools 的鼻祖了,从 2006 年开始到现在 也走过了 17 年的时间了。

从大牛手中的瑞士军刀,培训班的摆烂神器,再到国内成为盛极一时的脚本小子专属工具。sqlmap 无论如何,都在众多人心中留下了浓墨重彩的一笔。

关于 SQLI 注入部分的内容,可以参考其他文档 例如 https://github.com/Liki4/SQLi

BYD 挖坑不填, 你们快点催更他。

现在由于 ORM 类似技术、数据库注入技术 在开发者群体中广为人知,导致当下 SQLi 注入在很多时候已经相当难在实战中进行挖掘了,但是基本功还是要打扎实。

他可以没有,但是你不能不会。

关于 SQLMAP 使用文档 一类的文章还是很多的,内容呢基本大同小异,差的讲到使用参数就浅尝则止,好的确实不太多见。我这里就不列举了。当然我这里稍微多更新一点别人不会讲但是或许很好用的小技巧。

1. Command Args

Common args

命令行传参 是自定义 sqlmap 的形式之一 。较为常用或者比较有用的一些参数 例如 前缀 --prefix 后缀 --suffix 指定注入点 -p 还有 --hex 强制 sqlmap 使用 hex 技巧注入,可以规避一些小小的场景。

具体的一些小参数可以看看 https://wiki.wgpsec.org/knowledge/tools/sqlmap.html 作为速查手册。

Custom injection point recognization

要是 SQLMAP 不能准确的识别到你需要的注入点, 那么请使用以下的小寄巧。

尤其是面对一些参数传递的阴间情况 尤其是例如混合 json 格式和 x-www-urlencoded 一起传递的时候

action=c&data={"obj":"xxxx","arr":["12","33","44"]} 就会相对比较有效。

你可以尝试在注入点附近插入 * 后 让 sqlmap 去识别这个 * 通配符

CUSTOM_INJECTION_MARK_CHAR = '*' 这个其实也可以自定义 一些类似的其它内置参数 也可以在这里修改

settings File https://github.com/sqlmapproject/sqlmap/blob/7a6abb56d29225b73d333df00ce06012517c5553/lib/core/settings.py

当然这有些时候可能会导致一点 sqlmap 的小问题 LoL

Second Order Injection

SQLMAP 也支持二次注入 他以 –second-url 或者 –second-req 的形式在 sqlmap 参数中体现

可以参考 hacktricks 文章 https://book.hacktricks.xyz/pentesting-web/sql-injection/sqlmap/second-order-injection-sqlmap

Misc

这里小解释一下 level 和 risk 的含义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<level>
From which level check for this test.

Valid values:
1: Always (<100 requests)
2: Try a bit harder (100-200 requests)
3: Good number of requests (200-500 requests)
4: Extensive test (500-1000 requests)
5: You have plenty of time (>1000 requests)

<risk>
Likelihood of a payload to damage the data integrity.

Valid values:
1: Low risk
2: Medium risk
3: High risk

顺便谈谈我比较喜欢的两个参数

一个是 -r 这个参数可以使得我传递一个请求文件,让 sqlmap 处理整个 HTTP 报文进行处理。 --secode-req 同理

同样我也很喜欢 –sql-shell 参数,此参数可以让你发现数据库注入后,自行输入 sql 语句进行注入,就好像你已经获取到了 sql 的 shell 一样在交互式操作

2. Tamper Scripting Or Eval

Tamper

Tamper 脚本用于 sqlmap 处理 payload 语句部分生成的最后一步

在获取完输入的参数之后 sqlmap 会对 其进行导入后 将其塞入 kb.tamperFunctions 如果有多个会进行优先级比较后,重新进行排序每个 function 在数组中的位置

https://github.com/sqlmapproject/sqlmap/blob/7a6abb56d29225b73d333df00ce06012517c5553/lib/core/option.py#L761-L865

tamper 脚本可以自行编写

大概的方式是

必须有 一个长成类似这样的 tamper 函数

1
2
def tamper(payload, **kwargs):
return "string"

可选 的函数或者常量

  1. 依赖

这个函数会被导入时立即执行

通常来说这个小玩意不具有什么现实意义 因为 在 这里之前 import 部分就已经被执行了

1
2
def dependencies():
pass
  1. 优先级
1
2
3
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.HIGHEST

当然你用的时候可能需要 from sqlmap.lib.core.enums import

他们也有官方提供的各种 tamper 像是自动的 base64encode 啊之类的 这些用到了再百度

Eval

reference: https://infosecwriteups.com/the-mystery-of-sqlmaps-eval-f6c7bf43e1f

这是一个存在于 sqlmap 的早期神秘参数,假设你的加密或者处理函数比较简单,在发送请求之前 eval 将会被调用,用于处理你的参数。

你懂的 因为他可以执行代码 所以这个特性本质上也可以用于 lolbins 特权提升。

关于 eval 的小 bug 和作者给出的 PR 可以参看该拉取请求。 https://github.com/sqlmapproject/sqlmap/pull/5013

当然 eval 不只是修改请求之类的那么简单,你可以小小的使用它 开启 python 调试。

sqlmap --eval="import ipdb; ipdb.set_trace()" # ....

但是个人其实不太推荐使用该参数。虽然他也是自定义的一部分

3. Everything need middleware

接下来我们超脱于 sqlmap 之外,以请求返回的视角进行思考。

计算机科学里有一个经典的发言 计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决

默认模式下 SQLMAP 通常以 HTTP 作为请求,并且自动化的针对每个参数进行 SQL 语句的注入测试或者利用。

但是当遇到了诸如以下情况,SQLMAP 总是会相当吃力。

非 HTTP 应用协议

解释:例如非 http 的 gRPC, web socket 等常见应用协议

解决办法:

类似 gRPC 类,假设你完全不会编写代码的方法,可以借用现成的调试工具 如 GRPC-UI 手动发送一次请求后在 devtools 中拿出请求的数据报文 然后交由 sqlmap 针对 grpcui 端进行 sql 注入尝试。

graph LR
    sqlmap ==HTTPRequest==> grpcui-web ==RPCRequest==> Target

诸如 websocket 一类,社区有一些开源的 ws middleware 例如 这个 https://github.com/BKreisel/sqlmap-websocket-proxy

这类方法甚至可以延拓到 QQ Bot Telegram bot

状态维持

例如遇到了需要维护某些请求之间状态,例如保持链接,或者需要同时请求三方站其他内容,甚至是一些特殊的 csrftoken 反爬等

stackoverflow 有一个类似的回答 https://stackoverflow.com/questions/61448896/sqlmap-add-a-dynamic-token-at-each-request

请求变形 请求签名

  1. 做一定的 payload 的替换,尤其是参数级加密解密 二次编码的时候
  2. 另一类需要完全重写请求进行变形 例如请求方式改变 垃圾数据注入 waf 绕过等
  3. 有些服务会要求 请求内部参数,请求头,请求生成时间戳等进行签名 或是 整体加密 例如测试 AWS Aliyun (私有云)服务器的 API 请求,对其中的请求进行 AKSK 的签名

行文至此,这里需要和上面的 tamper 进行区别的一点是 tamper 是针对注入语句整体字符串进行重新处理,而我们的中间件核心是针对传递的整个 HTTP 请求报文进行处理 而接下来 我们需要提到的 Custom Payload 部分 则是针对某些注入技术,例如如何进行语句的构造。

这种的主要思路就是自己编写一个 web 服务 做请求转发,同时对请求内容做修改或者进行签名等,然后返回服务器的返回即可。

4. Custom Payload

之前已经提到了,Custom Payload 部分 则是针对某些注入技术级别的处理,例如如何进行语句的构造等

穿插一个 issue

具体文件为 xxxx.xml 文件 在 xml 目录下 分别对各类数据库进行判断 注入技巧 等

  1. 边界检测 boundaries.xml 检测当前 sql 语句的边界的 payload 即 判断注入点前面是
    ( 还是 " 还是 ' 而具体数字的含义已经写在开头了

  2. 检测报错 error.xml 通过报错输出检测后端数据库类型的正则手段

  3. 各类数据库请求方式 queries.xml 扒拉数据库基本信息的一些请求 包括特权等

banner 文件夹是判断各类中间件和数据库指纹特征的 不是这里的重点

我们重点观察 payloads 文件夹

这里是 payload test 块的基本使用 说明 解释了各个数字的含义 他在 boolean_blind.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
Tag: <test>
SQL injection test definition.

Sub-tag: <title>
Title of the test.

Sub-tag: <stype>
SQL injection family type.

Valid values:
1: Boolean-based blind SQL injection
2: Error-based queries SQL injection
3: Inline queries SQL injection
4: Stacked queries SQL injection
5: Time-based blind SQL injection
6: UNION query SQL injection

Sub-tag: <level>
From which level check for this test.

Valid values:
1: Always (<100 requests)
2: Try a bit harder (100-200 requests)
3: Good number of requests (200-500 requests)
4: Extensive test (500-1000 requests)
5: You have plenty of time (>1000 requests)

Sub-tag: <risk>
Likelihood of a payload to damage the data integrity.

Valid values:
1: Low risk
2: Medium risk
3: High risk

Sub-tag: <clause>
In which clause the payload can work.

NOTE: for instance, there are some payload that do not have to be
tested as soon as it has been identified whether or not the
injection is within a WHERE clause condition.

Valid values:
0: Always
1: WHERE / HAVING
2: GROUP BY
3: ORDER BY
4: LIMIT
5: OFFSET
6: TOP
7: Table name
8: Column name
9: Pre-WHERE (non-query)

A comma separated list of these values is also possible.

Sub-tag: <where>
Where to add our '<prefix> <payload><comment> <suffix>' string.

Valid values:
1: Append the string to the parameter original value
2: Replace the parameter original value with a negative random
integer value and append our string
3: Replace the parameter original value with our string

解释时间:
1. **1: Append the string to the parameter original value**

- 这意味着你需要将测试字符串附加到现有的参数值之后。例如,如果原始参数值是 `123`,并且你的测试字符串是 `XYZ`,那么修改后的参数值将是 `123XYZ`。
2. **2: Replace the parameter original value with a negative random integer value and append our string**

- 这里指的是首先用一个随机的负整数替换原始参数值,然后再附加测试字符串。例如,如果原始参数是 `123`,你选择了 `-456` 作为随机负整数,测试字符串是 `XYZ`,那么最终的参数值将是 `-456XYZ`。
3. **3: Replace the parameter original value with our string**

- 这个选项意味着直接用测试字符串替换原始参数值。继续上面的例子,如果原始参数值是 `123`,测试字符串是 `XYZ`,那么修改后的参数值就仅仅是 `XYZ`。


Sub-tag: <vector>
The payload that will be used to exploit the injection point.

Sub-tag: <request>
What to inject for this test.

Sub-tag: <payload>
The payload to test for.

Sub-tag: <comment>
Comment to append to the payload, before the suffix.

Sub-tag: <char>
Character to use to bruteforce number of columns in UNION
query SQL injection tests.

Sub-tag: <columns>
Range of columns to test for in UNION query SQL injection
tests.

Sub-tag: <response>
How to identify if the injected payload succeeded.

Sub-tag: <comparison>
Perform a request with this string as the payload and compare
the response with the <payload> response. Apply the comparison
algorithm.

NOTE: useful to test for boolean-based blind SQL injections.

tag 用于对比实验

Sub-tag: <grep>
Regular expression to grep for in the response body.

NOTE: useful to test for error-based SQL injection.

Sub-tag: <time>
Time in seconds to wait before the response is returned.

NOTE: useful to test for time-based blind and stacked queries
SQL injections.

Sub-tag: <union>
Calls unionTest() function.

NOTE: useful to test for UNION query (inband) SQL injection.

Sub-tag: <details>
Which details can be infered if the payload succeed.

Sub-tags: <dbms>
What is the database management system (e.g. MySQL).

Sub-tags: <dbms_version>
What is the database management system version (e.g. 5.0.51).

Sub-tags: <os>
What is the database management system underlying operating
system.

一个基本的格式长成 这样
<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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<test>
<title>MySQL RLIKE boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause</title>
<!-- 这里是标题,就是注入技术的名字 -->

<stype>1</stype>
<!-- 这里说明这里是 bool blind 注入 -->

<level>2</level>
<!-- 这里的 level 只有 2,表示在稍微要求增加请求数量的时候使用 -->

<risk>1</risk>
<!-- 这里表示该注入对数据库的危害为 1 比较小 -->

<clause>1,2,3</clause>
<!-- 表示这里存在注入点存在为 WHERE / HAVING GROUP BY ORDER BY 的子句中才有效 -->

<where>1</where>
<!-- 表示直接添加到测试字符串之后 -->

<vector>RLIKE (SELECT (CASE WHEN ([INFERENCE]) THEN [ORIGVALUE] ELSE 0x28 END))</vector>
<!-- 这里是攻击向量 任意语句的利用手段 -->

<request> <!-- 使用的测试 payload -->
<payload>RLIKE (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN [ORIGVALUE] ELSE 0x28 END))</payload>
</request>

<response> <!-- 响应检查 -->
<comparison>RLIKE (SELECT (CASE WHEN ([RANDNUM]=[RANDNUM1]) THEN [ORIGVALUE] ELSE 0x28 END))</comparison>
<!-- 检查 通过打以下 payload 检查返回,并且与打击真实 payload 来做对比标准测试 -->
</response>

<details>
<dbms>MySQL</dbms> <!-- MySQL 类型数据库系统 -->
</details>
</test>

当然,这里也有很多人的研究,例如 Anquanke Bees Blog

Wrapping up

以上,基本从认识 sqlmap 到 sqlmap 自定义的全部过程。从认识 sqlmap 的参数简单说起,到参数构造 tamper WAF 绕过和自定义处理 eval 函数,再到编写中间件对各种不同形式的服务/设施进行请求,最后再深入到 sqlmap 注入技术层次的自定义。一步一步强化在 sql 注入中的自定义能力。