8/27 に Netskope Threat Labs が、改ざんした WordPress サイト数百件をマルウェアの配布に使うキャンペーンのレポートを公開しました(EtherHiding in the Browser: ClickFix Chain Ends in Amatera)。訪問者に偽の Google reCAPTCHA を見せて、パスワードを盗むマルウェア Amatera を実行させる、という流れです。僕らは毎日 WordPress まわりの攻撃情報を巡回していて、この件は保守の実務に直結する型だったので、一次レポートと国内の状況を調べました。
先に、確認することだけ置いておきます。
wp-content/mu-plugins/にsite-helper-で始まる見覚えのないプラグインがないか見る- サイト全体で
front-probe.js・nochain-sw.js(sw.js・payload.jsの名でも観測)・nc-dropin.phpをファイル検索する - 見つかったら、ファイル削除で終えずに Service Worker の解除までやる(理由は最後の節で)
入口は mu-plugins に置かれた偽プラグインだった
攻撃者はまず、侵入したサイトの wp-content/mu-plugins/ に site-helper- + 16 進文字列という名前の偽プラグインを置きます。mu-plugins(must-use プラグイン)は WordPress が全リクエストで自動的に読み込む置き場で、有効化の操作が要らず、通常のプラグイン一覧とも別枠に表示されます。管理画面から無効化する操作もありません。だから、プラグイン一覧を眺める普段の点検では引っかからずに動き続けます。
この偽プラグインがページに front-probe.js を差し込み、訪問者のブラウザに nochain-sw.js という名前の Service Worker を登録します。サイト側の仕事はここまでで、以降の動きはサーバーの外で起きます。
本体はサーバーではなく訪問者のブラウザで動く
Service Worker は本来、オフライン対応や表示の高速化のためにブラウザへ常駐させる仕組みで、登録されると、そのサイトへの以降のアクセスすべてに割り込めます。nochain-sw.js はこれを使って、ページの応答から Content-Security-Policy ヘッダーを削除したうえで、自分のスクリプトを差し込んでいました。CSP はまさにこういう注入をブロックするための防御なので、防御を外してから注入する、という順番です。
差し込まれたスクリプトは、攻撃コードをどこかのサーバーからではなく、Base というブロックチェーン上のスマートコントラクトから読み込みます(EtherHiding と呼ばれる手法です)。改ざんサイトに攻撃の本体が置かれないので、サーバー上のファイルスキャンには引っかかりません。加えて、配布先が停止されても攻撃者はチェーン上の値を 1 つ書き換えるだけで復旧できます。実際、レポートの観測期間中にマルウェア配布用のドメインが 1 つ停止されましたが、この方法で差し替えられていました。
このコントラクトは公開されたブロックチェーン上にあるので、履歴は誰でも読めます。8/31 に BaseScan で開いたところ、書き込みは 86 件あり、直近は 8/15 でした。Action 列に並んでいるのは Set Active や Remove Script です。配信するものをオンチェーンで差し替える運用が、そのまま記録に残っていました。

