On this page
In late February, Pay2Key ransomware hit a U.S. healthcare organisation. Halcyon and Beazley Security published a joint report (opens in new tab) detailing the attack chain: compromised admin credentials, a week of dormancy, TeamViewer for access, credential harvesting with Mimikatz and LaZagne, and a self-extracting 7z archive that deployed the encryptor. The entire encryption phase took about three hours.
The report described the crypto as ChaCha20 with Curve25519 key exchange, a 12-byte null nonce, and per-file key generation via SystemFunction036. The report published IOC hashes, but the encryptor binary from the healthcare incident (68a95a0a...) is not on MalwareBazaar, Triage, ThreatFox, or VirusTotal as a downloadable sample.
We located an earlier Pay2Key build from January 9, 2026, packaged as a Mimic-based self-extracting archive. This is not the same binary used in the February healthcare incident. It is an older build from the same RaaS platform, sharing the same toolchain, SFX delivery structure, and NoDefender AV evasion kit documented in the Halcyon report. The February variant may differ in configuration, encryption thresholds, or behaviour. What follows applies to the January build only.
We mapped the encryptor's crypto architecture: key generation, cipher selection, nonce handling, key protection, and the intermittent encryption logic. The encryption is sound. There is no shortcut past Curve25519, no nonce reuse flaw, no weak key generation. Without the operator's private key, encrypted files are not recoverable through cryptographic means.
In this build, Pay2Key's intermittent encryption mode leaves 70 to 87 percent of large files as plaintext. For databases, virtual machine disks, and backup archives, most of the data is still there. Whether the February build uses the same thresholds and block sizes is unknown.
Sample overview
The Pay2Key encryptor ships inside a self-extracting 7z archive. The outer SFX drops 7za.exe, Everything.exe, and a password-protected inner archive containing the encryptor, a secondary binary, and Sysinternals SDelete.
| Field | Value |
|---|---|
| SHA256 | 2ae80e5bff8fc9055ce7dc60e59447cba6e6c3a215eea1b6de7d9cb5ae26f9e8 |
| MD5 | 10333c96ae8c877398bb16841b627c94 |
| Type | PE32 (GUI) Intel 80386, MSVC++ 2015 |
| Size | 2,394,112 bytes |
| Compiled | August 31, 2024 |
| Crypto library | OpenSSL 1.1.x (statically linked) |
| Internal name | payfast |
| File extension | Configurable per build |
| Ransom note | C:\\temp\\Decrypt_files.txt |
| Session file | C:\\temp\\session.tmp |
| Contact | ueli.maurer@onionmail.org |
The encryptor builds on Mimic ransomware (opens in new tab), a Conti derivative that uses voidtools Everything for filesystem enumeration. The import table includes 12 Everything32.dll functions: Everything_QueryW, Everything_GetResultFullPathNameW, Everything_GetResultSize, and nine others. The Restart Manager API (RmStartSession, RmRegisterResources, RmGetList, RmShutdown) handles unlocking files held by other processes before encryption.
This build's internal name is payfast. The February 2026 variant from the healthcare incident reportedly uses the name "Cobalt" internally. Different RaaS configurations produce different internal names, ransom note filenames, file extensions, and contact addresses from the same builder.
SFX delivery chain
The self-extracting archive runs a command line:
7za.exe x -y -p2295124761281648206 Everything64.dll
Everything64.dll is not a DLL. It is a 7z archive encrypted with the password 2295124761281648206, containing:
| File | SHA256 | Purpose |
|---|---|---|
| ENC_*.exe | 2ae80e5b... | Pay2Key encryptor (analysed below) |
| DC.exe | c576f7f5... | AutoIt-compiled binary (not a decryptor) |
| xdel.exe | e8eaa39e... | Sysinternals SDelete (PDB confirms) |
| Everything.ini | 2fefb69e... | Everything configuration |
| Everything2.ini | 89ad2164... | Everything configuration |
Both .ini hashes match the IOCs in the Halcyon report. DC.exe checks the registry key Software\\AutoIt v3\\AutoIt and exits with code 1, suggesting it requires an AutoIt runtime dependency not present in the package.
Encryption scheme
Key generation
Each file gets a unique 32-byte ChaCha20 key. The key is generated byte-by-byte in a loop at 0x44e950:
xor esi, esi ; counter = 0
loop:
call fcn.0044dc40 ; generate one random byte
mov [ebp+esi-0x98], al ; store in key buffer
inc esi
cmp esi, 0x20 ; 32 bytes
jl loop
The call chain resolves to BCryptGenRandom(NULL, pbBuffer, cbBuffer, BCRYPT_USE_SYSTEM_PREFERRED_RNG). This is the Windows CNG cryptographic random number generator. The keys are not predictable.
ChaCha20 with null nonce
The encryptor initialises the cipher context at 0x452443:
xorps xmm0, xmm0 ; xmm0 = all zeros
movups [ebp-0xdc], xmm0 ; zero 16 bytes
movups [ebp-0xcc], xmm0 ; zero 16 bytes
movq [ebp-0xbc], xmm0 ; zero 8 bytes
The IV/nonce field within this structure is 12 bytes of zero. Every file encrypted by this binary uses a null nonce.
This is not a vulnerability. ChaCha20 is a stream cipher where the keystream depends on both the key and the nonce. Reusing a nonce with the same key allows XOR recovery of both plaintexts. But Pay2Key generates a unique 32-byte key per file. A null nonce with a unique key produces a unique keystream. The encryption is equivalent to using a random nonce with a random key: both produce an unrepeatable output.
The null nonce would be a fatal flaw only if the same key were reused across multiple files. That does not happen here.
Curve25519 key protection
Per-file ChaCha20 keys are protected with Curve25519 (X25519) ECDH key exchange. The OpenSSL NID 0x40a (1034) for EVP_PKEY_X25519 appears in the key setup function at 0x452514. The scheme:
- The operator's static Curve25519 public key is embedded in the binary's encrypted RCDATA resource (253.7 KB blob at
0x006000a4). - At runtime, a per-victim ephemeral Curve25519 keypair is generated.
- For each file, the 32-byte ChaCha20 key is encrypted using the ECDH shared secret derived from the operator's public key and the victim's ephemeral private key.
- The encrypted key record is appended to
C:\\temp\\session.tmp.
The decryptor (operator-side) reads session.tmp, uses the operator's Curve25519 private key with the victim's ephemeral public key to rederive the shared secret, and recovers each file's ChaCha20 key.
session.tmp stays on disk
session.tmp is written to C:\\temp via WriteFile at 0x4528c4 during encryption. Each file's encrypted key record is appended as it is processed. There is no network exfiltration of this file in the analysed build.
The ransom note instructs the victim to provide their "personal ID" via email. This ID likely encodes the ephemeral public key, though we did not verify the exact encoding. The operator needs this ID plus their own private key to decrypt session.tmp entries. If session.tmp is deleted or corrupted before the operator receives it, recovery is impossible for both parties.
For incident responders: preserve C:\\temp\\session.tmp immediately. It is the only file that links encrypted data back to recoverable keys. If law enforcement later seizes the operator's infrastructure and obtains the private key, session.tmp is what makes decryption possible.
Intermittent encryption and data recovery
Mode selection
A byte at offset 0x49 in the encryption context determines the mode:
| Value | Mode | Behaviour |
|---|---|---|
0x31 ('1') | Full | Entire file encrypted |
0x32 ('2') | Intermittent | Partial encryption with skip gaps |
0x33 ('3') | Intermittent (alt) | Smaller blocks for files under 10 MB |
The file size threshold is stored at offset 0x4a and shifted left by 20 bits (1 MB granularity). The Halcyon report states files under 2 MB are fully encrypted and files 2 MB or larger are intermittent.
Block sizes
The intermittent function at 0x450700 sets the encryption block size based on file size:
cmp byte [esi+0x49], 0x33 ; mode 3?
cmp dword [esi+0x10], 0xa00000 ; file >= 10 MB?
mov dword [ebp-0x70], 0x80000 ; block = 512 KB (small files, mode 3)
mov dword [ebp-0x70], 0x100000 ; block = 1 MB (large files or other modes)
The code structure indicates the first and last blocks of each file are encrypted. This would destroy file headers and footers, causing format-level recovery tools to fail on standard entry points.
Skip pattern
The distance between encrypted blocks is not fixed. It is computed from the per-file ChaCha20 key bytes using four floating-point constants:
| Address | Value | Role |
|---|---|---|
0x5e9d88 | 0.00001 | Odd-byte multiplier |
0x5e9d90 | 0.0001 | Even-byte multiplier |
0x5e9da0 | 0.6 | Distribution divider |
0x5e9db0 | 1.4 | Accumulator scaler |
The algorithm iterates over the 32 key bytes, multiplying each by the alternating constants and accumulating the result. The accumulated value, scaled by 1.4 and divided by 0.6, determines the skip offset between encrypted blocks. Because the key bytes differ per file, the skip pattern varies per file. But the encrypted-to-plaintext ratio is roughly consistent.
Plaintext recovery estimates (modeled)
| File size | Block | Encrypted (approx.) | Plaintext recoverable |
|---|---|---|---|
| 2 MB | 512 KB | 75% | 25% |
| 5 MB | 512 KB | 30% | 70% |
| 10 MB | 1 MB | 30% | 70% |
| 50 MB | 1 MB | 18% | 82% |
| 100 MB | 1 MB | 15% | 85% |
| 500 MB | 1 MB | 13% | 87% |
| 1 GB+ | 1 MB | 12.5% | 87.5% |
These estimates are based on the block sizes and segment calculation in the binary. They have not been verified against actual encrypted files. For files over 10 MB, the model suggests roughly 85% of the content is untouched.
Partial recovery targets
SQL databases, VHDX virtual disks, backup archives, and large document stores are the most recoverable targets. These formats store data in structured pages or blocks. With 85% of the content intact:
- SQL Server / PostgreSQL: Data pages in the middle of
.mdf/.ndffiles are likely intact. Table data can be carved from raw pages even without the header. - Hyper-V VHDX: The VHDX metadata and BAT (Block Allocation Table) in the header will be encrypted, but the bulk of the virtual disk data in the middle is plaintext. Tools that can parse raw NTFS from a known offset can recover files from inside the VM.
- Backup archives: Depending on the format, individual backup segments in the middle of the file may be intact and extractable.
The encrypted blocks are randomly distributed based on the key, so automated carving requires identifying the block boundaries. A recovery tool would need to scan for the transition between high-entropy (encrypted) and structured (plaintext) data at 1 MB intervals.
Conti/Mimic heritage
Pay2Key's encryptor is built on Mimic ransomware, which itself derives from the leaked Conti builder (opens in new tab). The lineage is visible in the service and process kill lists. The encryptor terminates 60+ services and 40+ processes before encryption, including:
Services: AcronisAgent, BackupExecJobEngine, CAARCUpdateSvc, DefWatch, MSSQLFDLauncher, Veeam*, ccEvtMgr, ccSetMgr, SQLWriter, sophos, MVArmor, PDVFSService
Processes: sqlservr, sqlagent, msaccess, mysqld, oracle, python, node, java, Raccine, Sysmon, xServer, QBDBMgr, Creative Cloud
The Everything.exe integration for file enumeration, the Restart Manager API for file unlocking, and the SDDL-based ACL manipulation all originate from the Mimic codebase. Pay2Key adds Curve25519 key exchange (replacing Conti's RSA), the intermittent encryption mode with key-dependent skip distances, and the session.tmp key escrow mechanism.
Assessment
The crypto primitives are well chosen. BCryptGenRandom produces unpredictable keys, ChaCha20 is implemented via OpenSSL's CRYPTOGAMS assembly, and Curve25519 key exchange is computationally infeasible to break. The null nonce is irrelevant with unique per-file keys. We found no implementation flaw in the code paths we analysed that would enable victim-side decryption.
The practical recovery paths:
- Intermittent mode gaps. Files over 10 MB retain roughly 85% of their content as plaintext. Structured formats like SQL databases and VHDX disks can yield significant data through raw carving.
- Memory forensics. If a memory dump is captured while encryption is still running, per-file ChaCha20 keys may be recoverable from the process heap. The Halcyon report noted approximately one hour for the active encryption phase in the February incident.
- Preserve session.tmp. If law enforcement seizes the operator's Curve25519 private key,
C:\\temp\\session.tmpis required for decryption. Without it, even the operator cannot recover files.
IOC summary
Host
| Indicator | Type | Context |
|---|---|---|
C:\\temp\\session.tmp | File path | Encrypted per-file key store |
C:\\temp\\Decrypt_files.txt | File path | Ransom note |
ueli.maurer@onionmail.org | Ransom contact | |
payfast | Internal name | Binary self-identification |
HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\AllowMultipleTSSessions | Registry | Terminal Server persistence |
HKLM\\system\\CurrentControlSet\\Control\\Terminal Server\\fSingleSessionPerUser | Registry | Terminal Server persistence |
Behavioural
| Indicator | Description |
|---|---|
| Everything32.dll imports | Filesystem enumeration via Everything API |
| BCryptGenRandom | Per-file key generation (BCRYPT_USE_SYSTEM_PREFERRED_RNG) |
| RmStartSession / RmGetList | Restart Manager file unlocking |
| Fake Avast WSC registration | NoDefender toolkit (separate components, not in encryptor) |
Related hashes (January 2026 SFX package)
| File | SHA256 |
|---|---|
| SFX loader | 5e1ba287113770184fb51f0faed1a851d5066fa263a67a463da17601de82cb5a |
| Encryptor (ENC_*.exe) | 2ae80e5bff8fc9055ce7dc60e59447cba6e6c3a215eea1b6de7d9cb5ae26f9e8 |
| Everything64.dll (encrypted payload) | c45b87fff769379ebb9f4708438e208ee134692a2392a987205bfe900cceacb1 |
| DC.exe | c576f7f55c4c0304b290b15e70a638b037df15c69577cd6263329c73416e490e |
| xdel.exe (SDelete) | e8eaa39e2adfd49ab69d7bb8504ccb82a902c8b48fbc256472f36f41775e594c |
| Everything.ini | 2fefb69e4b2310be5e09d329e8cf1bebd1f9e18884c8c2a38af8d7ea46bd5e01 |
| Everything2.ini | 89ad2164717bd5f5f93fbb4cebf0efeb473097408fddfc7fc7b924d790514dc5 |
NoDefender toolkit (July 2025 campaign, reused in February 2026)
| File | SHA256 |
|---|---|
| powrprof.dll | 1c70d4280835f18654422cec1b209eec856f90344b8f02afca82716555346a55 |
| powrprof.exe | a8bfa1389c49836264cfa31fc4410b88897a78d9c2152729d28eca8c12171b9e |
| wsc_proxy.exe | bd4635d582413f84ac83adbb4b449b18bac4fc87ca000d0c7be84ad0f9caf68e |
See also: Payload ransomware group: mutex MakeAmericaGreatAgain.