标题 | 简介 | 类型 | 公开时间 | ||||||||||
|
|||||||||||||
|
|||||||||||||
详情 | |||||||||||||
[SAFE-ID: JIWO-2024-520] 作者: ecawen 发表于: [2017-09-03]
本文共 [442] 位读者顶过
0x01 前言ThinkPHP框架是当前国内最流行的PHP框架之一,虽然TP3.2.3这个版本和国外的开源框架还是有一定距离,但是人家教程多,用户量多,中文文档写得奇的优点,现在工作的公司用的是thinkphp3.2框架进行开发,TP框架为我们开发者提供了底层的安全过滤功能,所以我在使用TP框架开发的时候并没有很仔细的去想过安全的问题,而最近也是挤出了一点时间,想知道TP框架底层是如何运作的,底层是如何防注入的,看了一下文档,看了一下源码,找了一些资料,整理出了一些TP框架运行的原理。 0x02 简介通读源码的话,当然要从下载源码开始 : ) 下载地址:http://www.thinkphp.cn/down/610.html 技术准备:PHP基础,MySql基础 使用工具:Visutal Studio Code 服务器环境:xampp 推荐使用:phpStudy (推荐使用这个免得为了环境的问题浪费时间) 安装教程什么的话,我就省略了,我们直接进入正题
0x03 思路接下来介绍一下大概的思路(完成),然后介绍框架运行的原理,在然后说一下防注入的方法,最后说说审计Tp的思路与方法 本文相关文件: > 系统公共函数库: \ThinkPHP\Common\functions.php (封装了TP开放给外部的函数) > ThinkPHP Model模型类: ThinkPHP\Library\Think\Model.class.php (TP的数据库架构类,提供curd类库,是一个对外的接口 ) > TP内部curd类: ThinkPHP\Library\Think\Db\Driver.class.php (这个类的函数都被Model类中的curd操作间接的调用) 这里的话要大概说一下Tp在执行数据库操作之前的处理思路。
Ps:这里我们的M(‘goods’) goods是你的数据库表名,我们后面都简称为goods对象,
最终执行的sql语句的话大概是这样: SELECT * FROM `tdb_goods` WHERE goods_name='R510VC 15.6英寸笔记本' limit 1 如果给他赋值了一个操作例如 M('goods')->field('goods_id,goods_name')->where( array('goods_name'=>$goods_name) )->find(); 最终执行的sql语句: SELECT goods_id,goods_name FROM `tdb_goods` WHERE goods_name='R510VC 15.6英寸笔记本' limit 1 Driver.class.php这个类中除了处理curd操作,还处理pdo绑定,这里的pdo绑定并不是我们本文的重点内容所以简单提起他知道有这么一个东西就完了,我们的重点是了解TP的curd操作是如何进行的。 //这里可以开始真真分析了 说明连接的过程执行的操作等 0x04 正文我们一个一个解释来,先按顺序来介绍Model模型类几个重要的成员变量
4.1、where()方法的执行过程
这里的话,有个画红色方框的地方,我们可以通过官方文档来具体了解他的意思
这里可能有一些人看不懂,我简单的讲解一下 where() 方法
注:mysql_escape_string 的作用与addslashes 的作用是差不多的。 具体区别:
> 在magic_quotes_sybase=on时将“ '”转换成“ ' '”[出自:jiwo.org] 4.2 find() 方法的执行过程
这个方法的功能的话就是 获取主键,完善model类的成员变量 options数组 然后实例化db类调用select方法获取数据,然后处理数据完以后返回数据。 4.2.1 Find方法使用的$this->_parseOptions()讲解
这个方法的主要功能就是 获取操作的表名,查看是否有取别名 获取操作的模型,比对当前表的数据库字段是否一致,如有不一致的字段$this->options['strict']设置了时,进行报错处理否则进行删除多余字段的处理。 执行过滤的方法为_parseType ,他的功能是数据类型检测并且进行强制转换 > 强制转换的类型为int,float,bool 三种类型 上图中的_parseType方法
4.2.2 Find方法使用的$this->db->select()方法讲解$this->db是在Driver.class.php 类中的方法,我们跟进去
4.3 parseWhere方法分析我们这里用我们比较重要的parseWhere方法进行分析(为什么要用parseWhere方法进行分析呢?因为这个地方比其他的要复杂的多,其次是因为其他的都是拼接字符串,过滤,然后返回,所有没有什么好讲的)
这里的话图很多,调用的函数也很多,我们简单的来说说他的处理过程
这方法会去判断传进来的变量内容是否是字符串 如果是的话,那么就会直接返回 如果不是字符串而是数组的话,那么就会挨个的解析,并且判断是否是特殊的条件表达式,如果是调用parseThinkWhere 方法此方法主要是解析特殊的条件并且调用
已上条件都不匹配的情况下就认为是普通查询,普通查询都会调用parseWhereItem 方法
进入此方法以后会发现这个方法会根据 $exp 变量的不同拼接不同的sql语句 而在这个方法中看到最多的就是parseValue方法了
这个方法有会去调用escapeString方法 escapeString方法里面写的就是将传进来的变量进行addslashes 然后返回 嗯。。。。。。。整体流程看起来我们可以发现TP使用的过滤方法就是一个简单addslashes 来防止过滤,不得不说虽然简单但是还挺有效的。 一套流程走下来,好像并没有发现什么问题呢,该过滤的都过滤了,嗯。。。。那我为什么要写这文章呢?(´°̥̥̥̥̥̥̥̥ω°̥̥̥̥̥̥̥̥`) 0x05 本文重点内容先在放一次图先
前面我说了吧parseWhereItem方法会使用parseValue方法 最终是会调用addslashes函数进行过滤来防止注入,那么假如,有没有使用parseValue方法的变量,并且我们能控制的情况那么是否就可以进行注入了呢? 看到上面我画的三个圈圈了么,这是没有使用parseValue方法过滤的,这一块的作用是什么呢?我来简单的说明一下
这里我们来做个实验,重新修改我们的代码
在试另一个
是不是有点小激动??哦哦哦哦框架sql注入漏洞~~~,emmmmmm,嗯不存在的,来了解一个重要TP重要的安全函数I函数先来了解一下I函数的功能
从这里可以得知I函数是官方强烈推荐的用来代替post get cookie seesion等获取数据的方法,我们这里把原来的代码改回去在测试一下
神奇的I函数
> 路径:ThinkPHP\Common\functions.php
这个函数的主要功能为3个
think_filter函数分析
结合我们前面看的知识,大概就可以清楚这个空格的意思了。 例如:
注意:使用了think_filter函数时in后面是有空格的也就是说返回值是goods_name[0]=in(空格)&goods_name[1]=(true) and (updatexml(1,concat(1,(select user())),1))--&goods_name[2]=exp
也就是说我们传进去的值If( in(空格) == ‘in’ )那么当然是不匹配的也就防止了sql注入的产生 0x06 完经过上面的分析不知道大家是否有学到什么,对于使用TP框架是否熟悉了?已下是不按官方的规范使用的方式。 注入:(已下通通通通通通都是使用者的错误,不管TP的事情,自己看看对比一下自己的网站有没有这样做)
例如:全局搜索order(当我们可以操控order传进去的参数时,也是可以进行注入的,这是因为Tp对order方法只是一个字符串拼接的操作 )
小技巧找储蓄Xss:关于过滤Xss TP做的满好的基本上我们只能通用变量来判断是否可以Xss > 1,I(‘post.xxx’,’’,’’); I(‘get.xxx’,’’,’’); I(‘request.xxxx’,’’,’’) > 2,I(‘post.xxx’,’’,’xxxx’); I(‘get.xxx’,’’,’xxxx’); I(‘request.xxxx’,’’,’xxxx’) 这种情况是可以尝试进行Xss的,第三个参数给设置的情况下(给设置了时请自己查看调用的函数是用来干嘛的才进行Xss),或是为空的情况下(为空的情况下就可以直接进行Xss) > 3, $_GET[‘xxx’] $_POST[‘XX’] $_REQUEST[‘XXX’] 当你看到 这样的变量给带入add方法或是save方法也是可以进行Xss的 小技巧查看是否可以直接Getshell查看是否设置了DATA_CACHE_KEY(有设置的情况下,这个技巧请无视)
语句: %0D%0A%24a%3Deval(%24_POST%5B%27a3%27%5D)%3B%23 这里小技巧的话设置了DATA_CACHE_KEY 也是无用的不影响。
2.1 对方这样使用I函数 > I(‘post.xxx’,’’,’’); I(‘get.xxx’,’’,’’); I(‘request.xxxx’,’’,’’) 2.2 对方直接使用$_GET[‘xxx’] $_POST[‘XX’] $_REQUEST[‘XXX’] 语句: <?php%0A%0A%24a%3D%24_GET%5B3%5D%3B%2F%2F%0A%24a%3Deval(%24_POST%5B'a3'%5D)%3B?> 为什么需要这样才能利用呢?因为F函数生成的缓存不带 <?php ?> 所以我们需要自己构造 而自己构造的话,经过了I函数‘<’ ‘>’就会给过滤导致无用, 当然F函数我认为可以利用的情况下比S函数要方便很多因为F函数生成的文件名称是不加密的
例子1:
例子2:
注:使用框架请严格准守框架规范,避免一些出现意外的问题。 |