Skip to content
KitploitKITPLOIT
ИнструментыЭксплойтыБлог
Log in
Отправить
ИнструментыЭксплойтыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

ЛентыКонтактыКонфиденциальность© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Tourmaline — Reverse engineering notes, deobfuscated source, IOCs, and YARA rules for the Tourmaline ClickFix Python RAT, covering its DNS tunnel and blockchain dead-drop C2. | Kitploit
Инструменты/GitHubGitHub/v-pun215/tourmaline
Indicator of Compromise (IOC) ManagementReverse EngineeringMalware AnalysisDigital ForensicsCryptographyCommand and ControlThreat IntelligenceLearning & EducationIncident ResponseDNS Analysis
GitHubv-pun215/tourmaline
109321 дней назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →

Tourmaline

Reverse engineering notes, deobfuscated source, IOCs, and YARA rules for the Tourmaline ClickFix Python RAT, covering its DNS tunnel and blockchain dead-drop C2.

Репозиторий
Поделиться
Контент недоступен на запрошенном языке. Показываем английскую версию.

Tourmaline

I recently stumbled upon a piece of cleverly designed malware that calls itself "Tourmaline".

This README is very kindly written by Claude as I was super busy with exams at the time of this repository's inception.

Exploiting and decrypting this malware took a huge chunk of my time from math prep!

Read the blogpost!

FOR EDUCATIONAL AND RESEARCH PURPOSES ONLY
All samples are provided for malware analysis and defensive research. Do not execute outside a sandboxed, air-gapped environment.


Overview

Tourmaline (Tourmaline.exe) is a sophisticated, multi-stage Windows infostealer/backdoor distributed via a ClickFix campaign - a fake Cloudflare "Verify you are human" browser popup that tricks users into manually running a malicious command or installer.

The binary is a custom-built Inno Setup 6.7.0 (Revision 2, 64-bit offsets) installer that bundles a full Python 3.11 runtime and two stages of obfuscated Python payload. It establishes a persistent backdoor with:

  • DNS tunneling C2 over UDP port 53 (masquerading as microsoft.com queries)
  • Ethereum blockchain dead-drop for C2 IP distribution (Sepolia testnet)
  • ChaCha20-encrypted task execution channel
  • ECDSA-signed commands to prevent sinkholing
  • Anti-sandbox time-lock (100M iteration countdown, bypassable in O(1))

Repository Structure

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

Infection Vector

The malware is distributed via ClickFix - a social engineering technique where a compromised or attacker-controlled website overlays a fake Cloudflare CAPTCHA or browser verification page. The overlay instructs the victim to:

  1. Press Win+R
  2. Paste a command (copied to clipboard by the page's JavaScript)
  3. Press Enter

The pasted command downloads and silently executes Tourmaline.exe. The installer runs /VERYSILENT /SUPPRESSMSGBOXES /NORESTART.


Binary Format

PropertyValue
File nameTourmaline.exe
Size11,341,339 bytes (~10.8 MB)
MD5b74ac808dea2de31caf024310694ef0c
SHA256c9b390b3b7148f549df86503858d52e030b2b5e78fed0bc525ded5927f9265d6
FormatInno Setup 6.7.0 Unicode (Revision 2, 64-bit offsets)
PE type32-bit PE, 11 sections
Overlay size10,447,387 bytes
Inno magic offset0xD9864 (890,148 bytes)
App nameTourmaline
App version2.63.519
App GUID{2C25872D-85FC-44C7-9B16-844E39E50A44}
Install path{commonappdata}\Tourmaline
Bundled runtimePython 3.11 (full embed)
Payload files36 files in solid LZMA2 stream

Note: Stock innoextract 1.9 cannot extract this binary — it only supports Revision 1. Revision 2 uses 64-bit offsets and requires custom parsing (see src/decrypt_payload.py).


Execution Flow

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

Stage 1 — Anti-Sandbox Time-Lock (O(1) Bypass)

The loader (main.py) uses a countdown from 99,999,999 to find the XOR decryption key. On a real machine this completes in seconds (because _n starts high and the true value is near 14,511,188). In a sandbox with a short time limit, the loop never completes.

Key structure:

full_key = struct.pack('>I', _n) + bytes.fromhex('2b0cffe07b06ac25793b3f00cfaa2dd5881c2d6378165247539dbbdaeb')

Since we know the first 16 bytes of the plaintext (g1 = lambda l6, ), we can recover _n instantly via known-plaintext XOR attack:

key_prefix = bytes(ciphertext[i] ^ known_plaintext[i] for i in range(4))
# Result: key_prefix = 00dd6c54 → _n = 14,511,188

Use src/decrypt_payload.py to reproduce this.


Stage 2 — Core Backdoor Architecture

Configuration (Hardcoded)

ParameterValue
C2 IP158.94.211.185
C2 Port53 (UDP)
ProtocolCustom DNS-over-UDP tunnel
Spoofed domainmicrosoft.com
ChaCha20 key36f555c87f71581f57d83576c88193fdc00a0173f741a3e198e2d7abdc9cda59
Blockchain contract0x2d7a04cca0c34005f58393f30ac725e25f19e5f5 (Sepolia)
ECDSA pubkeyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEt17l3rGHHR9sYdHEvV8S+JRRCUHQQveSadlGk04xM/8WClDf/67Tyritt2+T18SY8n0xv1TKKl0AgnNFuboEEQ==
Service nameSystemService / TourmalineUpdate
MutexGlobal\Tourmaline_<MachineGuid-hash>

Blockchain Dead-Drop (C2 Resilience)

The malware calls an Ethereum smart contract on the Sepolia testnet to retrieve the active C2 IP address. This means the attacker can change the C2 IP at any time by updating the contract — traditional IP blocklist-based C2 disruption is ineffective.

Contract : 0x2d7a04cca0c34005f58393f30ac725e25f19e5f5
Selector : 0xeb9fd6fe
Network  : Ethereum Sepolia (chainId 11155111)
RPC      : https://ethereum-sepolia-rpc.publicnode.com
Result   : ChaCha20-encrypted blob containing current C2 IP

The returned data is decrypted with the hardcoded ChaCha20 key to reveal the live C2 address. At time of analysis, this resolved to 158.94.211.185 (verified via live RPC call).

DNS Tunnel (C2 Communication)

All C2 traffic is sent as raw UDP DNS queries directly to the C2 IP on port 53. Queries are structured as <encoded_data>.microsoft.com, bypassing DNS-based filtering and appearing as legitimate Windows telemetry.

  • Custom implementation: Does not use Python's socket.getaddrinfo or any DNS library
  • Opcode obfuscation: Each packet has a random XOR byte applied to the DNS opcode field
  • Encoding: Task data is base-encoded into DNS label format

Task Execution Engine

Скачать инструмент