訪問者に見えるのは、本物そっくりの reCAPTCHA です。チェックボックスを押すとクリップボードにコマンドがコピーされ、「Win + R を押して貼り付けて Enter」と指示されます。この貼り付けさせる手口は ClickFix と呼ばれています。実行すると Windows 標準の mshta 経由で多段のローダーが動き、最後にブラウザ保存のパスワードなどを盗む Amatera が実行されます。macOS の訪問者には無害なダミー表示を出す、という作り分けまでありました。
管理者にだけ見えない作りになっていた
この Service Worker は、誰にでも注入するわけではありませんでした。WordPress のログイン Cookie(wordpress_logged_in_)を持つ訪問者、つまりログイン中のユーザーには何もしません。/wp-admin と /wp-login.php へのアクセスも素通しにします。さらに nc_skip=1 という Cookie を持つブラウザもスキップするのですが、これは攻撃者が自分の動作確認用に使うスキップ用 Cookie です。この名前はあとでもう一度出てきます。
つまり、改ざんに一番気づけるはずのサイト管理者には、偽 reCAPTCHA が一度も表示されません。管理者がログインしたままサイトを見回っても普通のサイトのままで、訪問者から「変な画面が出た」と報告を受けて見に行っても再現しない、という状況が作られます。セキュリティプラグインの検査で「異常なし」と出るのも同じ理由で、WordPress 側に残っているのは中継役のファイルだけ、悪性の本体はブラウザとチェーン上にあります。
日本でも 7 月に駆除事例が出ていた
ここまでは海外の話として読んでいたのですが、国内の状況を調べて予想が外れました。日本の駆除業者のワードプレスレスキューが、Netskope のレポート公開より 6 週間前の 7/16 に、実際に対応した復旧事例としてこのマルウェアを記事にしていました(nochain-sw.js / nochain/sw.js とは?)。挙がっているファイル名は nochain/sw.js・nc-dropin.php・sw.js で、nc_skip Cookie と nc: で始まる Local Storage キーにも触れています。そう、先ほどの攻撃者の動作確認用 Cookie と同じ名前です。ファイル名だけでなく攻撃者側の内部的な Cookie 名まで一致しているので、同じものが日本のサイトで動いていたことになります。
規模の方は、Netskope が直接観測したのは数百サイトですが、同じ nochain-sw.js を含む攻撃基盤を追ったイスラエル国家デジタル庁の 8 月のレポートは、約 1 万サイトという桁で報告しています(Malware on the Blockchain)。国内が例外だと考える材料は無い、というのが調べ終えての結論です。
確認は 3 か所、駆除は Service Worker の解除まで
管理しているサイトでの確認は 3 か所です。
| 見る場所 | 探すもの |
|---|---|
wp-content/mu-plugins/ | site-helper- で始まる見覚えのないプラグイン |
| サイト全体のファイル検索 | front-probe.js / nochain-sw.js(sw.js・payload.js の名でも観測)/ nc-dropin.php |
| ブラウザの開発者ツール | Application > Service Workers に、登録した覚えのない Service Worker(シークレットウィンドウなど未ログインの状態で見る) |
1 つ目の mu-plugins は、サーバーにログインできなくても管理画面から確認できます。WordPress はプラグイン一覧に「必須」というタブを出し、mu-plugins に置かれた PHP ファイルをそこに並べます。自動で読み込まれるものは必ずここに出るので、攻撃者が置いたものも隠れません。ただし、レンタルサーバーやプラグインが正規に置いていることもあります。タブがあること自体は問題ではないので、並んでいるものに心当たりがあるかを見ます。

見つかった場合の駆除で、注意が 1 つあります。サーバー側のファイルを全部消しても、感染中にサイトを訪れた人のブラウザには Service Worker が登録されたまま残り、そのブラウザの中では注入が続きます。Netskope も、ファイル削除だけでなく Service Worker の明示的な解除までを駆除の手順として挙げていました。ブラウザは登録済みの Service Worker の更新を定期的に確認しに来るので、同じ URL に「自分を解除する(unregister する)だけの Service Worker」を置いておくと、その後にアクセスした訪問者から順に消えていきます。なお、偽 reCAPTCHA でコマンドを実行してしまった訪問者側は、ブラウザに保存したパスワード類が盗まれた前提での対応になります。
侵入の入口そのものは、脆弱なプラグイン・テーマや盗まれた認証情報と見られています。つまり入口は目新しくなく、更新が止まっているサイトほどこういう配布に使われやすい、といういつもの構図です。mu-plugins の確認は 1 分で終わるので、管理しているサイトが多い方は、今日ざっと見ておくのが無難です。自分のサイトの WordPress や PHP がどのくらい古いままかを知りたい方は、WordPress 年式診断に URL を入れてみてください。


