> ## Content Index
> Fetch the complete content index at: https://labs.stoik.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Following one ransom, properly: a Qilin case, from the first host to the money
- URL: https://labs.stoik.io/following-one-ransom-properly-a-qilin-case-from-the-first-host-to-the-money/
- Published: 2026-08-05T12:23:38.000Z
- Updated: 2026-08-10T13:50:55.000Z
- Author: Thibault Seret

> **A note on this write-up.**  
> This is the long version of a talk given at leHACK.  
> Identifiers are defanged: C2 IPs are masked, on-chain addresses and transaction IDs are redacted, exact amounts are rounded and block heights and timestamps withheld so the victim's transaction can't be trivially re-identified from a public explorer, GraphSense entity IDs are dropped, and the victim is referred to by sector only.  
> Exchange attributions are **trace-derived, not ownership-grade**, and the venue names are withheld in this public version (see *Methodology & confidence*). Negotiation economics from the engagement are withheld (TLP:AMBER+STRICT). Everything else is on-chain and public by nature.

---

## TL;DR

![The whole case on one clock: a five-month-early wallet flag, one VPN login, a 19-day silent dwell, encryption launched from the backup server, the ransom paid, and the funds fully laundered in 73 hours.](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide_master_timeline.png)

A healthcare-sector victim was hit by **Qilin** (aka *Agenda*). The entire break-in  
was **one login**: the built-in `administrator` opening an RDP session to the DC at 02:45 from a VPN-natted gateway IP, with a valid credential and no exploit. The attacker sat for **19 days**, then launched encryption **from the Veeam backup server**, not the domain controller. The DC went silent at 22:22\. The encryption itself was impossible to miss, but the DC's silence sat unflagged in monitoring for another 30 days, past the point the ransom was paid.

Two things made this case worth writing up:

1. **The infrastructure pivot.** The attacker wiped their logs but left one `WinSCP.ini`. It stored the raw ed25519 host keys of **11 C2 servers**, as point coordinates, not fingerprints. We reconstructed the fingerprints (RFC 8032), pivoted on internet-wide scan data, and went from a config file to *live* attacker tooling without sending a packet at the target.
2. **The money.** On stage we compressed the on-chain trace into "one payment → exchanges." That was a lie of brevity, and the room called it out. The real trail is a four-layer laundering machine with two **segregated** cash-out tracks, an intake-time 80/20 split, a coinjoin coordinator with **€2.15B of *total* multi-party throughput in 73 hours** (the operator is one depositor among hundreds, not the owner of that sum), and a destination wallet that had been **flagged as criminal five months before the victim paid.** And it was not a single payment: the *same* operator-hub address is shown, on the public chain alone, funding a **second** victim's ransom seventeen days later. This post gives that trace the room it deserves.

### Timeline (one clock)

| When                   | What                                                                                                                 | Source                           |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------------------- |
| **−5 months**          | The eventual cash-out wallet is flagged abuse / financial\_crime                                                     | CFLW dark-web feed               |
| **Feb 24, 02:45**      | Built-in administrator RDPs to the DC from a VPN-natted gateway IP                                                   | Fortigate VPN logs + RDP history |
| **+19 days**           | Silent dwell                                                                                                         | n/a                              |
| **Mar 14, 22:22**      | Encryption launched from the Veeam backup server; DC goes silent                                                     | host forensics                   |
| **+30 days**           | DC silence finally flagged in monitoring (the incident itself was discovered immediately, via the encryption impact) |                                  |
| **\~3.5h pre-payment** | Victim sends a 0.0001 BTC test ping to the ransom address                                                            | on-chain                         |
| **Early April 2026**   | Ransom paid: **\~2.5 BTC ≈ €150k**                                                                                   | on-chain                         |
| **+73h after payment** | Funds fully laundered                                                                                                | on-chain                         |
| **Post-incident**      | WinSCP.ini → 11 C2 → fingerprint pivot → 300→9 hosts                                                                 | OSINT                            |

---

## Who is Qilin

Thirty seconds on the adversary, because the structure matters for the money. **Qilin** (aka *Agenda*) is a **Ransomware-as-a-Service** operation, active since **2022**. An operator runs the platform and the leak site, affiliates do the actual break-ins, and the two split the take. The negotiation and operational tradecraft is **inherited from Conti**,  
which, as you'll see, runs all the way down to how the operator and the affiliate launder *separately*, on two tracks that never touch.

