PClock turns your WordPress blog into a malware command center
Over the past five months our malware research team has been tracking the evolution of the PClock ransomware family, which started out as a rather simplistic CryptoLocker copycat; but, has since significantly evolved. In this post, we want to take a closer look at the technical aspects of the encryption used by the latest variants. We will also explore how the malware author turns vulnerable WordPress blogs into C2 servers (short for “command and control servers”) by use of a malicious WordPress plugin.
Shortly after we broke the very first PClock version and released a decrypter, the malware author switched to a new encryption scheme. The new scheme is now used by all PClock variants. It is based on a per-infection key that is generated during the first run by concatenating the return values of various Windows functions.
The resulting string will look something like this:
12:15:19 PM 2416 3464 1376256 0 262292 65556 590762 65672
The parts that compose this string in order are:
- Time the key was generated
- Return value of the GetCurrentThreadID function
- Return value of the GetCurrentProcessID function
- Return value of the GetProcessHeap function
- Return value of the GetActiveWindow function
- Return value of the GetClipboardOwner function
- Return value of the GetDesktopWindow function
- Return value of the GetForegroundWindow function
- Return value of the GetShellWindow function
The final per-infection key is then generated by hashing the string using the SHA-256 algorithm. The per-infection key in this specific example would be dbbff5ce8b1d8e58e28346b0ebbb9a70c7d04e05f10a803bff9539d4e6e044ed. The malware will then send this per-infection encryption key to its C2 server. If the server returns that the per-infection key has been saved properly, the malware will continue to encrypt the victim’s files.
Files are encrypted by 16384 byte blocks using the RC4 algorithm. Each block uses a different per-block key that again is generated by hashing a string using the SHA-256 algorithm. Now the string contains the per-infection key, the file’s full path, and the block index. For example, if the malware wants to encrypt the first 16384 byte block of a file named “C:\MyDocument.doc” the per-block key would be the SHA-256 of the string “dbbff5ce8b1d8e58e28346b0ebbb9a70c7d04e05f10a803bff9539d4e6e044edC:\MyDocument.doc1”. For the second block of the file, the string used to calculate the key would change to “”dbbff5ce8b1d8e58e28346b0ebbb9a70c7d04e05f10a803bff9539d4e6e044edC:\MyDocument.doc2” and so on. The malware encrypts every block within the first megabyte of the file in this way. After that, only every 17th block of the file is encrypted. If there are less than 17 blocks remaining in the file, it will start encrypting every block again. Any trailing bytes that don’t add up to a full block will also be encrypted with a key derived from the per-infection key and the file name, essentially dropping the block number from the equation.
One interesting aspect of the SHA-256 implementation the malware uses is the fact that it internally operates on ANSI strings. Many non-English users will have files on their system that use file names which contain characters that aren’t part of the normal ANSI character set and PClock itself uses Unicode strings internally everywhere. Rather than performing a proper string conversion from Unicode to ANSI, the malware will simply cast every Unicode character into an ANSI character thus effectively dropping the higher level byte of the Unicode character.
After all files have been encrypted, the malware will securely delete the per-infection key from the victim’s system, meaning that only the malware’s C2 server has a copy of the per-infection key used to encrypt the victim’s files.
The PClock C2 server
Given the complexity of the new encryption scheme used by PClock, you may ask yourself how we were able to decrypt any files at all. The answer is simple: The malware author has been using hacked web servers to host his entire C2 infrastructure. While it surely is a cost effective way to get your malware campaign going, there are a few disadvantages. First, you don’t necessarily have access to the entire server, so you may be unable to fix the insecure configuration that allowed you to break into the web server to begin with. However, your C2 server software may also end up in the hands of malware researchers like us that can take a closer look at them.
The very first variants using the new encryption scheme used a simplistic C2 PHP script that didn’t check if you actually paid when you requested the decryption key. Our friend Nathan at BleepingComputer used this flaw to provide a small patcher that tricks the malware into thinking that the user paid, triggering the malware to ask the C2 server for the key to decrypt the victim’s files. The malware author quickly updated the server side scripts to add a check to make sure the user actually paid:
This was the first of many flaws. When examining the code closely you will see that the key is read from the “keys” sub-directory. Knowing that, we could simply guess the file names of the keys and download them directly. All we needed was a list of Bitcoin addresses generated by the malware, which the malware author conveniently left for us on the server in the form of a publicly accessible log file named “filescount.log”:
It took us only a few minutes to develop a small script that would download the log, extract all the generated Bitcoin addresses from it, and download the respective keys without using the malware author’s C2 script. The malware author noticed that we were somehow able to continue to provide decryption support to victims. Therefore he decided to randomize the names of key files further. When you look closely at the script snippet above, you will notice that the file name within the “keys” folder consists of two parts: The “$wallet” variable which is essentially the Bitcoin wallet address that the victim is asked to send the ransom to and a variable named “$SALT”. A salt in computer science is typically a piece of random data that is supposed to make things harder to guess for an attacker. Think of it as a primitive form of a password in this particular case. Luckily for us, malware authors are normal users that also use weak passwords from time to time. In this particular case, the single piece of information that the malware author’s entire C2 security depended on turned out to be “0000”:
Needless to say, it didn’t take more than a few seconds to guess it, meaning that yet another malware variant was broken. The malware author later attempted to use more complex salts like “80b5c1cc” to thwart our decryption efforts. Luckily one of the hacked server’s owner was responding to our notifications that their server had been part of a malware campaign. They were then nice enough to help us out thus providing us with a copy of all the malware author’s server side scripts along with all the keys stored on his server. Needless to say, we were able to break even those malware variants without problem.
The quiet before the Storm
For the next few weeks things were rather quiet. We broke all variants with the exception of one, where we were unable to get to the C2 server in time to recover all the stored encryption keys. Since we knew all the Bitcoin addresses associated with the malware, we were able to figure out from the first variants that infected about 4000 users in total less than 5 users paid the ransom. As a result we were cautiously optimistic that the malware author was just giving up at that point. We were wrong.
On March 3rd, nearly one and a half months after the last PClock attack, one of our early warning systems that we routinely set up for new malware families, picked up a new PClock variant. We quickly extracted the new C2 server addresses and tried our existing scripts to extract the keys with no success. Further analysis showed that the servers were all running outdated versions of WordPress. Observing the communication protocol used by the malware, we also noticed it was talking to the WordPress instance instead of a dedicated C2 server script as before. At this point, it was obvious that the malware author changed tactics.
One of the first steps we perform when looking at a hacked site is to try random file names to discover if they point to anything useful and we got lucky. We didn’t know it then; but, the malware author once again focused the security of his entire operation around a single password and yet again chose one of the weakest passwords imaginable:
After discovering the open “QWERTY” directory that everyone could list and download from, once again we had a way to extract all the keys from the C2 server. We knew that the malware author would eventually switch servers and that the new server may not allow us to list directories that easily. In order to be future proof, we needed another way to extract keys. As always, we informed all website owners that their website was being used as the command central for a malware campaign. Once again a website owner stepped up and agreed to cooperate with us.
WPUnitE turns your blog into a malware C2 server
We knew that the new C2 script used by the malware author was acting as part of the WordPress installation, so our immediate thought was to check the WordPress plugins. WordPress allows website owners to add additional features and functionality beyond the scope of the original WordPress software to their blog by use of third-party plugins. These plugins are loaded by WordPress whenever the blog is accessed and they are pretty much unrestricted. When we looked at the installed plugins, one plugin immediately stood out: WPUnitE 1.0 supposedly authored by “WordPress”.
The plugin’s source code is obfuscated through various layers of eval, GZip compression and BASE64 encoding. Once the obfuscation layers are removed, you end up with a small script that handles all the commands sent by the malware:
This plugin distinguishes two types of commands: Restricted commands which are only accessible after providing a password and unrestricted commands that are available to everyone. In this version of the script, the password is the aforementioned “QWERTY”. The password is also used by the C2 plugin as the storage path for all the saved encryption keys. This explains why we were able to find the open /QWERTY/ directory earlier.
The restricted commands are:
This command performs a simple self-check to make sure the plugin is functional and able to properly store received encryption key files.
This command takes all saved keys and returns them to the client in a serialized and BASE64 encoded format.
This command essentially takes a serialized and BASE64 encoded list of encryption keys and stores it on the server.
The malware author used GET_STATE and SET_STATE most likely to synchronize the encryption keys between all the C2 servers. In the past keys were lost and files were unable to be decrypted whenever the C2 server was taken down. This new approach allows the malware author to maintain a backup of all keys that were generated and seed it to new C2 servers after the old ones are taken down.
The commands that are available without a password, are exclusively used by the malware are:
PING is used by the malware to send the generated Bitcoin address, the generated encrypted key, and the number of encrypted files to the C2 server.
This command is used by the malware after the victim has paid the ransom in order to obtain the encryption key necessary to decrypt the victim’s files. It performs a similar check as before to make sure that only keys returned were actually paid for.
Knowing how the C2 plugin functions, we wrote our own small client script that was able to use the GET_STATE command in order to obtain all stored encryption keys from all the C2 servers.
At this point, the malware author released new variants with new C2 servers almost weekly, not knowing how we were able to obtain the encryption keys from the C2 servers. He must have assumed that we were hacking the servers the same way he did because he started updating the WordPress blogs he had infiltrated in order to close all the open vulnerabilities that would have allowed us access to the website and the stored keys. In reality, we knew his password and C2 interface so we used the very same methods that he used to create key backups for himself against him.
Readers of our blog know that unlike some of our competitors, we never release information publicly that can be used by malware authors to improve their creations. Rather we usually keep found flaws under wraps and only share them with other malware researchers in private so we can take advantage of these flaws to help many ransomware victims for a longer period of time. Knowing that while reading this blog post, it will come to you with no surprise that the malware author finally found a way to shut us out. On April 21st, new PClock variants emerged that used C2 servers that our custom client was unable to talk to. It turned out that he finally figured out that we must have known his “secure” password all this time and were in fact using the very same commands he was using to create his own key backups. He changed the password. Unfortunately for him we are good guys that don’t need to hide. We can ask the website owner nicely to send us a copy of the malicious C2 plugin and as before, one of them did. We were able to obtain the new password (“9eba6538”) and were back in business. Unfortunately, on April 28th the malware author released yet another new variant of his malware with an updated version of his C2 plugin.
Meet WPUnitE version 2.0
As with earlier versions, Version 2.0 of the C2 plugin uses a similar obfuscation technique. Although, the majority of the private commands have been changed:
First of all the password is no longer stored in clear text. Instead the password is stored as a MD5 hash (“7afd6de416cfd1427262d380ef1d4c33”). The GET_STATE and SET_STATE commands are a thing of the past. Now you have new GET_CLIENTS, GET_ORDERS and the SET_KEY commands, which all require password authentication. GET_CLIENTS replaces GET_STATE. It essentially returns a serialized and BASE64 encoded list of all the keys stored on the server. Unlike GET_STATE however, GET_CLIENTS will delete all keys after they have been exported. It is no longer possible to get a backup of all keys. You will merely have all the keys since the last backup was exported. Based on the logs we found, the malware author automatically exports keys about every 5 minutes through a Tor connection.
No longer cure for latest PClock variant
If the C2 server no longer has the keys, how will victims who decided to pay the ransom get the key? That is the purpose of the GET_ORDERS and SET_KEY. When a ransom is paid, the malware will contact the C2 server using the GET_KEY command as in previous versions. GET_KEY will check if the key is on the server and if not will create an “order” for the key and tell the malware to try again later. These “orders” can be exported like the keys using the GET_ORDERS function. Once the malware author verified that a ransom was paid, he will then use the SET_KEY function to place the correct key on the server again. The next time the malware checks for the decryption key using GET_KEY it will get the key and perform the decryption.
Due to the fact that the cryptographic keys are no longer stored on the server, we unfortunately can no longer dump them. After almost 4 months, the malware author finally managed to shut us out.
How can I protect myself?
We can’t state this enough, but prevention is the best solution. If you are an Emsisoft user, rest assured that all PClock variants were blocked by the behavior blocker found in Emsisoft Anti-Malware and Emsisoft Internet Security. Emsisoft customers were never at risk of a potential PClock infection.
If you do own a WordPress blog and do not want your website to be abused by malware authors, we strongly urge you to keep both WordPress and your plugins up-to-date. In addition to this, it is crucial to make sure that all your editor and administrator accounts use secure passwords. In at least one specific case that we know of, the malware author gained access because of a weak administrator password.
Last but not least, we want to thank our friends over at BleepingComputer and the owners of the hacked websites that graciously responded to our notifications and decided to do the right thing by helping us out.
As always, have a nice (ransom-free) time!
Former JP Morgan employee charged with selling customer information to thieves