
Reverse-Engineering-Notizen, deobfuskierter Quellcode, IOCs und YARA-Regeln für den Tourmaline ClickFix Python RAT, einschließlich seines DNS-Tunnels und Blockchain-Dead-Drop-C2.
Ich bin kürzlich auf ein Stück clever gestalteter Malware gestoßen, die sich selbst „Tourmaline“ nennt.
Diese README wurde freundlicherweise von Claude verfasst, da ich zum Zeitpunkt der Entstehung dieses Repositorys mit Prüfungen extrem beschäftigt war.
Das Ausnutzen und Entschlüsseln dieser Malware hat einen großen Teil meiner Zeit von der Mathevorbereitung beansprucht!
Lies den Blogbeitrag!
NUR FÜR BILDUNGS- UND FORSCHUNGSZWECKE
Alle Samples werden für Malware-Analyse und defensive Forschung bereitgestellt. Nicht außerhalb einer sandboxed, air-gapped Umgebung ausführen.
Tourmaline (Tourmaline.exe) ist ein ausgeklügelter, mehrstufiger Windows-Infostealer/Backdoor, der über eine ClickFix-Kampagne verbreitet wird – ein gefälschtes Cloudflare-„Verify you are human“-Browser-Popup, das Nutzer dazu verleitet, manuell einen schädlichen Befehl oder Installer auszuführen.
Die Binärdatei ist ein maßgeschneiderter Inno Setup 6.7.0 (Revision 2, 64-Bit-Offsets)-Installer, der eine vollständige Python-3.11-Laufzeit und zwei Stufen obfuskierten Python-Payloads bündelt. Er etabliert eine persistente Backdoor mit:
microsoft.com-Abfragen)tourmaline/
├── README.md # This file
├── LICENSE # Research use license
├── .gitignore
│
├── src/ # Extracted & deobfuscated source code
│ ├── stage1_loader.py # Stage 1: Original obfuscated XOR time-lock loader (main.py)
│ ├── stage2_backdoor.py # Stage 2: Deobfuscated core backdoor (from QGBdu.dxf)
│ └── decrypt_payload.py # Utility: O(1) payload key recovery & decryption
│
├── iocs/ # Indicators of Compromise
│ ├── indicators.json # Structured IOC data (IPs, hashes, domains, registry)
│ ├── indicators.csv # Flat CSV for SIEM import
│ └── rules.yar # YARA detection rules
│
└── samples/ # Malware samples (password-protected)
├── README.md # Sample archive instructions
├── Tourmaline_sample.zip # Password: infected - contains Tourmaline.exe
└── QGBdu.dxf # Raw encrypted Stage 2 payload blob
Die Malware wird über ClickFix verbreitet – eine Social-Engineering-Technik, bei der eine kompromittierte oder vom Angreifer kontrollierte Website eine gefälschte Cloudflare-CAPTCHA- oder Browser-Verifizierungsseite überlagert. Das Overlay weist das Opfer an:
Win+R drückenDer eingefügte Befehl lädt Tourmaline.exe herunter und führt sie still aus. Der Installer wird mit /VERYSILENT /SUPPRESSMSGBOXES /NORESTART ausgeführt.
| Eigenschaft | Wert |
|---|---|
| Dateiname | Tourmaline.exe |
| Größe | 11.341.339 Bytes (~10,8 MB) |
| MD5 | b74ac808dea2de31caf024310694ef0c |
| SHA256 | c9b390b3b7148f549df86503858d52e030b2b5e78fed0bc525ded5927f9265d6 |
| Format | Inno Setup 6.7.0 Unicode (Revision 2, 64-Bit-Offsets) |
| PE-Typ | 32-Bit-PE, 11 Sektionen |
| Overlay-Größe | 10.447.387 Bytes |
| Inno-Magic-Offset | 0xD9864 (890.148 Bytes) |
| App-Name | Tourmaline |
| App-Version | 2.63.519 |
| App-GUID | {2C25872D-85FC-44C7-9B16-844E39E50A44} |
| Installationspfad | {commonappdata}\Tourmaline |
| Gebündelte Runtime | Python 3.11 (vollständiges Embed) |
| Payload-Dateien | 36 Dateien in einem soliden LZMA2-Stream |
Hinweis: Das Standard-
innoextract 1.9kann diese Binärdatei nicht extrahieren – es unterstützt nur Revision 1. Revision 2 verwendet 64-Bit-Offsets und erfordert eine benutzerdefinierte Verarbeitung (siehesrc/decrypt_payload.py).
Tourmaline.exe
│
├─ Inno Setup installer runs silently
│ ├─ Extracts Python 3.11 runtime to %APPDATA%\Tourmaline\
│ ├─ Extracts main.py (Stage 1 loader)
│ ├─ Extracts QGBdu.dxf (encrypted Stage 2 blob)
│ ├─ Kills any existing pythonw.exe instances
│ └─ Registers persistence (Task Scheduler / registry)
│ └─ Name: "TourmalineUpdate" / "Hardware monitoring service"
│
├─ Stage 1: main.py (XOR Time-Lock Loader)
│ ├─ Counts _n from 99,999,999 → 0 (anti-sandbox delay ~hours on slow VMs)
│ ├─ At each _n, constructs 33-byte XOR key: struct.pack('>I', _n) + hardcoded_suffix
│ ├─ Tests key against known plaintext header of QGBdu.dxf
│ └─ On match: decrypts QGBdu.dxf entirely and exec()s the result
│ └─ O(1) bypass: known-plaintext attack on first 4 bytes (see below)
│
└─ Stage 2: QGBdu.dxf → Python backdoor
├─ Reads MachineGuid from HKLM\SOFTWARE\Microsoft\Cryptography
├─ Derives mutex Global\Tourmaline_<hash>
├─ Resolves C2 IP via Ethereum dead-drop (Sepolia testnet)
├─ Establishes DNS tunnel to C2
└─ Poll-execute loop: fetches tasks, exec()s Python, returns output
Der Loader (main.py) verwendet einen Countdown von 99,999,999, um den XOR-Entschlüsselungsschlüssel zu finden. Auf einer echten Maschine ist dies in Sekunden abgeschlossen (da _n hoch beginnt und der wahre Wert nahe bei 14,511,188 liegt). In einer Sandbox mit kurzem Zeitlimit wird die Schleife nie abgeschlossen.
Schlüsselstruktur:
full_key = struct.pack('>I', _n) + bytes.fromhex('2b0cffe07b06ac25793b3f00cfaa2dd5881c2d6378165247539dbbdaeb')
Da wir die ersten 16 Bytes des Klartexts kennen (g1 = lambda l6, ), können wir _n sofort durch einen Known-Plaintext-XOR-Angriff wiederherstellen:
key_prefix = bytes(ciphertext[i] ^ known_plaintext[i] for i in range(4))
# Result: key_prefix = 00dd6c54 → _n = 14,511,188
Verwenden Sie src/decrypt_payload.py, um dies zu reproduzieren.
| Parameter | Wert |
|---|---|
| C2-IP | 158.94.211.185 |
| C2-Port | 53 (UDP) |
| Protokoll | Benutzerdefinierter DNS-over-UDP-Tunnel |
| Gefälschte Domain | microsoft.com |
| ChaCha20-Schlüssel | 36f555c87f71581f57d83576c88193fdc00a0173f741a3e198e2d7abdc9cda59 |
| Blockchain-Vertrag | 0x2d7a04cca0c34005f58393f30ac725e25f19e5f5 (Sepolia) |
| ECDSA-Pubkey | MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt17l3rGHHR9sYdHEvV8S+JRRCUHQQveSadlGk04xM/8WClDf/67Tyritt2+T18SY8n0xv1TKKl0AgnNFuboEEQ== |
| Dienstname | SystemService / TourmalineUpdate |
| Mutex | Global\Tourmaline_<MachineGuid-hash> |
Die Malware ruft einen Ethereum-Smart-Contract im Sepolia-Testnetz auf, um die aktive C2-IP-Adresse abzurufen. Das bedeutet, dass der Angreifer die C2-IP jederzeit durch Aktualisierung des Vertrags ändern kann — eine herkömmliche Störung des C2 über IP-Blocklisten ist wirkungslos.
Contract : 0x2d7a04cca0c34005f58393f30ac725e25f19e5f5
Selector : 0xeb9fd6fe
Network : Ethereum Sepolia (chainId 11155111)
RPC : https://ethereum-sepolia-rpc.publicnode.com
Result : ChaCha20-encrypted blob containing current C2 IP
Die zurückgegebenen Daten werden mit dem fest codierten ChaCha20-Schlüssel entschlüsselt, um die aktive C2-Adresse zu ermitteln. Zum Zeitpunkt der Analyse ergab sich daraus 158.94.211.185 (verifiziert über einen Live-RPC-Aufruf).