By volume it is the **most active ransomware brand on earth** right now. Victims named on its leak site went from **167 in 2024 to 958 in 2025**, a **+474%** jump as LockBit and RansomHub collapsed, and 2026 is on pace to beat that again (**1,911** leak-site posts all-time). The economics are the most affiliate-friendly in the market: affiliates keep **up to 85%** of each ransom, and the operator takes the rest for running the platform.  
Demands come primarily in **BTC**, occasionally **XMR**. Hold that split in your head, because in the trace below you watch the **80/20 cut happen on-chain**.

It is not abstract. Qilin's most infamous hit, the June 2024 **Synnovis / NHS London** attack, delayed **11,000+ patient appointments**, forced a national blood appeal, and was cited as a contributing factor in a patient's death. And yet **Ransomwhere**, the public ransom-payment database you'd reach for to ask "how much is this group really making," has **zero** entries for Qilin; it skews toward 2018 to 2021 families. The busiest group on the planet is effectively invisible to the feed built to track ransom payments. *No public feed tracks it* is not the same as *it isn't happening*, which is exactly why one case, traced  
properly, is worth the length that follows.

How we know it's Qilin: the attribution rests on the incident-response side, not the chain **the ransom note matched Qilin's known template, encrypted files carried the group's extension, and the note pointed to the group's known TOR negotiation portal**. Nothing in the money trace depends on the label; the laundering machine below would be worth documenting whoever ran it. But every "Qilin" in this post traces back to those host-side artefacts, not to anything on-chain.

> *Figures: leak-site counts via Ransomlook and public reporting; Synnovis impact per NHS* 
> *England / BBC. Throughput and payment specifics below are from our own case work.*

---

## Pillar 1: One leftover file → their whole network

The DC was clean: no log-clearing, no audit tampering, no attacker tooling. The real evidence sat on the staging host the encryption ran from, in a folder named `C:\ProgramData\update\` (boring on purpose; a folder of installers reads like patching). Among the tools (Atera RMM as C2, NetScan, PsExec, a recon `.bat`) was a portable **WinSCP**, and WinSCP keeps a diary.

### WinSCP stores the host keys, as raw points

`WinSCP.ini` has a `[SshHostKeys]` section recording the SSH host key of **every server it ever connected to**. For ed25519 it stores the key in PuTTY's legacy format: the **affine `(x, y)` coordinates** of the Edwards point, *not* the fingerprint that Shodan and Censys index on.

```ini
[SshHostKeys]
ssh-ed25519@22:45.135.xxx.xxx = 0x89272fd8…f32199,0x2cebc698…92ebdc
ssh-ed25519@22:176.120.xxx.xxx = 0x89272fd8…f32199,0x2cebc698…92ebdc   ; <- identical key
ssh-ed25519@22:179.43.xxx.xxx = 0x…
…11 distinct C2 servers logged in total

```

Two IPs carrying the **identical** `(x, y)` is the first finding: they are **one server identity behind two addresses**, the same operator-controlled host, or a clone of its image. One false positive to rule out before leaning on this: hosting providers that clone VMs from a template without regenerating host keys can hand the identical key to unrelated tenants. **Here both IPs sat in the same provider's ranges with the same service stack, so we kept the one-identity reading.**

### Reconstructing the fingerprint (RFC 8032 §5.1.2)

To pivot, we need the SSH fingerprint, which means turning `(x, y)` back into the 32-byte wire-format public key, then hashing it. Point compression is the whole trick: encode `y` little-endian, and fold the low bit of `x` into the top bit.

```python
# WinSCP stores the ed25519 host key as the affine (x, y) of the Edwards point.
x = int(parts[0], 16)
y = int(parts[1], 16)

# RFC 8032 §5.1.2: compress to the 32-byte SSH pubkey.
pub = bytearray(y.to_bytes(32, "little"))   # y, little-endian
pub[31] |= (x & 1) << 7                      # fold bit-0 of x into the top bit

blob = ssh_string(b"ssh-ed25519") + ssh_string(bytes(pub))

