代码审计 | ThinkPHP3.2.x框架SQL注⼊
Posted 王少杰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了代码审计 | ThinkPHP3.2.x框架SQL注⼊相关的知识,希望对你有一定的参考价值。
七月流火:Thinkphp是一个快速、简单的基于MVC和面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,尤其注重开发体验和易用性,并且拥有众多的原创功能和特性,为WEB应用开发提供了强有力的支持。3.2版本则在原来的基础上进行一些架构的调整,引入了命名空间支持和模块化的完善,为大型应用和模块化开发提供了更多的便利。
漏洞简述
尽管ThinkPHP 3.2.x使用了 I 方法来过滤参数,但是还是过滤不严谨,导致SQL注入发生。
ThinkPHP基础知识
在进行漏洞分析之前,我们需要了解一下ThinkPHP3.2基础知识,这里仅介绍对本次漏洞分析有帮助的部分。
ThinkPHP3.2的 目录结构
(可以部署在非web目录下面)
├─ThinkPHP 框架系统目录
│ ├─Common 核心公共函数目录
│ ├─Conf 核心配置目录
│ ├─Lang 核心语言包目录
│ ├─Library 框架类库目录
│ │ ├─Think 核心Think类库包目录
│ │ ├─Behavior 行为类库目录
│ │ ├─Org Org类库包目录
│ │ ├─Vendor 第三方类库目录
│ │ ├─ ... 更多类库目录
│ ├─Mode 框架应用模式目录
│ ├─Tpl 系统模板目录
│ ├─LICENSE.txt 框架授权协议文件
│ ├─logo.png 框架LOGO文件
│ ├─README.txt 框架README文件
│ └─ThinkPHP.php 框架入口文件
我们本次的 payload 为:http://localhost/thinkphp32/index.php?username[0]=bind&username[1]=0 and updatexml(1,concat(0x7,user(),0x7e),1)
环境搭建
我们先安装好phpstudy,然后将下载好的ThinkPHP3.2.3完整版解压,将里面的thinkphp拷贝至phpstudy的网站根目录下的thinkphp32文件夹下,php版本这里用5.6。在thinkphp32目录下新建一个index.php文件,内容如下:
<?phpdefine("APP_PATH","./Application/");define('APP_DEBUG',True);include "ThinkPHP/ThinkPHP.php";
浏览器访问http://localhost/thinkphp32/index.php
,会在thinkphp32目录下生成一个Application文件夹,目录结构如下:
Application
├─Common 应用公共模块
│ ├─Common 应用公共函数目录
│ └─Conf 应用公共配置文件目录
├─Home 默认生成的Home模块
│ ├─Conf 模块配置文件目录
│ ├─Common 模块函数公共目录
│ ├─Controller 模块控制器目录
│ ├─Model 模块模型目录
│ └─View 模块视图文件目录
├─Runtime 运行时目录
│ ├─Cache 模版缓存目录
│ ├─Data 数据目录
│ ├─Logs 日志目录
│ └─Temp 缓存目录
修改 thinkphp32ApplicationHomeControllerIndexController.class.php 文件代码,内容如下:
<?phpnamespace HomeController;use ThinkController;class IndexController extends Controller {
public function index(){
$condition["name"] = I("name");
$data["pass"] = "1998";
$result = M("users")->where($condition)->save($data);
}}
配置连接数据库的文件 ApplicationCommonConfconfig.php ,内容如下:
<?phpreturn array(
'DB_TYPE' => 'mysql', // 数据库类型
'DB_HOST' => 'localhost', // 服务器地址
'DB_NAME' => 'thinkphp', // 数据库名
'DB_USER' => 'root', // 用户名
'DB_PWD' => 'root', // 密码
'DB_PORT' => 3306, // 端口
'DB_PREFIX' => '', // 数据库表前缀
'DB_CHARSET'=> 'utf8', // 字符集
'DB_DEBUG' => TRUE, // 数据库调试模式 开启后可以记录SQL日志 3.2.3新增);
漏洞分析
这次,我们还是根据payload,使用正向审计的方式来进行本次审计工作。首先我们来看一下我们创建的 thinkphp32ApplicationHomeControllerIndexController.class.php 文件代码,程序使用 I 方法来安全获取 username 变量,如下图:
我们跟进 I 方法看看, I 方法位于 thinkphp32ThinkPHPCommonfunctions.php 文件中,可以看到 $input 变量的值等于超全局数据 $_GET 的值。如下图:
接着主要是对获取到的变量,使用 htmlspecialchars() 进行过滤,如下图:
可以看到函数尾部使用了thinkphp自定义的过滤该方法 think_filter ,如下图:
该方法也在这个文件中定义,代码如下。可以清楚的看到并没有过滤 bind ,如下图:
function think_filter(&$value){
// TODO 其他安全过滤
// 过滤查询特殊字符
if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){
$value .= ' ';
}}
再回到 thinkphp32ApplicationHomeControllerIndexController.class.php 文件,看语句 $result = M("users")->where($condition)->save($data);
我们跟进 M 方法, M 方法的话就是新建了一个 ThinkModel 类,如下图:
之后调用了 ThinkModel 类的 where 方法,该方法位于 thinkphp32ThinkPHPLibraryThinkModel.class.php 文件中,这里实际上就是做了添加 $options['where'] 的操作,如下图:
我们继续看 save 方法,在程序末尾有个 update 操作,继续跟进
update 方法位于 thinkphp32ThinkPHPLibraryThinkDbDriver.class.php 文件中, parseSet 方法主要做了set[0] =
password=:0
,我们主要关注 parseWhere 方法。
我们跟进 parseWhere 方法,发现其中拼接了经过 parseWhereItem 方法处理的语句,如下图:
我们跟进 parseWhereItem 方法,会发现当 $val[0] 等于 bind 的时候,直接将参数进行拼接,如下图:
最终,执行攻击者构造的 SQL 语句,效果如下:
总结
笔者也是第一次审计Thinkphp3.2框架,在审计这套框架前还找了网络上的视频快速入门了下,再结合Thinkphp3.2手册,完成此次漏洞的审计。当然,文章有不当之处,还希望大家斧正。
关注我老板家公司
安全龙,专注做企业网络安全服务与网络安全技术培训!网址www.anquanlong.com
以上是关于代码审计 | ThinkPHP3.2.x框架SQL注⼊的主要内容,如果未能解决你的问题,请参考以下文章