WordPress Plugin Slider Revolution 3.0.95 任意文件上传漏洞

2015-09-14T00:00:00
ID SSV:89410
Type seebug
Reporter flsf
Modified 2015-09-14T00:00:00

Description

<p>下面是对版本号为3.0.3的分析和测试结果。<br></p><p>任意文件上传漏洞源于该插件自带的 “插件更新”” 功能,在启用该插件的同时会将一系列的action操作都注册到WordPress的ajax请求里。并且插件在接受更新请求后并没有判断用户权限,导致恶意者可利用该点进行攻击。<br></p><p>所涉及文件:/revslider_admin.php<br></p><pre class="lang-php" data-lang="php"> //add common scripts there //self::addAction(self::ACTION_ADMIN_INIT, "onAdminInit");

        //ajax response to save slider options.
        self::addActionAjax("ajax_action", "onAjaxAction");
    }

</pre><p>该插件在启用时,会将 ajax_action 参数与函数 onAjaxAction() 进行绑定,当通过 /wp-admin/admin-ajax.php 向插件传递参数时会调用 onAjaxAction()。</p><p> onAjaxAction() 函数关键部分如下:</p><pre class="lang-php" data-lang="php"> case "update_plugin": self::updatePlugin(self::DEFAULT_VIEW); break; </pre><p>当post参数 $client_action 为 “update_plugin” 时,会调用 updatePlugin() 开始升级插件。</p><p> updatePlugin() 函数位于 /inc_php/framework/base_admin.class.php 中。</p><p>所涉及文件:/inc_php/framework/base_admin.class.php</p><pre class="lang-php" data-lang="php"> protected static function updatePlugin($viewBack = false){ $linkBack = self::getViewUrl($viewBack); $htmlLinkBack = UniteFunctionsRev::getHtmlLink($linkBack, "Go Back");

        $zip = new UniteZipRev();

        try{

            if(function_exists("unzip_file") == false){                 
                if( UniteZipRev::isZipExists() == false)
                    UniteFunctionsRev::throwError("The ZipArchive php extension not exists, can't extract the update file. Please turn it on in php ini.");
            }

            dmp("Update in progress...");

            $arrFiles = UniteFunctionsRev::getVal($_FILES, "update_file");
            if(empty($arrFiles))
                UniteFunctionsRev::throwError("Update file don't found.");

            $filename = UniteFunctionsRev::getVal($arrFiles, "name");

            if(empty($filename))
                UniteFunctionsRev::throwError("Update filename not found.");

</pre><p>简要分析一下文件上传漏洞形成的过程。首先该函数(updatePlugin())获取了post过来的文件的信息:<br></p><pre class="">$arrFiles = UniteFunctionsRev::getVal($_FILES, "update_file"); </pre><p>随后会获取上传文件的文件名,MIME类型(插件将MIME类型的检测代码注释掉了)。<br></p><pre class="lang-php" data-lang="php">
$arrFiles = UniteFunctionsRev::getVal($_FILES, "update_file"); if(empty($arrFiles)) UniteFunctionsRev::throwError("Update file don't found.");

            $filename = UniteFunctionsRev::getVal($arrFiles, "name");

            if(empty($filename))
                UniteFunctionsRev::throwError("Update filename not found.");

            $fileType = UniteFunctionsRev::getVal($arrFiles, "type");

</pre><p>然后获取了上传文件的临时路径和创建了目录 “/temp/update_extract” (目录创建失败会抛出异常并中止处理):<br></p><pre class="lang-php" data-lang="php"> $filepathTemp = UniteFunctionsRev::getVal($arrFiles, "tmp_name"); if(file_exists($filepathTemp) == false) UniteFunctionsRev::throwError("Can't find the uploaded file.");

            //crate temp folder
            UniteFunctionsRev::checkCreateDir(self::$path_temp);

            //create the update folder
            $pathUpdate = self::$path_temp."update_extract/";               
            UniteFunctionsRev::checkCreateDir($pathUpdate);

            //remove all files in the update folder
            if(is_dir($pathUpdate)){ 
                $arrNotDeleted = UniteFunctionsRev::deleteDir($pathUpdate,false);
                if(!empty($arrNotDeleted)){
                    $strNotDeleted = print_r($arrNotDeleted,true);
                    UniteFunctionsRev::throwError("Could not delete those files from the update folder: $strNotDeleted");
                }
            }

</pre><p>如果 “/temp/update_extract” 创建成功,会清理该目录下的所有文件,然后将上传的文件移动至该目录下:<br></p><pre class="lang-php" data-lang="php"> //copy the zip file. $filepathZip = $pathUpdate.$filename;

            $success = move_uploaded_file($filepathTemp, $filepathZip);
            if($success == false)
                UniteFunctionsRev::throwError("Can't move the uploaded file here: {$filepathZip}.");

            if(function_exists("unzip_file") == true){
                WP_Filesystem();
                $response = unzip_file($filepathZip, $pathUpdate);
            }

</pre><p>这里很明显,没有对上传文件做限制,直接使用 move_uploaded_file() 将上传文件(任意)拷贝到了 “/temp/update_extract/” 目录下,后续的处理都不用再分析。<br></p>