Skip to content

Kyber ransomware is not just post-quantum name-dropping

Kirk
13 min read
malwareransomwarekyberreverse-engineeringencryptionrust
On this page

Kyber ransomware sounds like post-quantum branding until the crypto starts lining up.

The ransom note says the files were encrypted with AES-256-CTR, and that X25519 plus Kyber1024 were used for key generation. That could have been branding. Ransom notes are full of borrowed cryptography words.

This sample is not that. Local analysis confirms a Rust ransomware build with AES-CTR-style file encryption, Kyber1024-sized encapsulation material, active Curve25519/X25519 arithmetic, HMAC-SHA256-style key and IV derivation, and a fixed 0x744 trailer on every encrypted file.

The recovery result is blunt. Instrumented analysis recovered a fixture key and IV and decrypted a seeded test file, which validates the model. That is not a reusable decryptor. From the sample and encrypted files alone, local analysis did not find a practical recovery path.

The short version: the note is not empty post-quantum dressing. The code and file format both point to real hybrid crypto.

If you operate a threat intelligence platform with API access and can provide a researcher account, please reach out to [email protected]. Additional data sources directly increase the quality and coverage of the threat intel published here.


Public reporting

Rapid7 published a side-by-side Kyber analysis (opens in new tab) from a March 2026 incident response case. They recovered two payloads in the same environment: a VMware ESXi encryptor and a Windows file-server encryptor. The samples shared a campaign ID and Tor infrastructure, but not the same cryptographic reality.

The ESXi note claimed AES, X25519, and Kyber. Rapid7 found ChaCha8 with RSA-4096 key wrapping instead. The Windows line is different: the Rust variant implements the advertised Kyber1024 and X25519 key-protection path while AES-CTR handles bulk file encryption.

This post focuses on the older Windows sample 4ed176edb75ae2114cda8cfb3f83ac2ecdc4476fa1ef30ad8c81a54c0a223a29. The contribution here is the file-format and runtime proof: the 0x744 trailer, the 0x620 Kyber-sized field, the AES counter handling, and the fixture decryption check.

BleepingComputer reported (opens in new tab) that, as of April 22, 2026, it found one listed victim on the Kyber extortion portal: a large American defense contractor and IT services provider. PCrisk had also documented (opens in new tab) the .#~~~ extension and READ_ME_NOW.txt ransom note in December 2025, which lines up with Kyber being visible before the March 2026 Rapid7 case.

Sample overview

FieldValue
Sample4ed176edb75ae2114cda8cfb3f83ac2ecdc4476fa1ef30ad8c81a54c0a223a29.exe
Triage run251018-c56cbag16d (opens in new tab)
SHA2564ed176edb75ae2114cda8cfb3f83ac2ecdc4476fa1ef30ad8c81a54c0a223a29
MD518498b1ff111ee9d9a037c280f75b720
SHA10e9a47782e39741a2c161bf639252d33ad3a428a
TypePE32+ Windows x64 console executable
Size1,907,200 bytes
PDB hintencrypt.pdb
Encrypted extension.#~~~
Ransom noteread_me_now.txt

The binary carries Rust module strings that match the job it performs: encrypt::crypto, encrypt::walker, encrypt::csprng, encrypt::icons, and encrypt::services.

The dependency strings are also direct:

Crate stringWhy it matters
pqc_kyber-0.7.1Kyber implementation path
curve25519-dalek-4.1.3Curve25519 arithmetic path
aes-0.8.4AES implementation path
sha2-0.10.8SHA/HMAC-style derivation support
rayon-1.10.0 / crossbeam-channel-0.5.13threaded file processing

Those strings alone would not be enough. Rust binaries can drag in unused code. The proof is that runtime probes hit the key paths during file encryption.

What the encryptor does

The controlled run reached normal ransomware behavior.

It wrote ransom notes, registered the encrypted-file class, wrote a custom icon, logged its own thread pool and random-number setup, and launched the usual recovery-inhibition commands. Encrypted files used the .#~~~ extension.

Host changes included:

