
Tourmaline ClickFix Python RATのリバースエンジニアリングノート、難読化解除済みソース、IOC、YARAルール。そのDNSトンネルとブロックチェーンデッドドロップC2を網羅しています。
最近、私は「Torumaline」と自称する巧妙に設計されたマルウェアの断片に偶然出会いました。
このREADMEは、このリポジトリの作成当時、私が試験で非常に忙しかったため、Claudeが非常に親切に書いてくれました。
このマルウェアの悪用と復号には、数学の準備から膨大な時間を割くことになりました!
ブログ記事を読んでください!
教育および研究目的のみ
すべてのサンプルはマルウェア分析および防御研究のために提供されています。サンドボックス化されたエアギャップ環境外で実行しないでください。
Tourmaline (Tourmaline.exe) は、ClickFixキャンペーンを通じて配布される洗練された多段階のWindowsインフォスティーラー/バックドアです。これは、偽のCloudflare「あなたが人間であることを確認してください」ブラウザポップアップで、ユーザーを騙して悪意のあるコマンドやインストーラーを手動で実行させるものです。
このバイナリは、完全なPython 3.11ランタイムと2段階の難読化されたPythonペイロードをバンドルした、カスタムビルドの**Inno Setup 6.7.0 (リビジョン2、64ビットオフセット)**インストーラーです。以下の機能を持つ永続的なバックドアを確立します:
microsoft.comクエリを装う)tourmaline/
├── README.md # このファイル
├── LICENSE # 研究利用ライセンス
├── .gitignore
│
├── src/ # 抽出および難読化解除されたソースコード
│ ├── stage1_loader.py # ステージ1: 元の難読化XOR時間ロックローダー (main.py)
│ ├── stage2_backdoor.py # ステージ2: 難読化解除されたコアバックドア (QGBdu.dxfから)
│ └── decrypt_payload.py # ユーティリティ: O(1)ペイロードキー復元と復号
│
├── iocs/ # 侵害指標
│ ├── indicators.json # 構造化されたIOCデータ (IP、ハッシュ、ドメイン、レジストリ)
│ ├── indicators.csv # SIEMインポート用のフラットCSV
│ └── rules.yar # YARA検出ルール
│
└── samples/ # マルウェアサンプル (パスワード保護)
├── README.md # サンプルアーカイブの手順
├── Tourmaline_sample.zip # パスワード: infected - Tourmaline.exeを含む
└── QGBdu.dxf # 生の暗号化されたステージ2ペイロードブロブ
このマルウェアはClickFixを通じて配布されます。これは、侵害された、または攻撃者が制御するウェブサイトが偽のCloudflare CAPTCHAまたはブラウザ検証ページをオーバーレイするソーシャルエンジニアリング手法です。オーバーレイは被害者に以下を指示します:
Win+Rを押す貼り付けられたコマンドはTourmaline.exeをダウンロードしてサイレントに実行します。インストーラーは/VERYSILENT /SUPPRESSMSGBOXES /NORESTARTで実行されます。
注: 標準の
innoextract 1.9ではこのバイナリを抽出できません — リビジョン1のみをサポートしています。リビジョン2は64ビットオフセットを使用し、カスタムパースが必要です (src/decrypt_payload.pyを参照)。
Tourmaline.exe
│
├─ Inno Setupインストーラーがサイレント実行
│ ├─ Python 3.11ランタイムを%APPDATA%\Tourmaline\に抽出
│ ├─ main.py (ステージ1ローダー)を抽出
│ ├─ QGBdu.dxf (暗号化されたステージ2ブロブ)を抽出
│ ├─ 既存のpythonw.exeインスタンスを強制終了
│ └─ 永続性を登録 (タスクスケジューラ / レジストリ)
│ └─ 名前: "TourmalineUpdate" / "Hardware monitoring service"
│
├─ ステージ1: main.py (XOR時間ロックローダー)
│ ├─ _nを99,999,999 → 0までカウント (遅いVMでは数時間のアンチサンドボックス遅延)
│ ├─ 各_nで33バイトのXORキーを構築: struct.pack('>I', _n) + hardcoded_suffix
│ ├─ QGBdu.dxfの既知の平文ヘッダーに対してキーをテスト
│ └─ 一致時: QGBdu.dxfを完全に復号し、結果をexec()
│ └─ O(1)バイパス: 最初の4バイトに対する既知平文攻撃 (下記参照)
│
└─ ステージ2: QGBdu.dxf → Pythonバックドア
├─ HKLM\SOFTWARE\Microsoft\CryptographyからMachineGuidを読み取り
├─ ミューテックスGlobal\Tourmaline_<hash>を導出
├─ イーサリアムデッドドロップ (Sepoliaテストネット)経由でC2 IPを解決
├─ C2へのDNSトンネルを確立
└─ ポーリング実行ループ: タスクを取得し、Pythonをexec()し、出力を返す
ローダー (main.py) は、XOR復号キーを見つけるために99,999,999からのカウントダウンを使用します。実際のマシンでは、これは数秒で完了します (_nは高い値から始まり、真の値は14,511,188付近であるため)。短い時間制限のあるサンドボックスでは、ループは決して完了しません。
キー構造:
full_key = struct.pack('>I', _n) + bytes.fromhex('2b0cffe07b06ac25793b3f00cfaa2dd5881c2d6378165247539dbbdaeb')
平文の最初の16バイト (g1 = lambda l6, ) がわかっているため、既知平文XOR攻撃により_nを即座に復元できます:
key_prefix = bytes(ciphertext[i] ^ known_plaintext[i] for i in range(4))
# 結果: key_prefix = 00dd6c54 → _n = 14,511,188
これを再現するにはsrc/decrypt_payload.pyを使用してください。
このマルウェアは、Sepoliaテストネット上のイーサリアムスマートコントラクトを呼び出して、アクティブなC2 IPアドレスを取得します。これは、攻撃者がコントラクトを更新することでいつでもC2 IPを変更できることを意味します — 従来のIPブロックリストベースのC2妨害は効果がありません。
Contract : 0x2d7a04cca0c34005f58393f30ac725e25f19e5f5
Selector : 0xeb9fd6fe
Network : Ethereum Sepolia (chainId 11155111)
RPC : https://ethereum-sepolia-rpc.publicnode.com
Result : 現在のC2 IPを含むChaCha20暗号化ブロブ
返されたデータは、ハードコードされたChaCha20キーで復号され、ライブC2アドレスが明らかになります。分析時点では、これは**158.94.211.185**に解決されました (ライブRPC呼び出しで検証済み)。
すべてのC2トラフィックは、生のUDP DNSクエリとしてC2 IPのポート53に直接送信されます。クエリは<encoded_data>.microsoft.comとして構造化され、DNSベースのフィルタリングをバイパスし、正当なWindowsテレメトリとして表示されます。
socket.getaddrinfoやDNSライブラリを使用していませんバックドアは任意のPython exec()エンジンを実装しています。タスクは:
exec()サポートされるタスクタイプ: Python exec、ファイルアップロード/ダウンロード、シェルコマンド、自己更新。
| ファイル | SHA256 |
|---|---|
Tourmaline.exe | c9b390b3b7148f549df86503858d52e030b2b5e78fed0bc525ded5927f9265d6 |
Tourmaline.exe (MD5) | b74ac808dea2de31caf024310694ef0c |
以下をカバーする検出ルールについてはiocs/rules.yarを参照してください:
このマルウェアがマシン上で実行された場合:
taskkill /F /IM pythonw.exe%APPDATA%\Tourmaline\ または %COMMONAPPDATA%\Tourmaline\TourmalineUpdateを削除HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunでTourmalineまたはSystemServiceを確認158.94.211.185:53/UDP; 予期しないすべてのアウトバウンドUDP/53をブロックethereum-sepolia-rpc.publicnode.compip install pyOpenSSL cryptography
# リポジトリルートから:
python3 src/decrypt_payload.py samples/QGBdu.dxf decrypted_stage2.py
7z x -pinfected samples/Tourmaline_sample.zip
LICENSEを参照してください。このリポジトリは教育および防御研究目的のみです。
| プロパティ | 値 |
|---|
| ファイル名 | Tourmaline.exe |
| サイズ | 11,341,339バイト (~10.8 MB) |
| MD5 | b74ac808dea2de31caf024310694ef0c |
| SHA256 | c9b390b3b7148f549df86503858d52e030b2b5e78fed0bc525ded5927f9265d6 |
| 形式 | Inno Setup 6.7.0 Unicode (リビジョン2、64ビットオフセット) |
| PEタイプ | 32ビットPE、11セクション |
| オーバーレイサイズ | 10,447,387バイト |
| Innoマジックオフセット | 0xD9864 (890,148バイト) |
| アプリ名 | Tourmaline |
| アプリバージョン | 2.63.519 |
| アプリGUID | {2C25872D-85FC-44C7-9B16-844E39E50A44} |
| インストールパス | {commonappdata}\Tourmaline |
| バンドルランタイム | Python 3.11 (完全埋め込み) |
| ペイロードファイル | ソリッドLZMA2ストリーム内の36ファイル |
| パラメータ | 値 |
|---|
| C2 IP | 158.94.211.185 |
| C2ポート | 53 (UDP) |
| プロトコル | カスタムDNS-over-UDPトンネル |
| 偽装ドメイン | microsoft.com |
| ChaCha20キー | 36f555c87f71581f57d83576c88193fdc00a0173f741a3e198e2d7abdc9cda59 |
| ブロックチェーンコントラクト | 0x2d7a04cca0c34005f58393f30ac725e25f19e5f5 (Sepolia) |
| ECDSA公開鍵 | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt17l3rGHHR9sYdHEvV8S+JRRCUHQQveSadlGk04xM/8WClDf/67Tyritt2+T18SY8n0xv1TKKl0AgnNFuboEEQ== |
| サービス名 | SystemService / TourmalineUpdate |
| ミューテックス | Global\Tourmaline_<MachineGuid-hash> |
| タイプ | 値 |
|---|
| C2 IP | 158.94.211.185 |
| C2ポート | 53/UDP |
| 偽装ドメイン | *.microsoft.com (カスタムUDP、実際のDNSではない) |
| イーサリアムRPC | https://ethereum-sepolia-rpc.publicnode.com |
| スマートコントラクト | 0x2d7a04cca0c34005f58393f30ac725e25f19e5f5 |
| キー | 値 |
|---|
HKLM\SOFTWARE\Microsoft\Cryptography\MachineGuid | 被害者フィンガープリンティングのために読み取り |
%APPDATA%\Tourmaline\ | インストールディレクトリ |
| タスクスケジューラ | TourmalineUpdate |
| サービス表示名 | Hardware monitoring service |
| ミューテックス | Global\Tourmaline_<hash> |
| フィールド | 値 |
|---|
| 発見日 | 2026年9月 |
| 研究者 | Vihaan Pundir (v-pun215) |
| 配布ベクター | ClickFix偽Cloudflare CAPTCHA |
| 分類 | バックドア / DNSトンネルC2 / ブロックチェーンデッドドロップ |
| プラットフォーム | Windows (64ビット) |