# Hash the wire blob: each scanner indexes a different encoding of it.
md5    = hashlib.md5(blob).digest()
sha256 = hashlib.sha256(blob).digest()
shodan_fp  = ":".join(f"{b:02x}" for b in md5)                       # Shodan  ssh.fingerprint   (colon-MD5)
censys_fp  = sha256.hex()                                            # Censys  fingerprint_sha256 (hex)
openssh_fp = "SHA256:" + base64.b64encode(sha256).decode().rstrip("=")  # ssh-keygen -lf (base64)

```

The reconstructed value is **byte-for-byte** what `ssh-keygen -lf` prints for the same key. We verified it against freshly generated keys before trusting it on the case data: reconstruct `(x, y)` → fingerprint, compare to `ssh-keygen`, identical.  
That's nine lines of point math, no magic, and it's the entire basis for the pivot.

### Pivot on the key, not the address

The C2 IPs from the config are **cold** today: query them on Censys/Shodan and you get *no results*; even where a host answers, the host key is `No Data`. The operator rotated away months ago. The IP rotates before any blocklist publishes it. The fingerprint only rotates if the operator regenerates the host key, one command, which this operator never ran. The pivot works because of opsec laziness, not physics: treat it as a window that closes the day they read a post like this one. **The IP rotates before any blocklist publishes it. The fingerprint does not.**

So you search the *fingerprint* across the internet's existing scan data, with no active scanning at the target:

```text
# Shodan
ssh.fingerprint:"51:f9:bc:a6:…:ee:29:04"

# Censys
services.ssh.server_host_key.fingerprint_sha256="9a51cbb8…719a82cd"

```

Each query returns **every host presenting that key**, including addresses never written in the config, and it catches IP rotation the moment the operator moves; the key travels with the server. Clustering the results by **identity, not address** surfaces the wider fleet.

### From the whole internet to nine hosts

Knowing the affiliate's tooling, we turned their habits into Censys filters and  
intersected two ordinary signals into one rare combination:

```text
http Server header = "CerberusFTPServer/2024"     # 300 hosts run it
  AND labels.value = "RMM"                        # the affiliate also ran Atera
→ 9 candidate hosts