AreaObserved behavior
Ransom noteread_me_now.txt written to drive and user roots
File classHKCR\.#~~~, HKCR\fucked.file, HKCR\fucked.file\DefaultIcon
IconC:\fucked_icon\processed_file.ico
Shadow copiesvssadmin, PowerShell WMI deletion, and wmic SHADOWCOPY DELETE command launches
Recovery settingsbcdedit recovery changes and wbadmin system-state backup deletion
Logswevtutil cl event-log clearing loop
Servicespatterns for sql*, msexchange*, vss*, backup*, and veeam*

Ransom note scope

The ransom note provides the operator contact points:

TypeEndpoint
Chatmlnmlnnrdhcaddwll4zqvfd2vyqsgtgj473gjoehwna2v4sizdukheyd[.]onion/chat/f9e1d038b1f5220e888b56e97881937f
Blogkyblogtz6k3jtxnjjvluee5ec4g3zcnvyvbgsnq5thumphmqidkt7xid[.]onion

The extracted note path was C:\fucked_icon\READ_ME_NOW.txt. The note itself is weirdly useful because it advertises the same crypto stack the binary later backs up, while also sounding like someone ran a standard double-extortion script through a bored group chat. The section headers are doing a lot of accidental comedy: ??WE HAVE A FLASH DRIVE WITH BACKUPS ON THE ADMIN'S NECK??, ??CAN WE TRUST HACKERS??, and ??WHAT ABOUT THE ANONYMITY?? are not subtle.

/
#  Hello, if you are seeing this then you have been attacked by Kyber Ransomware.
\

 <=> Your files are encrypted with the AES-256-CTR algorithm.
     >--  (Explanation) https://en.wikipedia.org/wiki/Advanced_Encryption_Standard

 <=> Two asymmetric algorithms X25519 and Kyber1024 were used for key generation.
     >--  (Explanation) https://en.wikipedia.org/wiki/Curve25519
     >--  (Explanation) https://en.wikipedia.org/wiki/Kyber

 <=> Keys are created from several random sources, so do not hope that you will return the files without our help
     >--  (Explanation) https://en.wikipedia.org/wiki//dev/random
     >--  (Explanation) https://en.wikipedia.org/wiki/RDRAND
     >--  (Explanation) https://en.wikipedia.org/wiki/HKDF

