{
	"id": "e68e2a34-8db0-4d7a-94c0-4b5e883daf80",
	"created_at": "2026-04-06T00:10:24.175549Z",
	"updated_at": "2026-04-10T03:21:42.210421Z",
	"deleted_at": null,
	"sha1_hash": "1835e23d79ca2b35893c93341852b7071fec24ea",
	"title": "RansomEXX, Fixing Corrupted Ransom",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 4130065,
	"plain_text": "RansomEXX, Fixing Corrupted Ransom\r\nBy Brenton Morris\r\nPublished: 2021-10-02 · Archived: 2026-04-05 17:48:51 UTC\r\nSince the sudden disappearance of the REvil ransomware operation, there has been a rise in other “ransomware as\r\na service” (RaaS) operators attempting to claim their piece of the RaaS market share left behind. Among the most\r\nprominent of these groups is RansomEXX / RansomX. They have become infamous not only for their high-profile\r\nattacks, but also for the leak site they use to name and shame their victims who don’t adhere to their ransom\r\ndemands, and for their deployment of ransomware payloads for both Windows and Linux devices.\r\nBased on the high number of recent attacks by this group, the Profero IR team has encountered multiple\r\nransomware cases involving the Linux variant of this malware. During some of these incidents, we analyzed the\r\nransomware and a version of its decryption tool and discovered a bug in the encryption process that left some files\r\ncorrupted and unable to be decrypted by the tool.\r\nIn the following report, we describe how this ransomware and the decryption tool work — and how some\r\ncorrupted files can potentially be rescued. We also introduce a new tool that can be used to extract the decryption\r\nkey information from the Linux version of the decryption tool provided by the attackers and then use that\r\nconfiguration to decrypt affected files. We hope that this tool will remove the need to reverse engineer the\r\nattacker’s decryption tool during an incident and make for a speedier recovery.\r\nThe source code of the tool is publicly available here.\r\nRansomware Analysis\r\nSummary\r\nRansomEXX has the ability to recursively encrypt files in a list of provided directories using symmetric\r\nencryption (AES-CBC). Each file is appended with a header containing information encrypted with an RSA public\r\nkey — such as the AES key and IV values — so that they can be decrypted. Additionally, this header is\r\nregenerated roughly every 0.18 seconds along with a new AES key and IV to prevent decrypting all files with a\r\nkey and IV recovered by analyzing memory dumps taken from an infected machine. If two files are encrypted\r\nwithin the same 0.18 second period, they will be encrypted with the same key.\r\nThe malware appears to be specifically compiled for each attack, with the target organization’s name included in\r\nthe embedded ransom note, making it harder to share samples publicly. There is also an unused config value\r\ncontaining file extensions which indicate this malware can also be compiled to run on Windows. The use of the\r\nmbedTLS library also supports this conclusion, as it can be compiled for various target platforms.\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 1 of 23\n\nThere is no persistence method enabled in this ransomware and it runs as a standalone command line tool which\r\ncan be executed on the victim machines as part of a multi-staged attack.\r\nOverview\r\nThe analyzed samples were not packed or stripped, making our analysis easier as we can see the original function\r\nnames used by the author. The malware uses the mbedtls library for encryption capabilities:\r\nExecution Flow\r\nWhen initiated, the malware first loads the ransomware config with the ConfigLoadFromBuffer function and\r\nthen calls the GeneratePreData function:\r\nThe GeneratePreData function (pictured below) carries out the tasks of setting up the mbedtls context, including\r\ngenerating a random seed using the current time as personalization data to add extra entropy and generating the\r\n“ransom header” which contains RSA encrypted initialization information for the encryption such as IV and key\r\nused. This “header” is appended to each encrypted file so that it can be decrypted:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 2 of 23\n\nNext, the malware starts a thread to re-run the above function every 0.18 seconds (180,000 microseconds). Note\r\nthat inside the GeneratePreData function a mutex is acquired to prevent the context from changing while in use.\r\nThis means there is no guarantee that it will regenerate any of these values on time. This is likely used to ensure\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 3 of 23\n\nthat any key recovered from a memory dump would only be able to decrypt a small number of the most recently\r\nencrypted files.\r\nOnce this thread is running the main work begins: the malware loops through a list of directories passed to it by a\r\ncommand line and calls the EnumFiles function on each.\r\nFrom here, the malware initializes the same number of worker threads as the system has processors, and it is these\r\nworker threads that handle the actual encryption of each file. The encrypt_dir function is then called.\r\nThe encrypt_dir function loops through the directory recursively, creating the ransom note inside each directory\r\nand assigning each file discovered to a worker thread, which then perform the encryption. This function skips\r\ncalling itself on the current directory or the parent directory, and does not encrypt any ransom notes. Interestingly,\r\nthis function does not make use of the list of file extensions in the config item with index 11, which appears to be\r\na list of file types to skip when encrypting. Instead, it encrypts every file it locates that is not a ransom note.\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 4 of 23\n\nA high-level view of the function calls made when the malware starts can be seen below:\r\nPress enter or click to view image in full size\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 5 of 23\n\nConfiguration\r\nThe malware configuration is stored in a list of dynamically sized items. Each item contains the following\r\nelements:\r\nThis data structure is parsed by the malware in the ConfigLoadFromBuffer function and stored in an easily\r\naccessible global config structure to be used during runtime:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 6 of 23\n\nBy storing the config values in this way, the malware author has applied some very basic obfuscation and hidden\r\nthe code that references these values from the disassembler, lengthening the time required to analyze this sample.\r\nThe malware config contains the following values encoded in this way, as seen below. Blank values are currently\r\nunknown or unused\r\nPress enter or click to view image in full size\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 7 of 23\n\nSome of these config values are not used in this binary. This suggests the malware is written using a modular\r\ndesign, which allows the attackers to turn features on or off at compile time. Along with the fact that the malware\r\ncontains references to the victim organization in the ransom note, this indicates that the malware is compiled for\r\neach individual attack.\r\nEncryption Process\r\nWhen a worker thread receives a file path to encrypt, it calls the CryptOneFile function. This function oversees\r\nthe target file’s encryption in AES CBC mode using a key size of 256 bits. Each file is appended with the “ransom\r\nheader” generated in the GeneratePreData function.\r\nThe ransomware encrypts files using a rolling window which moves through the file in a manner which depends\r\non which CryptLogic values the malware is using for that particular file.\r\nA CryptLogic is a set of values which determine how a file should be encrypted or decrypted in blocks. The\r\ndecrypt logic to use for a given file is determined by its size in bytes. Each CryptLogic is a struct with the\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 8 of 23\n\nfollowing C definition:\r\nstruct CryptLogic {\r\nuint64_t lowerLimit;\r\nuint64_t upperLimit;\r\nuint64_t chunkSize;\r\nuint64_t blockSize;\r\n};\r\nThe lowerLimit value is the lower limit of files to be encrypted/decrypted with the contained chunkSize and\r\nblockSize values while the upperLimit is the upper limit for the file size.\r\nThe chunkSize is the number of bytes which are read, encrypted/decrypted and then written back to one affected\r\nfile at a time, while the blockSize is the number of bytes in the file after each chunk is encrypted/decrypted. In the\r\nsample analyzed, the blockSize is larger than the corrosponding chunkSize, so the malware will only partially\r\nencrypt affected files but it is still enough to render the files unusable.\r\nA description of each value in the CryptLogic is below:\r\nPress enter or click to view image in full size\r\nAfter the CryptOneFile function has appended the encrypted header to a file it calls the\r\nProcessFileHandleWithLogic function — which will get the correct crypt logic values to use — it then works its\r\nway through the file using the method described above:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 9 of 23\n\nIf successful, the ransomware will then rename the encrypted file to indicate it has been encrypted:\r\nPress enter or click to view image in full size\r\nA high-level overview of the function calls made by the encrypt_worker thread can be seen below:\r\nPress enter or click to view image in full size\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 10 of 23\n\nDecryption Tool Analysis\r\nSummary\r\nThe decryption tool is able to recursively decrypt files in a list of provided directories using AES in CBC mode.\r\nEach encrypted file contains a header with information required to decrypt, such as the AES key and IV values\r\nused to encrypt the file. This header is read and the key and IV are decrypted, and then removed from the file.\r\nSubsequently, the file is decrypted, and returns to its original state.\r\nGet Brenton Morris’s stories in your inbox\r\nJoin Medium for free to get updates from this writer.\r\nRemember me for faster sign in\r\nDue to failure to acquire a lock on the file, it is possible that while the file is being encrypted it is in use by the\r\nsystem and being written to in parallel. This would lead to a file corruption, with encrypted data mixed in with\r\nunencrypted data or with extra data being appended to the file after the encrypted header — causing the\r\ndecryption tool to fail to obtain the correct keys to decrypt the file. We encountered several log files that were\r\npartially corrupted due to this flaw. This presence of this flaw could mean that even after paying a ransom to the\r\nattackers, victim organizations would not be able to recover some files.\r\nOverview\r\nThis file is not packed or stripped and uses the mbedTLS library for AES decryption:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 11 of 23\n\nExecution Flow\r\nThis file looks very similar to the ransomware component analyzed in this post.\r\nWhen comparing the two files we can see that there are only a small number of different functions between these\r\nsamples.\r\nIt starts off with the main function similar to the ransomware component without the call to GeneratePreData or\r\nthe creation of the regenerate_pre_data worker thread. It loads the ransomware config from a buffer using the\r\nexact same method documented in the ransomware analysis above, and then calls EnumFiles on each directory\r\npassed in via the command line args:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 12 of 23\n\nEnumFiles is identical to the ransomware component’s EnumFiles function. It creates a pool of worker threads\r\nequal to the number of the victim machine’s CPUs using the init_workers function, and then calls encrypt_dir,\r\npassing the target directory path as the only parameter:\r\nThe encrypt_dir function is almost identical to the function in the ransomware component with the same name, it\r\nloops through all subdirectories recursively and assigns each file found to a worker thread. The only difference\r\nhere is that this function removes the ransom note instead of dropping one, this can be seen in the picture below:\r\nPress enter or click to view image in full size\r\nRansomware encrypt_dir function compared to the decryption tool.\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 13 of 23\n\nConfiguration\r\nThe configuration provided with the decryption tool contains everything it needs to decrypt affected files.\r\nThe decryption tool uses the exact same encoding mechanism for its config values as the ransomware component\r\nitself, but this time using a lot more config values:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 14 of 23\n\nThe configuration contains the following encoded values:\r\nPress enter or click to view image in full size\r\nDecryption Process\r\nThe decryption tool worker threads are almost identical to the workers in the ransomware, except that they call\r\nDeCryptOneFile when they receive a path to decrypt, while the ransomware calls CryptOneFile:\r\nPress enter or click to view image in full size\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 15 of 23\n\nThe DeCryptOneFile function calls the DeCryptOneFileEx function and then removes the file extension that\r\nwas added to the file during encryption:\r\nThe DeCryptOneFileEx function reads the encryption information stored in the “ransomware header” at the end\r\nof the file and ensures that it parses correctly. Then it truncates the file to remove the added header:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 16 of 23\n\nIt then calls the ProcessFileHandleWithLogic function, instructing it to use the DeCryptOneBlock function to\r\ndecrypt the file block by block. This function decrypts files in the same way the ransomware encrypted them,\r\ncalculating which crypt logic configuration to use based on the original file size.\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 17 of 23\n\nThe DeCryptOneBlock function is a simple function which decrypts one 16-byte chunk of a file:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 18 of 23\n\nFiles Failing to Decrypt\r\nWhen running this decryption tool on a directory of files, you may find that some files do not decrypt but no\r\nvisible error is shown. This is due to the bug in the encryption process — files that are being written to at the time\r\nof the encryption may be corrupted, especially if the ransomware has already added the “header.” This happens\r\nbecause the ransomware does not lock the files to prevent other applications from writing to them during\r\nencryption.\r\nThis can be seen in the following screenshot. Above the line highlighted in red is encrypted data, below is the\r\nlegitimate log data.\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 19 of 23\n\nWhen the decryption tool attempts to decrypt a file, it reads the RSA encrypted AES key and IV from the end of\r\nthe file, parsing the unencrypted log data that was appended as a blob of RSA encrypted data. This causes the call\r\nto mbedtls_rsa_pkcs1_decrypt to fail. This is demonstrated below — note the return value in rax is non-zero\r\nright after the call to mbedtls_rsa_pkcs1_decrypt:\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 20 of 23\n\nThe decryption tool does not report this error to the user and instead will silently fail and move on to the next file.\r\nRecovering the Corrupted Files\r\nDue to the above bug in the encryption process, some files encrypted by this malware could have been written to\r\nby a legitimate application during the encryption process, corrupting the file. If the nature of this corruption is\r\nsimple, such as ASCII log file data being appended after the encrypted portion of the file, a file can be easily\r\nrecovered.\r\nDuring encryption, the malware will append each file with RSA encrypted key information required to decrypt a\r\nfile once a ransom is paid. When a file is being decrypted this information is read from the end of the file,\r\ndecrypted with the RSA private key, and then used to decrypt the file. For decryption to work in the case that\r\nlegitimate data has been appended after the key information we need to truncate the file to remove this data,\r\ndecrypt the file, and then append the data previously truncated.\r\nIn the example below the file would need to be truncated to 0x000013b8 bytes in size. The decryption tool will\r\nthen run correctly.\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 21 of 23\n\nIf the nature of the corruption is more complex than the above example it may still be possible to recover the file\r\nby untangling the encrypted and unencrypted data and then splicing it back together in the correct order but if the\r\nlegitimate file data was high entropy data (such as an encrypted file) this would likely be impossible.\r\nConfig Extractor and Decryption Tool\r\nBecause the attackers provide paying victims with a decryption tool they must run to decrypt their files there is a\r\nrisk that the decryption tool may be malicious. This requires affected victims to reverse engineer the provided\r\ndecryption tool to ensure there is no hidden payload or malicious features, a time investment that can be\r\nproblematic for some organizations during a ransomware incident. Due to this we decided to write our own\r\nimplementation of the Linux decryption tool which can be used to carry out the following tasks:\r\nExtract the config required to decrypt files from a Linux decryption tool provided by the attackers\r\nUse this config to decrypt files encrypted by the Linux version of RansomEXX\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 22 of 23\n\nToday we are releasing this tool as an open-source command-line application written in Go. Its usage is as\r\nfollows:\r\nUsage of ./ransomexx-tools:\r\n-config string\r\nPath of the extracted config file to use for decryption\r\n-debug\r\nLog debug output\r\n-decrypt\r\nDecrypt a list of directories\r\n-decryption-tool string\r\nPath to the decryption tool to extract the config from. Required when using -exconfig\r\n-dirs string\r\nA list of directories to recursively decrypt, separated by a comma\r\n-exconfig\r\nExtract the config from a decryption tool provided by the RansomEXX group\r\n-num-workers int\r\nNumber of workers to use for decryption (default 4)\r\n-out string\r\nThe file to save the extracted config to.\r\nThis tool can be found on our GitHub here: proferosec/RansomEXX-Tools (github.com)\r\nExtracting the Config\r\nTo extract the config containing all decryption key information from a decryption tool provided by the attackers\r\nsimply run the tool with the following parameters:\r\n./ransomexx-tools -exconfig -decryption-tool /path/to/attcker/provided/decryption-tool -out config.json\r\nYou will then have a file in the current directory named config.json with the extracted configuration values.\r\nDecrypting Files\r\nOnce the config has been extracted you can use this tool to decrypt your files instead of the attacker-provided\r\ndecryption tool. Run the tool with the following parameters:\r\n./ransomexx-tools -decrypt -config config.json -dirs /path/to/decrypt,/second/path/to/decrypt\r\nThe -decrypt mode takes the path to the config file in -config and a comma-separated list of directories to\r\nrecursively search for files to decrypt in the -dirs parameter.\r\nSource: https://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nhttps://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701\r\nPage 23 of 23",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"Malpedia"
	],
	"references": [
		"https://medium.com/proferosec-osm/ransomexx-fixing-corrupted-ransom-8e379bcaf701"
	],
	"report_names": [
		"ransomexx-fixing-corrupted-ransom-8e379bcaf701"
	],
	"threat_actors": [],
	"ts_created_at": 1775434224,
	"ts_updated_at": 1775791302,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/1835e23d79ca2b35893c93341852b7071fec24ea.pdf",
		"text": "https://archive.orkl.eu/1835e23d79ca2b35893c93341852b7071fec24ea.txt",
		"img": "https://archive.orkl.eu/1835e23d79ca2b35893c93341852b7071fec24ea.jpg"
	}
}