```

By itself, Cerberus FTP is on \~300 hosts; an RMM label is common too. Asked for both at once, the internet collapses to **9 hosts** that look like this operator, one of which served a live **Cerberus Web Client** login page (the affiliate's browser-based tool for moving stolen victim files).

![slide07f_funnel.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide07f_funnel.png)

> From the whole internet to nine servers: 300 hosts run the affiliate's Cerberus FTP build; intersect that with an RMM label and the internet collapses to nine candidate hosts.  
> **Honest framing.** Those nine are a *shortlist of candidates to investigate*, not confirmed attribution; but a shortlist of nine, built from one victim's leftover file, with zero packets sent at the target.

**The host serving the live Cerberus login page was reported to its provider before publication.**

---

## Pillar 2: Following the money, properly

This is the section we owe the room. On stage it became "the victim paid, and the money went to exchanges." Here is what actually happened.

First, the methodological point that makes the rest legible: **we do not trace addresses, we trace entities.** A blockchain address is a leaf. Using the common-input-ownership heuristic (co-spend clustering, the engine inside tools like GraphSense), addresses that are spent together are inferred to be controlled by one actor and collapsed into an **entity**. The "one transaction → exchange" story skips every entity, every intermediate relay, and the split that happens *before* anything reaches a cash-out. Put those back and the picture changes completely.

### The payment, and the move before it

- **Ransom:** **\~2.5 BTC (≈ €150k)**, early April 2026, into an operator-controlled intake address. *(Exact amount, block, timestamp and tx hash are withheld here. Together they'd pull the unredacted victim transaction from any explorer in seconds.)*
- **3.5 hours earlier:** a **0.0001 BTC** test transaction, *victim wallet → ransom address*. This is a **victim test-send** (confirming the address works before wiring six figures), not an operator action. That is precisely *why* it's a dependable signal rather than fragile tradecraft: it's the victim's own caution, so the operator can't suppress it without instructing victims to stop verifying the address. As an on-chain tell, a tiny inbound to a ransom address routinely precedes the full transfer, so spotting it buys a few hours' notice that a payment is imminent.

![slide09b_testping.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide09b_testping.png)

> A 0.0001 BTC test ping fires 3.5 hours before the full \~2.5 BTC payment, from the same wallet to the same address: the very first on-chain move, almost invisible, and a live warning that a payment is coming.

### The funding anomaly

Before the payment, where did the victim's BTC come from? Tracing the victim wallet *backwards*, its \~2.5 BTC arrived via a **single-use relay** funded by the **operator hub** (`~12 BTC → relay → ~2.5 BTC → victim`), and the funding transaction sits in the **same block** as the ransom payment. The victim held the coins for *less than one block*. Victim and operator infrastructure demonstrably touch *before* the ransom is paid. That much is **confirmed** on-chain.

The interpretation needs care, and our earlier instinct ("the operator seeded the victim's wallet") is probably the *weaker* reading. The more likely one: the victim bought BTC through a **gray-zone OTC desk that the operator also launders through**. The hub behaves like a high-volume OTC (four-year history, hundreds of counterparties, \~€388M throughput), and ransomware crews are known to steer victims toward "no-questions" desks they themselves use. On that reading the shared infrastructure needs **no victim complicity** and no bespoke pre-funding; operator-seeding becomes a secondary hypothesis, not the default. Either way the on-chain fact stands, and, as a later section shows, the *same* just-in-time  
funding shape recurs in a second incident, which fits a shared OTC far better than per-victim seeding.

One caveat that colours everything downstream: we call it "the operator hub" as shorthand, but whether the hub is operator-*owned* infrastructure or a third-party gray-market desk the operator merely *uses* is unresolved on-chain. The distinction is not academic. If it is a shared desk, its \~€388M lifetime throughput is the *desk's* volume, not Qilin's revenue, and the downstream "relays" are ordinary hot-wallet change rather than bespoke laundering hops. We keep the "hub" label for readability and flag the ambiguity rather than smooth it over.

### The split happens at the intake, not at an exchange

The ransom address is an **operator-controlled intake**. Funds do not flow from it to an exchange. They **split**, within hours:

- **80% (≈2.0 BTC) → the affiliate pool**
- **20% (≈0.5 BTC) → the operator's mixer pool**

This is the inherited RaaS revenue model expressed on-chain, and it's the first thing the compressed version erased.

### Two cash-out tracks, kept apart

From the split, the money runs down **two independent laundering tracks**. A 3-hop forward trace from one never reaches the other; they are deliberately kept apart. (Operationally: two cash-outs, two subpoenas.)

**The affiliate track (the gang's cut).**  
The 80% lands in an **affiliate pool**, a cluster with **\~€194M lifetime** 
**throughput** across **\~2,196 counterparties**, drained to zero. The pool then exits in a **single batch of 1,604.15 BTC ≈ €113.6M (>99.95% of its balance)** to an off-ramp cluster carrying multiple exchange tagpacks, consistent with an **OTC / institutional desk** (*working hypothesis*). Co-resident in that off-ramp cluster is a **Phobos** payment address from 2021 (*suggestive only*; a CIOH cluster-merge artifact cannot be ruled out from a single address).

**The operator track (the brand's cut).**

The 20% enters the **operator's mixer pool**, a **WabiSabi-style coinjoin** 
**coordinator** (P2TR) that processed **35,621 BTC ≈ €2.15B in the same 73 hour window** (\~€700M/day). That €2.15B is the coordinator's *total* multi-party throughput, not the operator's money; the operator is one depositor among hundreds, which is precisely the point of using it.A number that size deserves its own scrutiny: \~€700M/day is well beyond anything public coordinators have historically carried, and the obvious objection is that we mistook an exchange's batching for a coinjoin. The structure says otherwise — uniform-denomination P2TR outputs, hundreds of counterparties with no address reuse, and zero tagpacks where an exchange cluster would carry many. But the anomalous scale is itself part of the finding: coordinators this size exist, and they wear no label.  
From there:

- a direct hop to one exchange (`10.97 BTC`);
- the rest through a **CFLW-tagged abuse corridor** (`21,541 BTC` across \~25k addresses) that fans out to four more exchange clusters (`22.62 / 8.13 / 6.88 / 5.20 BTC`);
- and a leg back into a public **Wasabi CoinJoin** (\~22.5M addresses), the **end of trace**.

Crucially, a portion of the mixed output (≈77%) re-merges toward the affiliate pool. The tracks brush on-chain even though the cash-outs stay segregated, and the direction of that flow is telling. The most economical reading is that the operator settles with affiliates in post-mix coins: the 20% goes in dirty, comes out clean, and most of it is handed back. On that reading the mixer isn't just the operator's laundry, it's the payroll department. We file it as a working hypothesis; simple post-mix consolidation fits the same graph. Either way, the segregation is about the cash-outs, two exits, two subpoenas, not about the money never touching.

### The warning nobody used

The affiliate pool, the wallet the victim's money actually landed in, was tagged `abuse / financial_crime` by a commercial dark-web feed on **2025-11-06**, **five months before the payment.** The ransom-note address itself was fresh and screened clean; the destination did not. Screening only the address you're given shows nothing. **Screen the cluster it belongs to, and re-screen the moment funds move.**

### The detailed trail (defanged)

![slide_money_graph.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide_money_graph-1.png)

> The full map: the victim pays one ransom into an operator-controlled intake, which splits 80/20\. The 80% gang's cut runs down the affiliate track (affiliate pool → single-batch off-ramp); the 20% brand's cut runs down the operator track (coinjoin mixer pool → CFLW abuse corridor → five trace-tagged exchange clusters). The operator hub also funded the victim's wallet before payment. Wallet addresses and entity IDs removed; amounts aggregate; exchange names withheld and are trace tags, not ownership.

### Scale, in context

This was not a boutique operation. The **operator hub** has cycled **\~9,006 BTC (≈€388M) over four years** across 115 addresses and is still active; our victim's payment is **\~0.03%** of its lifetime throughput. The hub is fed by **abuse-tagged clusters** (a dark-web `mixing_service` contributing \~3,049 BTC over 74 tx, an `account_hack/market` source, a `money_laundering` source), and it pushes out to a public Wasabi CoinJoin and even to a **2022 ransomware-tagged address**: multi-affiliate, multi-incident laundering. The affiliate side shows **\~2,196 inbound counterparties** at \~1.26 BTC each (≈€71k *at each deposit's block time*, the size of a typical affiliate cut, **not** €194M ÷ 2,196), many other victims, historically.

> **Discipline note.** This multi-victim claim is **aggregate and historical** (hub throughput + counterparty count). There is exactly **one** victim intake in *this* dataset, the GraphSense export. An earlier pass that read operator-internal laundering denominations *within that dataset* as "other victim streams" was **retracted**, and we don't reintroduce it. Enumerating other victims is a separate query. That is exactly what the next section does, on the public chain, and it turns up a concrete second one.

### It wasn't a single payment: a second victim, on the public chain

After the talk, we ran the open-source version of that query: no commercial clustering, no entity database, just the public Bitcoin ledger read through a free explorer. One result is worth stating plainly.

![slide_second_victim.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide_second_victim.png)

> The same operator-hub address that funded our victim is shown funding a different victim seventeen days later: the hub's primary address sends \~11 BTC to a single-use relay, the relay passes \~10 BTC to a funder wallet, the funder sends the exact ransom amount to a fresh victim wallet, and in the same block that victim forwards it to a new ransom intake, preceded by a 0.0001 BTC test-ping fifteen minutes earlier.

About **seventeen days after our case**, the *same recurring operator-side* 
*recipient* surfaces again. On the free public chain we can follow it  
address-to-address, no clustering required: a funder wallet sends the **exact ransom amount** to a fresh victim wallet, and \~2 hours later that victim forwards it into a new ransom intake that **splits to that same recurring operator-side address**, the third such split we found inside an 11-day April window. The just-in-time funding shape repeats: a funder pre-loads the precise amount, the victim holds it only briefly before paying.

What clustering *would* be needed for, and what we therefore **don't** assert, is that this recurring recipient is the *same entity* as the hub that funded our healthcare victim. Confirming that needs the commercial clustering tier we deliberately did without here; on free public data the two are a **candidate match, not proof**. So this is a concrete, publicly traceable second ransom split that shares one operator-side recipient with our case. Strong as a pattern, but "the same hub paid twice" stays a **working hypothesis** until a commercial tier resolves the cluster.

The operator's housekeeping is visible too. Within the same April window, that operator-side recipient moved a cut through **three transactions packed into a single block**, each one spending the *previous* transaction's **unconfirmed** output:  
![slide_sameblock.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide_sameblock.png)

> Three transactions in one Bitcoin block: TX2 spends an output of TX1, TX3 spends an output of TX2, none of them confirmed yet. Whoever signed TX2 and TX3 holds the keys to the chained addresses — read straight off the ledger, no clustering needed. A recurring collector address skims a small peel from both.

That ordering is only possible if the spender holds the private key to each freshly created output: you cannot spend an unconfirmed output unless you own it. Chained this tightly inside a single block, it is strong evidence of one wallet moving on autopilot. It is not a magic wand: exchange batching and CoinJoin coordinators chain unconfirmed outputs too, so we read it as strong corroboration of single-wallet control rather than an absolute trump card, strongest when paired with the co-spend clustering. A recurring **collector** address skims a small peel from each hop, and the same collector recurs across the chain: operator bookkeeping, in the open.

But it's worth being exact about what the public chain can and can't carry, because the difference between "verified" and "attributed" is the whole game:  
![slide_osint_boundary.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide_osint_boundary.png)

> A two-column scorecard. Verified on public data, reproducible by anyone: same-block atomic chaining, the hub funding a second victim, the repeating just-in-time funding plus dust test-ping, and a recurring operator-side collector. Needs commercial tooling, not asserted here: the full 115-address cluster and the €388M total, the exchange names at cash-out, the dark-web abuse tag flagged five months early, and the Qilin family attribution itself.

**What public data proves:** the same-block common control, the second publicly traced ransom split, the repeating just-in-time funding shape, the recurring collector.  
**What it cannot, and we therefore don't claim:** that the second split's  
operator-side recipient is the *same hub* that funded our victim rather than a lookalike address (that's a cluster question, not a ledger one), the full 115-address cluster and the \~€388M total (multi-hop clustering at scale isn't reproducible from a public explorer), the exchange names at cash-out (no public source attributes them), the dark-web "flagged five months early" tag (proprietary by nature, which is *why* it has value), and the "this is Qilin" label itself (that rests on the incident-response side, not the chain).

One emerging behaviour is worth flagging without over-reading it: in a sibling incident, change funds transit **cross-chain through NEAR Intents**, moving in chunks up to \~`0.30 BTC` to a deposit address that immediately forwards to NEAR Intents' Bitcoin treasury (which we identified from a public block-explorer tag for that treasury address, a third-party label, not NEAR's own published list). The appeal is structural: an intent-based cross-chain swap moves BTC into another chain (or straight into a stablecoin) *programmatically*, with **no deposit account at a KYC-bound exchange**. The deterministic on-chain  
link breaks at that non-custodial boundary, which is harder to subpoena than an exchange; that said, a cross-chain tracker can often re-acquire the trail from the treasury's downstream side and tight timing correlation, so it is a speed bump, not a wall. We flag this as a single sibling-incident observation, not a trend we can prove from this dataset, and we are deliberately **not** using it to characterise our healthcare victim, whose funds we did not trace there.

---

## Pillar 3: Why it stayed quiet

The attacker's tradecraft was modest. The *detection environment* did the hiding.

**Every loud alert was a false positive.** Over the 16 days of DC logs that survived, there were **940,969** failed-logon "brute force" events, all **self-inflicted**: a misconfigured Barracuda DCAgent hammering the DC  
from localhost (\~59k/day), normal Fortigate VPN LDAP binds that look exactly like a password spray, and nightly Veeam VSS `ntds.dit` snapshots tripping an "Ntdsutil Abuse" rule. **17 Sigma rules fired, all noise.** The one real indicator, the 02:45 built-in-admin login, was the quietest event in the log.

**The evidence almost didn't survive.** The DC kept only **16 days** of security logs, shorter than the 19-day dwell, so its own record of the break-in was already overwritten by the time anyone looked. We reconstructed the initial access from the **Fortigate VPN logs**, which retained the account, the three connections (Feb 20/23/24), the 02:45 login, and the source. The way in was a **valid VPN credential** (reused, weak, or broker-sourced; acquisition unknown), **not an exploit**. Two controls would each have stopped it cold. The VPN accepted a password alone — no MFA — so one leaked credential was the entire perimeter. And the account behind it was the domain's built-in administrator: RID 500, **usable through the VPN / used over RDP immediately after the VPN session**, straight onto the DC. That's also the detection nobody had: built-in administrator, successful type-10 logon, source in the VPN pool is a one-line rule with essentially zero false positives. In an estate that produced 940,969 false alarms in 16 days, the single highest-signal rule available was never written.  
The same gap means the 19-day dwell is partly a blank: with the DC's log  
window already rolled over, the stretch between access and encryption  
can't be reconstructed from host logs. The tooling (Atera, NetScan, WinSCP, PsExec) was recovered from the Veeam staging host *after the fact*; it tells us what they ran, not the day each piece landed.

Data left the estate over SFTP via WinSCP toward the Cerberus infrastructure; volumes are withheld here. **The victim never appeared on the leak site, consistent with a paid ransom.** \- Fortigate → FortiGate

**The launch point was the backup server.** Encryption ran from the Veeam host (`10.160.0.26`), not the DC. The DC was only the identity target. Encryption was Windows-only — despite Qilin shipping one of the more capable ESXi lockers in circulation, and despite NetScan having mapped the VMware ports. The affiliate saw the hypervisors and left them alone. Time-boxed affiliate, skills gap, or a playbook that stops at Windows, we can't say which, but it's a reminder that affiliate capability and brand capability are different things: the arsenal is only as dangerous as the person deploying it.

**The C2 was a signed, whitelisted IT product.** Atera RMM, dropped as  
`AteraAgent.exe / setup_Unassigned.msi` in `\ProgramData\update\`. "Code signed and legitimate" is now an attacker advantage, not a safety guarantee.

The monitoring gap outlived the incident. The victim knew it had been encrypted within hours, systems were down, a note was on screen — yet "the domain controller stopped producing logs" wasn't flagged for 30 days, a week after the ransom had already been paid. Even mid-crisis, nobody correlated the silence of the most important host in the estate with the incident unfolding around it.

---

## Methodology & confidence

Every claim above carries a tier. We never dress a trace tag up as ownership.

![slide_methodology.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide_methodology.png)

> How we read it, shape over labels: the mixer carried no provider tag, so we identified it by structure (≈€2.15B over 73h, hundreds of no-reuse counterparties, uniform P2TR outputs, zero tagpacks). Each claim is filed under a confidence tier from confirmed down to gated

| Tier                   | Means                        | Examples here                                                                                                                                                                                                                                                                                                                                          |
| ---------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Confirmed**          | Cryptographic / on-chain     | the payment; the 80/20 split; the two-IPs-one-key match; operator↔affiliate segregation; the victim's BTC traced back to the hub; a **second ransom split publicly traced address-to-address**; **same-block atomic chaining** \= common control of the chained addresses (the single-wallet reading of the whole chain is High-confidence, see below) |
| **High-confidence**    | Multiple heuristics agree    | operator hub = professional multi-affiliate laundering hub; operator pool = coinjoin coordinator; multi-victim history                                                                                                                                                                                                                                 |
| **Working hypothesis** | Single heuristic / trace tag | affiliate off-ramp = OTC desk; the five trace-tagged exchange clusters (Chainlabs **trace** tags, not ownership; names withheld in this public version); the second split's operator-side recipient = the *same hub* as our case (a recurring address across an 11-day window, candidate-grade without commercial clustering)                          |
| **Gated**              | Needs a commercial tier      | the real-world actor behind the off-ramp, one query away, deliberately not invented                                                                                                                                                                                                                                                                    |
| **End of trace**       | Tooling limit                | mixer internals and the Wasabi CoinJoin; demixing needs timing analysis                                                                                                                                                                                                                                                                                |

Three principles do most of the work:

- **Multi-input only.** Our clusters rest on the **common-input-ownership** heuristic: addresses co-spent as inputs to one transaction must share a signer. We lean on that and deliberately **not** on change-address heuristics, which infer ownership from *suspected* change outputs and are a classic source of false merges (GraphSense's entity clustering is built the same way). Where we needed the strongest available signal, the operator's outflow, we went past heuristics to same-block chaining. What it proves outright is control of the chained addresses — you cannot spend an output you don't hold the key to. What it strongly suggests, paired with the co-spend clustering, is one wallet moving on autopilot; exchanges and coordinators chain unconfirmed outputs too, so we don't read it alone.
- **Shape over labels.** The mixer carried no tag from any provider. We identified it by its *structure*: \~€2.15B throughput in 73h, hundreds of distinct counterparties with no reuse, uniform P2TR outputs, zero tagpacks. A coordinator wears no label; throughput and fan-in/out are the signature.
- **Trace tags ≠ ownership.** The exchange names come from Chainlabs Trace TagPacks: strong leads, not court-grade. Confirm via a commercial ownership tier before any filing. Say it out loud whenever the names appear.

> **On the euro figures.** Every EUR amount here is GraphSense's valuation of a transaction *at its own block time*, not a single spot price. BTC's price moved between the events described, so dividing one euro figure by another (or by a counterparty count) gives slightly different implied BTC prices: the affiliate off-ramp, for instance, cleared at a higher BTC price (\~€71k) than the April ransom (\~€60k). The **BTC quantities are the invariant**; read the euros as point-in-time conversions.

---

## Five things to take home

None of these require a bigger budget.

1. Screen the cluster, not the address — and re-screen when funds move. The ransom-note address was fresh and clean; the pool it drained into had been flagged abuse / financial\_crime five months earlier. One cluster-level query at payment time would have surfaced it.
2. The test ping is your warning shot. A tiny inbound preceded the full payment by 3.5 hours in our case and 15 minutes in the second one. If you watch ransom addresses at all, alert on the small test-send, not the six figures — that's the few hours of notice you'll ever get.
3. Log retention must outlive dwell. 16 days of DC security logs against a 19-day dwell: the record of the break-in was overwritten before anyone looked. Longer retention on tier-0 hosts is the cheapest forensic insurance there is.
4. One rule beats 940,969 alerts. Built-in administrator, type-10 logon, VPN source: near-zero false positives, and it would have caught the only real event in the log. MFA on the VPN would have prevented the event existing at all.
5. The backup server is a launch pad, not a bystander. Encryption ran from the Veeam host, not the DC. Treat backup infrastructure as tier-0: separate credentials, separate monitoring, and a raised eyebrow at anything it executes.

---

## ATT&CK

![slide_attack_matrix.png](https://storage.ghost.io/c/27/4b/274b59ba-d79e-48c3-8026-1123d67ebe3d/content/images/2026/08/slide_attack_matrix.png)

> The whole chain mapped to catalogued ATT&CK techniques across Initial Access, Execution/C2, Discovery, Lateral Movement, Exfiltration and Impact: every ID visible in standard Windows Security and network logs.

| Tactic           | Technique                                   | In this case                                                                    |
| ---------------- | ------------------------------------------- | ------------------------------------------------------------------------------- |
| Initial Access   | T1078.001 Valid Accounts: Default           | built-in administrator, 02:45 RDP to the DC (VPN-natted source), zero prior use |
| Initial Access   | T1133 External Remote Services              | VPN-natted entry                                                                |
| Execution / C2   | T1219 Remote Access Software                | Atera RMM as C2                                                                 |
| Defense Evasion  | T1036.005 Masquerading: Match Name/Location | \\ProgramData\\update\\                                                         |
| Discovery        | T1046 Network Service Discovery             | NetScan / SoftPerfect                                                           |
| Lateral Movement | T1021.001 Remote Services: RDP              | host-to-host, PsExec                                                            |
| Discovery        | T1083 File & Directory Discovery            | ls -R >> listing.txt                                                            |
| Exfiltration     | T1048 Exfil Over Alternative Protocol       | SFTP via WinSCP                                                                 |
| Impact           | T1486 Data Encrypted for Impact             | launched from the Veeam backup server, 22:22                                    |
| Impact           | T1657 Financial Theft                       | €150k laundered in 73h                                                          |

---

## Appendix: defanged IOCs & reproducible bits

**Host / endpoint**

- C2 staging path: `C:\ProgramData\update\`
- C2 agent: `AteraAgent.exe` / `setup_Unassigned.msi` (Atera RMM)
- Recon: `Netscan64.exe` (SoftPerfect), `scan.bat`, PsExec
- Exfil: `WinSCP.exe` 6.3.5 portable (over SFTP)