(??WE HAVE A FLASH DRIVE WITH BACKUPS ON THE ADMIN'S NECK??)
>========================================================================================
> In addition to encrypting files, a lot of data has been downloaded from your network.
> If you don't write to us, within a week or two your name will end up on our
> blog with example of important data.
>========================================================================================

(??CAN WE TRUST HACKERS??)
>========================================================================================
> If you come to our chat room, you can count on free decryption for three small files.
> and examples of the downloaded data.
>========================================================================================

(??WE DON'T HAVE VALUABLE DATA??)
>========================================================================================
> We take a responsible approach to doing our job.
> We have probably downloaded a lot of personal information from your servers, and could
> cause you HUGE problems by publishing it.
# Documents such as payroll, statements, contracts and others may contain valuable data,
# the publication of which could lead to lawsuits.
>========================================================================================

(??WILL THE POLICE HELP??)
>========================================================================================
> DO NOT try to call the police as they will not save you from
> publishing your data, nor will they help you get your files back,
> they will only ban you from paying.
>========================================================================================

(??WHAT IF I TRIED TO TRICK YOU???)
>========================================================================================
> DO NOT modify the files, you may damage them and make it so
> we can't help you.
>========================================================================================

(??WHAT ABOUT THE ANONYMITY??)
>========================================================================================
> We create unique links to anonymous chat for each company.
> you don't have to worry, all the details of our deal will be kept secret.
> We also have alternative ways to contact us if you are worried and do
> not want to write in the panel.
>========================================================================================

HOW TO CONTACT US:
  <=> Download Tor Browser (https://www.torproject.org/download)
  <=> Open it
  <=> Follow this link: hxxp[:]//mlnmlnnrdhcaddwll4zqvfd2vyqsgtgj473gjoehwna2v4sizdukheyd[.]onion/chat/f9e1d038b1f5220e888b56e97881937f
  (Also maybe you would like to visit our blog? Don't be shy!)
  <=> Blog: hxxp[:]//kyblogtz6k3jtxnjjvluee5ec4g3zcnvyvbgsnq5thumphmqidkt7xid[.]onion

The file format

Each encrypted output has a simple top-level shape:

encrypted body || 0x744-byte trailer

The trailer is the useful part. It is fixed-size, starts with a four-byte marker, and then holds the metadata needed for attacker-side recovery.

Trailer offsetSizeContent
0x000 to 0x0034magic bytes e1 2f a8 c3
0x004 to 0x1030x100AES-wrapped metadata
0x104 to 0x7230x620Kyber1024-sized material
0x724 to 0x7430x20plaintext Curve25519/X25519-derived tail

Keep the two sizes separate. 0x620 is the Kyber1024-sized field inside the trailer. 0x744 is the full appended trailer.

The controlled run produced 12 encrypted internal test fixtures. They are not public IOCs; they are included here only to show the fixed trailer size. Every output was original size plus 0x744. The budget-2026.xlsx fixture, for example, started as 24,576 bytes and became 26,436 bytes:

Internal fixtureOriginal sizeEncrypted sizeDelta
budget-2026.xlsx.#~~~24,57626,4360x744
customer-list.csv.#~~~8,19210,0520x744
quarterly-planning.docx.#~~~32,76834,6280x744

Final write watches also saw 0x744 trailer buffers being passed to NtWriteFile. These buffers began with e12fa8c3, the little-endian form of 0xc3a82fe1.

That ties the trailer to the ransomware's write path. It is not a parsing mistake from dumped files.

AES-CTR, with a metadata wrinkle

The sample derives two named fields:

FieldSizeFirst watched value
encryption-key0x20 bytesfcca04669f1a9c79786e29914563c772584fba1aebc58ce1fd17c8e11a1266ea
encryption-iv0x10 bytesdf2dba375800d76695d5ca37e5c72a50

The labels are not only strings in the binary. Runtime watches show encryption-key and encryption-iv being expanded by HMAC-SHA256-style code. The setup function builds inner and outer SHA256 pad states, then the label expansion function appends the field label and counter byte before finalizing.

The 32-byte key is passed into the AES key schedule at 0x1400628c0. The AES stream routine at 0x140001000 XORs generated keystream against the target buffer, which is the CTR-style shape expected from the ransom note's AES-256-CTR claim.

The IV handling is worth spelling out in plain English:

  • the first eight IV bytes are stored as-is in the AES counter state
  • the second eight IV bytes are byte-swapped before storage
  • the counter starts at zero for the trailer metadata wrap
  • body encryption starts at counter 0x10

That last point is the wrinkle. The first 0x100 bytes of trailer metadata consume 16 AES blocks. The file body then continues from counter 0x10, rather than restarting at zero.

The local verifier confirmed the model. Using the watched key and IV, it decrypted the budget fixture metadata and body. The metadata field at raw offset +0x08 decrypted to 0x6000, matching the 24,576-byte body size. The body decrypted back to the fixture's 0x42 fill bytes.

That is a strong validation check. It is not a victim-facing break, because the key and IV came from instrumented execution.

The Kyber part is real

The sample embeds a Kyber1024-sized public key in .rdata.

FieldValue
Address0x1401526eb
Size0x620 / 1,568 bytes
SHA2561b66614d63ce9f1b0b9f68464a93d826a3af7e08ccadcbc662f8444f0eaab6b9

A Rust lazy initializer copies that key into runtime state. Runtime watches then show the key pointer and 0x620 length being passed into the crypto path for each file.

The binary also contains Kyber-specific error strings:

StringWhy it matters
Error when trying to calc Kyber (ciphertext, shared_secret)names the Kyber encapsulation result shape
Invalid public key sizesupports public-key validation logic

The per-file trailer also has a 0x620 region at offsets 0x104 to 0x723. That size matches Kyber1024 public key and ciphertext material. The field is copied as one contiguous region before the final trailer is written.

Size alone is not the whole argument. The runtime public-key pointer, Kyber crate path, Kyber error strings, 0x620 length checks, and trailer layout all point in the same direction.

The X25519 side

No literal x25519 or montgomery string survived in this build. The Curve25519 evidence is in the code and constants.

The binary contains the source path string curve25519-dalek-4.1.3/src/scalar.rs. More importantly, the active crypto path reaches Curve25519-style field arithmetic at runtime.

Local anchors:

EvidenceMeaning
0x14017f960 contains little-endian 0x1db42 / 121666Curve25519 Montgomery ladder constant variant
Function 0x1400bea00 uses 0x7ffffffffffff51-bit Curve25519 limb mask
Runtime reaches 0x14002d09b -> 0x1400bea00 with rdx=0x14017f960active arithmetic path during encryption
Trailer 0x724 to 0x743 equals raw builder bytes before and after metadata wrappingplaintext 32-byte Curve25519/X25519-derived tail

For file format work, the 0x20 tail matters because it is not part of the AES-wrapped 0x100 metadata area. It remains readable in the final trailer.

It is also separate from the 64-byte key-derivation input used to derive the AES key and IV. The KDF input is built from two 32-byte pieces, then fed into the HMAC-SHA256-style expansion.

No decryptor path in this sample

The binary can parse existing 0x744 trailers. That is not the same as decrypting them.

The parser at 0x1400221a0 splits the trailer into fields:

Final trailer fieldParsed destination
+0x004 to +0x103parsed +0x008
+0x104 to +0x723parsed +0x108
+0x724 to +0x743parsed +0x728
magicparsed +0x748

The caller checks the magic and routes valid encrypted files into already-encrypted handling. It does not decapsulate Kyber, derive victim AES keys from the trailer, or decrypt the file body.

Static command strings show win_encryptor, path, hyperv, and system. No decrypt or recover mode was found. The File unlocked successfully strings belong to file locking and opening behavior, not cryptographic recovery.

The clean read: this sample is the encryptor. Recovery would need a separate decryptor or service holding private material.

Recovery limits

Local break attempts did not expose a practical decryptor from the sample and encrypted files alone. The trailer does not store plaintext AES key or IV. No embedded private key was found. Across the 12 unique fixed-run encrypted outputs, there was no observed AES key/IV reuse, no repeated aligned 16-byte trailer blocks, and no constant-XOR body prefix hit once duplicate dumps were excluded.

The fixture key/IV recovery is still important. It proves the analysis is reading the AES state correctly. It does not turn into a general decryptor unless the same key material can be recovered from a real victim environment during execution.

That is the line between validating the scheme and breaking it.

Detection shape

The strongest hunt is the combination:

SignalWhy it matters
Rust PE32+ x64 console binary with encrypt.pdbbuild identity
pqc_kyber-0.7.1, curve25519-dalek-4.1.3, aes-0.8.4 stringscrypto stack
.#~~~ encrypted extensionfile impact marker
0x744 trailer beginning e1 2f a8 c3encrypted file format
trailer 0x104 to 0x723 is 0x620 bytesKyber1024-sized material
read_me_now.txtransom note name
C:\fucked_icon\processed_file.icocustom encrypted-file icon
HKCR\.#~~~ and HKCR\fucked.filefile class registration
recovery-inhibition commands via vssadmin, wmic, bcdedit, wbadmin, wevtutilransomware impact path

Compact indicators:

TypeValue
Sample SHA2564ed176edb75ae2114cda8cfb3f83ac2ecdc4476fa1ef30ad8c81a54c0a223a29
Ransom note SHA256ef054d22823758290db94aab3c901471a9ebd633f94963030806cc68dd433d8d
Icon SHA2565a5f2bfea416f4b9ed4e6e45d82df524c1d9fa5f99c08944f2bacdf5bf9f525d
Embedded Kyber1024 public key SHA2561b66614d63ce9f1b0b9f68464a93d826a3af7e08ccadcbc662f8444f0eaab6b9
Extension.#~~~
Trailer size0x744
Trailer magice12fa8c3
Chat onionmlnmlnnrdhcaddwll4zqvfd2vyqsgtgj473gjoehwna2v4sizdukheyd[.]onion
Blog onionkyblogtz6k3jtxnjjvluee5ec4g3zcnvyvbgsnq5thumphmqidkt7xid[.]onion

Kyber ransomware is crude around the edges. The icon path is ugly, the class name is ugly, and the note reads like every other pressure script with a Tor link. The crypto work is the part worth taking seriously.

For defenders, the read is simple: hunt the extension, the trailer, the Rust crypto strings, and the recovery-inhibition behavior. For recovery, do not assume the Kyber name is empty marketing. In this sample, the scheme is real enough that the encryptor alone did not give up the files.

Share this article