IoTマルウェアMiraiの設定情報抽出ツール「mirai-toushi」の公開
2025年03月28日 金曜日

CONTENTS
はじめに
2024年から2025年の年末年始にかけて、様々な企業に対するDDoS攻撃が発生し、サービス障害が相次ぎました。
DDoS攻撃の原因として、IoTマルウェアに感染したIoT機器(ルータ、DVR、IPカメラなど)が関与しており、これらの感染したIoT機器がC2サーバから指令を受けてDDoS攻撃を実行しています。
2016年にソースコードが流出したIoTマルウェア Mirai とその亜種が、2025年現在でも攻撃によく使われています。
攻撃者はオリジナルのソースコードをそのまま攻撃に使っているわけではなく、C2サーバなどの情報が格納された設定情報を編集した上で、攻撃に使うマルウェアをクロスコンパイルします。
このため、Miraiのマルウェア解析では、オリジナルのソースコードからの変更点がある設定情報を抽出し、そのマルウェアの特徴を把握することが重要です。
マルウェアごとに手動で設定情報の抽出を行うと時間が膨大にかかってしまうため、ツールで抽出を自動化する必要があります。
既存のツールでもMiraiの設定情報を抽出するものは存在しますが、対応アーキテクチャ数が少ないなどの課題があったため、独自にMiraiの設定情報抽出ツール「mirai-toushi」を開発し、GitHubに公開しました。
-
- mirai-toushi: https://github.com/iij/mirai-toushi
本記事では、mirai-toushiの機能と実行方法について説明します。
* mirai-toushiの名前の由来については、マルウェア「Mirai」が日本語に由来する単語だったため、ツール名にも日本語をつけたいと思い、後半に「toushi」(透視、投資)をつけています。
2025年3月に発行されたIIJの季刊技術レポート「IIR vol.66」では、Miraiの設定情報の構造やmirai-toushiの一部の実装について説明しているので、併せてご覧ください。
また、mirai-toushiに関する内容は2025年5月開催のセキュリティカンファレンス「Botconf 2025」に採択され、発表資料や論文が後日公開される予定です。
-
- タイトル「mirai-toushi: Cross-Architecture Mirai Configuration Extractor Utilizing Standalone Ghidra Script」
mirai-toushiの機能
mirai-toushiは、OSSのリバースエンジニアリングツール Ghidra の自動化機能Ghidra Script(Python)で実装しています。
アーキテクチャに依存しないデコンパイラや中間表現のP-Codeを活用することで、8種類のアーキテクチャのマルウェアで実行できるようになっています。
-
- ARM
- MC68000
- MIPS
- PowerPC
- SPARC
- SuperH4
- x86
- x86_64
mirai-toushiには3種類の機能があり、それぞれの機能で抽出できる情報について以降で説明します。
-
- xor_scanner.py: パスワードリストの抽出
- xor_table.py: テーブルの抽出
- parse_main.py: resolve_cnc_addr()に平文で書かれているC2を抽出、DoS攻撃の関数情報を抽出
1. xor_scanner.py
xor_scanner.pyでは、1バイトXORで暗号化されたパスワードリストを抽出できます。
パスワードリストは、Miraiが行う感染活動(Telnetスキャン)に使われ、ユーザ名・パスワードだけでなく、ランダム選択の重み付き確率に使われる重みの値も抽出できます。
この値が大きいほど、そのパスワードリストが選択される確率が高くなることを意味します。
{ "add_auth_entry_func": { "name": "add_auth_entry", "entrypoint": "0804f8d0", "scanner_key": "0x22" # パスワードリストのXORキー }, "scanner_init_func": { "name": "scanner_init", "entrypoint": "0804fa20", "auth_tables_sha256": "0e60e37e94...", # パスワードリスト全体のSHA256 "auth_tables_count": 23, # パスワードリストの数 "auth_tables": [ { "user": "root", # ユーザ名 "pass": "admin", # パスワード "weight": 8 # 重み }, { "user": "admin", "pass": "admin", "weight": 7 },
2. xor_table.py
xor_table.pyでは、1バイトXORで暗号化されたテーブルを抽出できます。
テーブルは様々な用途で使われ、オリジナルのMiraiのテーブルには以下の設定情報が含まれています。
-
- C2サーバのドメインとポート番号
- Scan Receiverのドメインとポート番号
- 標準出力に出力される文字列
- 敵対マルウェアのプロセスをキルするためのシグネチャ
- Telnetスキャンのログイン成功後に実行するコマンド
- DoS攻撃に使われるパラメータ
このようにテーブルは様々な用途で使われるため、xor_table.pyではテーブルの呼び出し元関数・アドレスの情報も付与しています。
これによってシンボル情報が削除されていない検体で、関数名からテーブルの用途を推測できるようになります。
* シンボル情報が削除されている検体では元の関数名を復元できないため、追加で解析を行い用途を特定する必要があります。
{ "table_lock_val_func": { "name": "table_lock_val", "entrypoint": "08050f80", "table_key": "0x22", # テーブルのXORキー(1バイト) "table_original_key": "0xdeadbeef" # 元のテーブルのXORキー(4バイト) }, "table_init_func": { "name": "table_init", "entrypoint": "08051080", "tables_sha256": "5c4a784a20...", # テーブル全体のSHA256 "tables_count": 50, # テーブルの数 "tables_int_count": 2, # 数値型テーブルの数 "tables_str_count": 48, # 文字列型テーブルの数 "tables": [ { "id": 3, # テーブルのID "type": "str", # テーブルの型 "str_data": "example.com", # テーブルのデータ "table_addr": "080565d8", # テーブルのアドレス "refs": [ { "func": "resolve_cnc_addr", # テーブルの呼び出し元関数 "addr": "0804e552" # テーブルの呼び出し元アドレス } ] }, { "id": 4, "type": "int", "int_data": 23, "table_addr": "080565e0", "refs": [ { "func": "resolve_cnc_addr", "addr": "0804e5a9" } ] },
3. parse_main.py
一部のMirai亜種では、C2のドメインやIPアドレスがテーブルではなく、resolve_cnc_addr()に平文で書かれます。
このため、parse_main.pyではresolve_cnc_addr()に平文で書かれるC2を抽出できるようにしました。
これに加えて、Miraiではマルウェアごとに実装されているDoS攻撃の関数が異なり、これもマルウェアを特徴づける情報であるため、parse_main.pyではDoS攻撃の関数情報も抽出するようにしています。
{ "main_func": { "name": "main", "entrypoint": "0804df60" }, "resolve_cnc_addr_func": { "name": "resolve_cnc_addr", "entrypoint": "0804dc40", "cnc": "192.0.2.1" # C2サーバのドメイン/IPアドレス }, "attack_init_func": { "name": "attack_init", "entrypoint": "0804a630", "attacks_count": 5, # DoS攻撃関数の数 "attacks": [ { "vector": 0, # DoS攻撃関数の識別子 "name": "attack_tcp_syn", # DoS攻撃関数 "entrypoint": "0804b530" # DoS攻撃関数のエントリーポイント }, { "vector": 1, "name": "attack_tcp_ack", "entrypoint": "0804af90" },
mirai-toushiの実行方法
mirai-toushiはGhidraがインストールされている環境で、追加設定や追加ライブラリなしで実行できます。
Ghidraのインストール方法については、Ghidraの Installation Guide をご確認ください。
実行方法は、GhidraのGUIから実行するJython interpreterとCUIから実行するHeadless analyzerに対応しており、以降でそれぞれについて説明します。
Jython interpreter
Ghidraを起動し、プロジェクトを作成していない場合は、 [File] -> [New Project…] からプロジェクトを作成します。
作成したプロジェクトに解析対象のマルウェアをドラッグアンドドロップして、マルウェアをインポートします。
インポートしたマルウェアをダブルクリックすると、CodeBrowserが起動します。
最初に表示されるAnalyzeのポップアップで [Yes] をクリックして、Ghidraの初期解析を開始させます。
このとき、解析のオプション(Analysis Options)はデフォルトのままで大丈夫です。
初期解析が完了した後(画面右下に表示されるステータスバーが消えた後)、画面上の [Window] -> [Jython] (Ghidra 11.2より前のバージョンでは [Python])からJython interpreterを起動します。
起動したJython interpreterで、mirai-toushiの Ghidra Script の内容をコピペすることで、mirai-toushiの解析が実行され、結果がJSON形式で出力されます。
* Jython interpreter以外でGUIから実行する方法として、[Window] -> [Script Manager] から実行することもできます。この場合、事前にmirai-toushiのGhidra Scriptを既定のghidra_scriptsフォルダ内に配置しておく必要があります。
Headless analyzer
CUIから実行する場合は、はじめにgit cloneなどでmirai-toushiのリポジトリをダウンロードします。
$ git clone https://github.com/iij/mirai-toushi $ cd mirai-toushi/
runner.shに実行権限を付与し、Ghidraのインストールディレクトリと解析対象のファイルを指定することでmirai-toushiを実行できます。
マルウェア解析に用いられるLinuxディストリビューションREMnuxの場合、デフォルトのGhidraのインストールディレクトリは/opt/ghidraとなります。
$ chmod +x runner.sh
$ GHIDRA_INSTALL_DIR=<GHIDRA_INSTALL_DIR> ./runner.sh <ELF_FILE>
実行結果は、./output/<SHA256>/フォルダにJSON形式のファイルで出力されます。
おわりに
本記事では、Miraiの設定情報抽出ツール「mirai-toushi」の機能と実行方法について説明しました。
GitHubリポジトリでは、ツールをサンプルの検体に適用したときのより詳細な 出力例 と JSON Schema も確認できます。
ツールで抽出できた設定情報は以下のような用途などで使えるので、是非活用してみてください。
-
- パスワードリストから検体が標的とする機器を推測
- C2サーバやScan Receiverのドメイン・IP アドレス・ポート番号をIoCとして活用
- 新規のMirai亜種の検知