<p>所涉及文件:/inc_php/framework/base_admin.class.php</p><pre class="lang-php" data-lang="php"> //if not inside plugin don't continue
if($this->isInsidePlugin() == true){
self::addAction(self::ACTION_ADD_SCRIPTS, "addCommonScripts");
self::addAction(self::ACTION_ADD_SCRIPTS, "onAddScripts");
}
//a must event for any admin. call onActivate function.
$this->addEvent_onActivate();
self::addActionAjax("show_image", "onShowImage");
}
</pre><p>插件在启用时将ajax中的show_image请求绑定处理函数onShowImage()。其中onShowImage() 函数原型位于 “/inc_php/framework/base.class.php” 中。<br></p><p>所涉及文件:/inc_php/framework/base.class.php<br></p><pre class="lang-php" data-lang="php"> /**
*
* on show image ajax event. outputs image with parameters
*/
public static function onShowImage(){
$pathImages = UniteFunctionsWPRev::getPathContent();
$urlImages = UniteFunctionsWPRev::getUrlContent();
try{
$imageView = new UniteImageViewRev(self::$path_cache,$pathImages,$urlImages);
$imageView->showImageFromGet();
}catch (Exception $e){
header("status: 500");
echo $e->getMessage();
exit();
}
}
</pre><p>可以看到在onShowImage() 函数中,实例化了 UniteImageViewRev 类,并调用了该类的 showImageFromGet() 方法。</p><p> 所涉及文件:/inc_php/framework/image_view.class.php</p><pre class="lang-php" data-lang="php"> /**
*
* show image from get params
*/
public function showImageFromGet(){
$imageFilename = UniteFunctionsRev::getGetVar("img");
$maxWidth = UniteFunctionsRev::getGetVar("w",-1);
$maxHeight = UniteFunctionsRev::getGetVar("h",-1);
$type = UniteFunctionsRev::getGetVar("t","");
//set effect
$effect = UniteFunctionsRev::getGetVar("e");
$effectArgument1 = UniteFunctionsRev::getGetVar("ea1");
if(!empty($effect))
$this->setEffect($effect,$effectArgument1);
$this->showImage($imageFilename,$maxWidth,$maxHeight,$type);
}
</pre><p>showImageFromGet() 函数从 “GET” 请求里获取参数 “img” 的值赋值给变量。<br></p><pre class="">$imageFilename = UniteFunctionsRev::getGetVar("img");
</pre><p>然后注意 $effect 这个变量:<br></p><pre class="">$effect = UniteFunctionsRev::getGetVar("e");
</pre><p>在函数最后调用 showImage() 方法,showImage() 函数部分关键代码如下:<br></p><pre class="lang-php" data-lang="php"> $filepath = $this->pathImages.$filename;
if(!is_file($filepath)) $this->outputEmptyImageCode();
//if gd library doesn't exists - output normal image without resizing.
if(function_exists("gd_info") == false)
$this->throwError("php must support GD Library");
//check conditions for output original image
if(empty($this->effect)){
if((is_numeric($maxWidth) == false || is_numeric($maxHeight) == false)) outputImage($filepath);
if($maxWidth == -1 && $maxHeight == -1)
$this->outputImage($filepath);
}
</pre><p>其中 $this->pathImage 的值在一开始的时候被赋值为了WordPress “wp-content” 所在的物理路径(例如:C:\xxxx\www\wordpress\wp-content\),然后通过将 $this->pathImage 与传进来的文件名 $filename进行连接赋值给 $filepath:<br></p><pre class="">$filepath = $this->pathImages.$filename;
</pre><p>并且 $this->effect,$maxWidth和$maxHeight都可以从 “GET” 请求参数中获取,所以可以构造一定的payload,使得函数流程执行到 $this->outputImage($filepath) 来读取文件。outputImage() 函数如下:<br></p><pre class="lang-php" data-lang="php"> //------------------------------------------------------------------------------------------
// outputs image and exit.
private function outputImage($filepath){
$info = UniteFunctionsRev::getPathInfo($filepath);
$ext = $info["extension"];
$filetime = filemtime($filepath);
$ext = strtolower($ext);
if($ext == "jpg")
$ext = "jpeg";
$numExpires = 31536000; //one year
$strExpires = @date('D, d M Y H:i:s',time()+$numExpires);
$strModified = @date('D, d M Y H:i:s',$filetime);
$contents = file_get_contents($filepath);
$filesize = strlen($contents);
header("Last-Modified: $strModified GMT");
header("Expires: $strExpires GMT");
header("Cache-Control: public");
header("Content-Type: image/$ext");
header("Content-Length: $filesize");
echo $contents;
exit();
}
</pre><p>outputImage() 函数直接通过两个操作就将文件内容输出:<br></p><pre class="">$contents = file_get_contents($filepath);
echo $contents;
</pre><p>整个过程中没有任何过滤,导致可控下载文件路径,造成任意文件下载。</p>
全部评论 (5)