Cetus: Dockerデーモンを標的にするクリプトジャックワーム

Cryptomining, as illustrated here, is one of the goals of Cetus, a cryptojacking worm.

This post is also available in: English (英語)

概要

セキュリティ専門家はコンテナ技術黎明期からセキュアでないDockerデーモンを大きな脅威と捉えてきました。パロアルトネットワークス脅威インテリジェンス調査チーム Unit 42でもこれまでに、こうしたコンテナの脅威について「Docker Engineのコンテナで拡散する初めてのクリプトジャック(仮想通貨採掘)ワーム」、「セキュアでないDockerデーモンへの攻撃者の戦術とテクニックが明らかに 地理的分布で日本は全体の3.7%」という2本の記事を公開しています。これにつづいて筆者たちはDockerデーモンのハニーポットを設置した調査を行いました。その目的は、「インターネット上に公開されている平均的Dockerデーモンをとりまく状況がどのようなものか」、「COVID-19に起因するクラウドへの移行が果たして標的型クラウド攻撃の質や量の向上につながったのかどうか」を確認することにありました。

本稿では筆者らが仕掛けたDockerデーモンのハニーポットで発見された「Cetus」というMoneroマイニング用の改良型Dockerクリプトジャックワームについて解説していきます。

パロアルトネットワークスのPrisma Cloudをご利用のお客様は、Prisma Cloud Computeのホストコンプライアンス保護機能を通じて不備のあるDockerデーモン構成の警告・解決策を受け取ることでこの脅威から保護されています。

ハニーポット

本調査の実施にあたり、筆者は分離された制限付きDockerデーモンを設置し、5月のまる一ヶ月のトラフィックをすべてログに記録しました。その間、ボットネットからワームまであらゆるものを配信するさまざまな攻撃を目撃しました。それらの大部分がMonero用クリプトジャッキングを目的としたものでしたが、なかでもとりわけ頻繁に見られた攻撃の1つが筆者らの注意を引きました。そこにはワームを思わせるパターンがあったからです。このワームの場合、他の攻撃とは違って、ハニーポットがセキュアでないさまざまなDockerデーモンインスタンスから攻撃を受けていました。これまでのハニーポット設置時の経験やコンテナセキュリティ関連の研究プロジェクト類に照らしても、セキュアでないDockerデーモンを標的としたワームを目にするのはさほど一般的とはいえません。そこで筆者はこのペイロードを分析し、結果的にこれが新種のDockerワームであるものと判断しました。このマルウェアの各インスタンスはローカルネットワーク内外のDockerデーモンインスタンスを検出して感染しようとします。

Cetusの仕組み

ギリシャ神話にクジラに似たある生き物についての物語があります。この生き物は一見無害そうでいて実はどこへ出没しても大混乱を引き起こす海の怪物です。この生き物の名前をCetus(ケートス)といいます。

今回見つかったマルウェアは、クジラのロゴを使うDockerデーモンを狙っていて、一見なんでもないような正当なバイナリに偽装しようとしています。ここから筆者はこのマルウェアをCetusと名付けることにしました。

CetusはPortainerと呼ばれるDocker環境でよく利用される正当なバイナリを模倣することでその正体を偽装します。Portainerはユーザーインターフェイス(UI)管理ツールで、これを使うと複数のDocker環境を効率よく管理することができます。新しいマシンを引き継ぐさい、Cetusはそのマシンに自分自身をコピーしてXMRigクリプトマイナーのペイロードをデプロイします。Cetusは、このときクリプトマイナーをdocker-cacheというべつの正当そうな名前のバイナリに偽装しますが、こちらはPortainerとちがって実際の正当なバイナリ名ではありません。

The Cetus life cycle starts with two functions: miner_start and scan_start, which follow the flow illustrated here. The final step is to cause the victim to create an Ubuntu container, update repositories, install Masscan and Docker, copy Cetus and XMRig, add persistence through .bash_aliases, and then restart the container and run Cetus.
図 1 Cetusのライフサイクル

感染の仕組みは単純かつ巧妙です。CetusはMasscanを使ってサブネット内にDockerデーモンがないかランダムにスキャンします。Dockerデーモンが見つかると当該デーモンのREST APIにリクエストを送って感染を広げようとします。Cetusはご丁寧にもこれらのリクエストをDockerのコマンドラインインタフェース(CLI)ツールを使ってこしらえています。このときのCetusの攻撃フローを図1に示します。Cetusが実行するコマンドは具体的に次のとおりです。

  • デーモンがエクスプロイト可能でまだ感染していないことを確認します。

  • Docker Hubからubuntu:18.04の新しいコンテナを実行します。

  • パッケージマネージャリストを更新します。

  • MasscanDockerをパッケージマネージャ経由でインストールします。

  • 悪意のあるportainerdocker-cacheバイナリをコンテナにコピーします。

  • Cetusを/root/.bash_aliasesに追加します。これでコンテナが再起動するかrootがbashセッションを開始するつどCetusが実行されるようになります。

  • コンテナを再起動してCetusを実行します。

Cetusのリバースエンジニアリング

Cetusのリバースエンジニアリングは手っ取り早く簡単にできます。デバッグ対策や難読化などの手法は使用されておらず、シンボルまで含まれています。

ただしクリプトマイナー側はそうはいきません。XMRigマイナーはクリプトジャック攻撃に最もよく使用されるクリプトマイナーの1つなので、セキュリティ対策ツールにはウイルスとして扱われます。したがって、セキュリティ対策ツールを出し抜いて攻撃を行うためにXMRigマイナーは高度に難読化されており、リバースエンジニアリング処理も難しくなっています。

