zoukankan      html  css  js  c++  java
  • wordpress插件wpdiscuz任意文件上传漏洞分析

    下载链接

    https://downloads.wordpress.org/plugin/wpdiscuz.7.0.3.zip

    测试

    环境

    • windows phpstudy
    • phpstorm

    解压插件到wp-content/plugins目录下

    登录管理员启用插件,这时文章下面评论区

    上传带GIF头的php文件

    可以看到上传成功,图片地址也在回显中

    http://127.0.0.1/wordpress/wp-content/uploads/2020/08/1-1598075857.9448.php

    分析

    wp-setting.php 将wp_ajax_nopriv_wmuUploadFiles写入了$wp_filter

    foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
       wp_register_plugin_realpath( $plugin );
       include_once $plugin;
       /**
        * Fires once a single activated plugin has loaded.
        *
        * @since 5.1.0
        *
        * @param string $plugin Full path to the plugin's main file.
        */
       do_action( 'plugin_loaded', $plugin );
    }
    

    通过表单action参数插件加载

    $action = ( isset( $_REQUEST['action'] ) ) ? $_REQUEST['action'] : '';
    

    wordpress先加载插件

    入口文件

    上传的关键代码在wp-contentpluginswpdiscuzutilsclass.WpdiscuzHelperUpload.php376行

    public function uploadFiles() {
    ……
    require_once(ABSPATH . "wp-admin/includes/image.php");
    foreach ($files as $file) {
    $error = false;
    $extension = pathinfo($file["name"], PATHINFO_EXTENSION); //$extension="php"
    $mimeType = $this->getMimeType($file, $extension);
    

    检测文件mime类型

    private function getMimeType($file, $extension) {
        $mimeType = "";
        if (function_exists("mime_content_type")) {
            $mimeType = mime_content_type($file["tmp_name"]); //image/gif
        } elseif (function_exists("finfo_open") && function_exists("finfo_file")) {
            $finfo = finfo_open(FILEINFO_MIME_TYPE);
            $mimeType = finfo_file($finfo, $file["tmp_name"]);
        } elseif ($extension) {
            $matches = wp_check_filetype($file["name"], $this->options->content["wmuMimeTypes"]);
            $mimeType = empty($matches["type"]) ? "" : $matches["type"];
        }
        return $mimeType;
    }
    

    继续跟进

    ……
    if ($this->isAllowedFileType($mimeType)) {
        if (empty($extension)) {   //$extension="php" 没进入
            ……
         }
        $file["type"] = $mimeType;
    } else {
        ……
    }
    do_action("wpdiscuz_mu_preupload", $file);  //没什么用
    if (!$error) {
        $attachmentData = $this->uploadSingleFile($file);
    

    isAllowedFileType

    private function isAllowedFileType($mimeType) {
        $isAllowed = false;
        if (!empty($this->options->content["wmuMimeTypes"]) && is_array($this->options->content["wmuMimeTypes"])) {
            $isAllowed = in_array($mimeType, $this->options->content["wmuMimeTypes"]);
        }
        return $isAllowed;
    }
    

    $this->options->content["wmuMimeTypes"] 内容

    在数组内

    $isAllowed=true

    上传操作在

    340行 $attachmentData = $this->uploadSingleFile($file);

    uploadSingleFile

    private function uploadSingleFile($file) {
    $currentTime = WpdiscuzHelper::getMicrotime();
    $attachmentData = [];
    $path = $this->wpUploadsPath . "/";
    $fName = $file["name"];
    $pathInfo = pathinfo($fName);
    $realFileName = $pathInfo["filename"];
    $ext = empty($pathInfo["extension"]) ? "" : strtolower($pathInfo["extension"]);
    $sanitizedName = sanitize_file_name($realFileName); 
    $cleanFileName = $sanitizedName . "-" . $currentTime . "." . $ext;
    $cleanRealFileName = $sanitizedName . "." . $ext;
    $fileName = $path . $cleanFileName;
    if (in_array($ext, ["jpeg", "jpg"])) {
    $this->imageFixOrientation($file["tmp_name"]);
    }
    $success = apply_filters("wpdiscuz_mu_compress_image", false, $file["tmp_name"], $fileName, $q = 60);
    if ($success || @move_uploaded_file($file["tmp_name"], $fileName)) {
    

    到这里已经把文件上传了
    上传文件名为原文件名+时间戳+后缀

    v7.0.5的改进

    isAllowedFileType 对mime的后缀和文件后缀进行比较

    private function isAllowedFileType($mimeType, $extension) {
        $isAllowed = false;
        if (!empty($this->mimeTypes) && is_array($this->mimeTypes)) {
            foreach ($this->mimeTypes as $ext => $mimes) {
                if ($ext === $extension) {
                    if ($isAllowed = in_array($mimeType, explode("|", $mimes))) {
                        break;
                    }
                }
            }
        }
        return $isAllowed;
    }
    

    总结

    整个上传过程只对文件头进行检测,并没有对文件后缀进行检测,导致可以设置一句话木马内容为

    图片文件头+php代码

    ,进行getshell

  • 相关阅读:
    自兴人工智能——字典
    自兴人工智能——字符串
    列表与元组——自兴人工智能
    自兴人工智能——通用序列操作
    自兴人工智能——Python运算符和操作对象
    自兴人工智能------Python语言的变量认识及操作
    使用opencv-python框出人脸
    使用opencv-python录视频
    (自兴人工智能)python字符串
    (自兴人工智能)python元组
  • 原文地址:https://www.cnblogs.com/0daybug/p/13674091.html
Copyright © 2011-2022 走看看