さらにこの2月にリリースされたXMRig 5.5.3を使用している点から、本マルウェアが新しいものであると結論付けることができます。 Cetusのアーキテクチャは単純で、miner_startscan_startという2つの関数が含まれています。

"The code pictured here reads as follows: miner_start(); while ( 1 ) { random = rand(); and other lines not reproduced in plaintext here. This code starts Cetus's two main functions."
図 2 Cetusの主な関数

miner_start関数の機能は明快です。/var/log/stmp.logを開き、Cetusのアクションをログに記録し、XMRigクリプトマイナーを実行し、マシンのCPUを使ってMoneroをマイニングします。scan_start関数はそれよりずっと興味深く、コアとなるマルウェアの機能を実行しています。ランダムな16ビットサブネットを選び、Masscanを実行してサブネット内をスキャンし、ポート2375でリッスンしているDockerデーモンを探します。デーモンが見つかるとダウンロード済みDocker CLIツールで感染プロセスを開始します。このマルウェアが興味深いのは、Dockerデーモンに感染するたびにコンテナを別の名前で呼び出す点です。本マルウェアは8つずつ名前が記されたリストを2つ持っており、各リストから1つずつ名前をランダムに名前をピックアップして、その2つの名前をつなげて使っています。

This figure contains examples of the names used by Cetus, including boorish_peristeronic, verdant_quire and limpid_oxter.
図 3 悪意のあるコンテナ名

次にCetusはこの名前を引数としてマイナーを実行します。マイナーは自分自身をこの名前で識別してマイニングプールに参加し、マイニング関連のアクター情報を送信します。これによって攻撃者は各マイナーを分類し、マイニングプールAPI経由でマイナーや攻撃キャンペーンの統計情報を生成することができます。こうした統計やログの仕組みをもたせている点から、本マルウェアのオペレーターはすべてを注意深く監視したがっているものと結論づけることができます。

結論

コンテナを標的とするマルウェアはその秘めた可能性への理解が攻撃者間で進むにつれ複雑化しています。本稿はGraboidに引き続きUnit 42で文書化された2本目のDocker用クリプトジャックワーム解説記事です。

なお筆者らは、Cetusを別のクリプトジャックワームとリンクすることにも成功しました。こちらのクリプトジャックワームはAWSとDockerデーモンを攻撃するもので、Cetusと同じMoneroウォレットアドレスを使用していました。

クラウドに対する攻撃はますます巧妙化してきているというのが今回の調査での筆者らの結論です。

なお、パロアルトネットワークスのPrisma Cloudをご利用のお客様は、Prisma Cloud Computeのホストコンプライアンス保護機能を通じて不備のあるDockerデーモン構成の警告・解決策を受け取ることでこの脅威から保護されています。

This shows an example of a Prisma Cloud host alert, warning of an insufficient Docker daemon configuration – an issue that could make a Docker daemon vulnerable to Cetus.
図 4 Prisma Cloudのホストアラート

IoC

ファイル
ファイル名 SHA256値
docker-cache e03cf2af46ad1fe590e63f0020243c6e8ae94f074e65ace18c6d568283343dac
portainer b49a3f3cb4c70014e2c35c880d47bc475584b87b7dfcfa6d7341d42a16ebe443

表 1 マルウェアのハッシュ値

マイニングに関する情報

マイニング プール

pool.minexmr.com:443

支払い先アドレス

85X7JcgPpwQdZXaK2TKJb8baQAXc3zBsnW7JuY7MLi9VYSamf4bFwa7SEAK9Hgp2P53npV19w1zuaK5bft5m2NN71CmNLoh

コンテナ名
    1. baleful_gormmet
    2. baleful_obelus
    3. baleful_agelast
    4. baleful_amatorculist
    5. baleful_peristeronic
    6. baleful_hirquiticke
    7. baleful_oxter
    8. baleful_quire
    9. boorish_gormmet
    10. boorish_obelus
    11. boorish_agelast
    12. boorish_amatorculist
    13. boorish_peristeronic
    14. boorish_hirquiticke
    15. boorish_oxter
    16. boorish_quire
    17. adroit_gormmet
    18. adroit_obelus
    19. adroit_agelast
    20. adroit_amatorculist
    21. adroit_peristeronic
    22. adroit_hirquiticke
    23. adroit_oxter
    24. adroit_quire
    25. fecund_gormmet
    26. fecund_obelus
    27. fecund_agelast
    28. fecund_amatorculist
    29. fecund_peristeronic
    30. fecund_hirquiticke
    31. fecund_oxter
    32. fecund_quire
    33. limpid_gormmet
    34. limpid_obelus
    35. limpid_agelast
    36. limpid_amatorculist
    37. limpid_peristeronic
    38. limpid_hirquiticke
    39. limpid_oxter
    40. limpid_quire
    41. risible_gormmet
    42. risible_obelus
    43. risible_agelast
    44. risible_amatorculist
    45. risible_peristeronic
    46. risible_hirquiticke
    47. risible_oxter
    48. risible_quire
    49. verdant_gormmet
    50. verdant_obelus
    51. verdant_agelast
    52. verdant_amatorculist
    53. verdant_peristeronic
    54. verdant_hirquiticke
    55. verdant_oxter
    56. verdant_quire
    57. zealous_gormmet
    58. zealous_obelus
    59. zealous_agelast
    60. zealous_amatorculist
    61. zealous_peristeronic
    62. zealous_hirquiticke
    63. zealous_oxter
    64. zealous_quire