Research By: Eyal Itkin and Itay Cohen
Exploits have always been an important and integral part of malicious attacks. They allow attackers to gain capabilities that are not easy to achieve otherwise. Whether attackers strive to gain higher privileges on a given computer, or laterally move inside a network, exploits often play a key role in their plan. While in-the-wild exploits are used by many malware families, the malware authors get most of the attention, and the exploit developers remain out of the spotlight.
As part of our effort to focus on the exploit developers themselves, we previously shared our methodology and technique of fingerprinting and tracking exploit developers. In our earlier publication, we thoroughly explained our methodology and focused on Volodya, a prominent exploit developer we tracked using the unique fingerprints left in their exploits. Now our focus is on another exploit developer known as PlayBit or luxor2008.
As our research technique of fingerprinting exploit writers exceeded our initial expectations, we were on the lookout for more exploits to investigate. Soon enough, we came across this blog post from Kaspersky detailing how Sodin (a.k.a Sodinokibi, or REvil), an infamous ransomware, is using a 1-Day exploit for CVE-2018-8453.
CVE-2018-8453 is an interesting case, as it was formerly caught in the wild by Kaspersky when used by FruityArmor. From their report, it was clear that this exploit was reimplemented by another actor. While we would prefer to investigate an exploit developed by the actor behind the 0-Day exploit, we had to settle for the exploit used in REvil.
Even from this one sample, it was clear that this new actor uses a totally different exploit template than the one used by Volodya. Luckily for us, the actor chose to implement new features that weren’t in Volodya’s exploit template, which gave us a wider choice of artifacts to hunt for. After we created a few hunting rules, we set out to pursue our quarry.
All of the exploits that we found related to this actor were 1-Day exploits for Local Privilege Escalation (LPE) vulnerabilities in Windows. This list of 5 different CVEs that were exploited eventually led us to our actor’s identity: PlayBit (a.k.a luxor2008). A full profile of the actor can be found later on in this blog post, under the “Intelligence Report” section.
Basic Description: Uninitialized kernel pointer in
Used by the following malware families: Dyre, Ramnit
Background on this vulnerability:
This vulnerability was originally found by Google’s Tavis Ormandy, and made headlines due to an unusual disclosure process as Microsoft was not notified about the vulnerability before the full disclosure.
Figure 1: Decompiled code showing PlayBit’s exploit banner, as seen in IDA Pro.
Basic Description: Use-After-Free in
Used by the following malware families: Dyre, Evotob
Background on this vulnerability:
Also known as MS15-010, this vulnerability was found by Udi Yavo, the CTO of enSilo. The public disclosure of the vulnerability included a technical explanation of the vulnerability as well as the exploitation plan. In addition, the authors specifically mentioned they were able to exploit this vulnerability on all Windows versions, and even supplied a demo video.
Even though the disclosure didn’t share any exploit code, it was enough to draw our actor’s attention. Three months after the patch, PlayBit already had a working exploit, and a month later this exploit was used by the Dyre Banking Trojan. The exceptional case behind this vulnerability is described in more detail in FireEye’s Black Hat presentation on CVE-2015-0057.
CreateWindow callback validation error
Used by the following malware families: Locky
Background on this vulnerability:
Also known as MS15-051, this vulnerability was originally exploited as a 0-Day in an operation attributed to APT28.
Basic Description: Memory corruption in
Used by the following malware families: LockCrypt
Background on this vulnerability:
Originally exploited as a 0-Day, once again attributed to APT28. This 0-Day was found and exploited by Volodya, later to be exploited again and sold by PlayBit.
Basic Description: Use-after-free in
Used by the following malware families: REvil (Sodinokibi), Maze, Neshta
Background on this vulnerability:
Originally exploited as a 0-Day, and attributed to FruityArmor.
As bitdefender reported, Maze ransomware uses two different LPE exploits: CVE-2016-7255, and CVE-2018-8453. What’s interesting is that they use Volodya’s exploit for CVE-2016-7255 (like GandCrab, and many other malware families), while transitioning to using PlayBit’s exploit for CVE-2018-8453. Not only do we see both Volodya and PlayBit selling their exploits to the same malware actor, we can take this opportunity to learn about the dynamics involved. While PlayBit sells their own exploit for CVE-2016-7255, Maze chose to use Volodya’s exploit even though they also purchased an exploit from PlayBit (CVE-2018-8453).
It seems a bit unusual that when purchasing their LPE exploits, the actors behind Maze decided to buy from two different sellers, especially as PlayBit sells both of these exploits. However, an important fact to remember is that Maze ransomware was first discovered in 2019. Therefore, our theory is that at least in some campaigns, the operators behind Maze simply “inherited” the first exploit, later purchasing another one to target more victims.
When going over the list of CVEs that were exploited by PlayBit, we found a unique pattern that they all share: All of the vulnerabilities were already “famous” before PlayBit decided to implement an exploit for them.
As we can see, all of the CVEs that our actor chose to exploit as 1-Days were already well known. While we didn’t find a similar tactic for Volodya when choosing which 1-Day vulnerabilities to exploit, it does seem that this helped PlayBit advertise their exploits in underground forums.
One more characteristic that we found in all of PlayBit’s exploits that were lacking in Volodya’s, is the exploitability check. PlayBit supplies the customer with a thin wrapper around the exploit, which checks whether the target computer is indeed vulnerable. Although the check varies a bit between different exploits and versions, the basics are the same: the modification date of the vulnerable win32k driver is checked, to detect if a patch was installed.
Figure 2: Checking if
win32k.sys was modified after February 10, 2015 (CVE-2015-0057). Screenshot from Cutter.
This operational decision was very useful from our perspective, as the exploit effectively tells us in which Patch Tuesday the exploited vulnerability was fixed:
win32k.syschecked for a modification date of February 10, 2015.
win32k.syschecked for a modification date of May 13, 2015.
win32k.syschecked for a modification date of November 8, 2016.
win32kfull.sysare checked for a modification date of September 11, 2018.
Now that we found 5 different exploits from PlayBit, we can review them in greater detail and familiarize ourselves with the actor’s work habits. As was the case with Volodya, it was clear to us from the beginning that PlayBit probably has a simple template to deploy for the different exploits.
As some of the actor’s characteristics were already used in the previous comparison to Volodya, we chose to focus instead on other implementation decisions, some of which aren’t even included in Volodya’s exploits.
In every exploit, PlayBit picks a handful of important functions and obfuscates their use. Instead of just importing these functions in the PE level, or using their cleartext strings and importing them using
GetProcAddress(), PlayBit devised their own import technique.
Figure 3: Loading the addresses of
Ps* symbols based on their hash/CRC.
Here is a short Python snippet that performs this “hash” calculation (more like a checksum / CRC):
from malduck import ror def calc_hash(export_str): crc_value = 0 for c in export_str: cur_value = ord(c) # convert lower case back to upper case if cur_value >= ord('a'): cur_value -= 0x20 # 'a' - 'A' = 0x20 crc_value = ror(crc_value, 13) + cur_value return crc_value
Not only is this hash-based import technique used in all of the actor’s exploits, we were also able to find it in other tools they sold over the years, going back to 2012.
When examining the functions imported using this mechanism, we found out they all have a common trait. All of these functions are used by the “shellcode”, the exploitation part that is executed with high privileges and is responsible for elevating the permissions of the target process. This also means that it is relatively easy to locate the shellcode in each of the exploits, as it references the global variables that store the addresses of the specially imported functions.
Like any other experienced exploit developer attempting to target as many OS versions as possible, our actor needs to fingerprint the exact version of the immediate target. This means that the exploit identifies and calibrates itself to the target’s Windows version. In contrast to Volodya, it seems that PlayBit is interested in everything they can learn about the target:
Figure 4: Querying for the exact OS version, as can be seen in Cutter.
While this API call is used in all of the exploits, it was used exclusively only in the exploit of CVE-2013-3660. As this API became deprecated, the exploits from 2015 and later only use it when querying for the service pack and the OS type. Both the major number and minor number of the Windows OS are now queried using a different technique.
Switching from the now deprecated
GetVersionEx(), PlayBit chose to query the Process-Environment-Block (PEB).
Figure 5: Extracting the major and minor versions from the PEB, as can be seen in Cutter.
This is a clear difference in the modus operandi of PlayBit as compared to Volodya. Not only do they extract the same information in different ways, but Volodya is also interested in far less information than PlayBit, even when they both exploit the same vulnerability (CVE-2016-7255).
In general, both actors hold detailed version-specific configurations from which they load the relevant information once the OS version is determined. The main difference between the two is that the code flow in Volodya’s exploits rarely depends on the OS version, while PlayBit incorporates multiple twists and turns using various if-checks that depend on the OS version.
In contrast to what we initially thought, a closer examination of PlayBit’s exploits showed that they do indeed contain a kernel-pointer-leak primitive. Not only do the exploits contain such a leak, the chosen leak primitive hints at a high level of understanding of the internals of Windows. PlayBit directly accesses the Desktop Heap stored in user-mode, via the
Win32ClientInfo field stored in the Thread-Environment-Block (TEB).
Figure 6: Extracting information on the Desktop Heap, using TEB’s
As Microsoft gradually fixed the design issue that allowed for this pointer-leak, PlayBit had to implement some updates along the way to allow this technique to continue to work. For instance, Creators Update removed the
ulClientDelta field from
Win32ClientInfo, mandating that the exploit for CVE-2018-8453 calculate it manually. This technique was finally patched by Microsoft in Windows 10 RS4.
The leak primitive enables PlayBit to learn the kernel addresses of the windows created during the exploitation. In turn, this information is used in several phases during the exploitation:
The last point is explained in more detail in the next section.
In the initial versions of the earlier exploits, such as the exploit for CVE-2013-3660 and some versions of CVE-2015-0057, the exploit caused the kernel to execute a token-swapping shellcode stored in user-mode.
Figure 7: PlayBit exploit scanning the
EPROCESS in search for the token, as can be seen in Cutter.
The downside of this form of privilege-elevation is that SMEP prohibits the kernel from executing code that is stored in user-mode. Instead of changing the way the token-swap is performed, PlayBit decided to add an additional layer that turns off SMEP. This way, the problem is reduced to the same token-swap problem that earlier exploits already solved. A classic academic solution.
In this set of exploits, an additional kernel shellcode was added. This bootloader code is copied to kernel-space and stored as the “window name” of one of the windows corrupted by the exploit. Upon execution, the code modifies CR4 to disable the SMEP support, and then jumps back to the original user-mode payload.
Figure 8: Checking for kernel-mode, and masking out the SMEP-related bit out of CR4.
The exploit copies the payload to the kernel using the
NtUserDefSetText syscall, which explains why this syscall is included in the per-version configuration of all of the relevant exploits.
Note that this SMEP bypass is based on the fact that the above code snippet can be executed, in kernel-mode, even though it should have been a window name. The fact that memory pools were flagged as “executable” (or more specifically, weren’t flagged as “non-executable”), was used by many attackers. Eventually, Microsoft noticed this design flaw in the kernel’s memory and introduced Non-eXecutable (NX) pools to the kernel.
Once again, PlayBit decided to overcome this added restriction using yet another reduction, implemented in the exploit for CVE-2018-8453.
This additional change was more complicated than the previous one, as it also demanded the use of Arbitrary-Read and Arbitrary-Write kernel primitives. While the use of these primitives allows for a cleaner exploit to begin with, as Volodya was doing since 2015, PlayBit only added it as an additional step in the reduction to the basic user-mode token-swap payload.
During this step, the page table entries are traversed in search of the entry associated with the kernel shellcode. Once found, the entry is masked-out of the XD (eXecute Disable) bit, and stored back in the table. From this point on, the memory page containing the kernel shellcode is executable, and thus the privilege-escalation chain can start.
Figure 9: Traversing the Page Table and removing the XD bit from the record of the kernel shellcode.
After finding enough samples that adhere to PlayBit’s exploit template for Windows memory corruption LPEs, we decided to perform one more check. Using exploit-specific artifacts from each of the exploits, we created an additional set of hunting rules and did one more search.
In this additional search, we found Ramnit samples which contain an exploit for CVE-2013-3660, but with some changes:
GetProcAddress()is used instead.
Figure 10: A check for KB2850851 before exploiting CVE-2013-3660.
Our Ramnit sample exploits both CVE-2013-3660 (by PlayBit) and CVE-2014-4113 (using the same exploit code originally found as a 0-Day). The original exploit for CVE-2014-4113 was part of an exploit framework in which the API passes a command-line argument, and that command is executed as SYSTEM. As that wasn’t the original API for PlayBit’s exploit, some adjustments were made and PlayBit’s exploits were re-adjusted to receive a command-line argument to be executed once elevated.
When further investigating this new framework, we saw that it matched FireEye’s report on the Dyre Banking Trojan. As Dyre exploited CVE-2013-3660 and CVE-2015-0057, both of which were written by PlayBit, this means that during the lifetime of this exploit framework, it included at least the following 3 exploits:
Aside from connecting PlayBit to this now defunct exploit framework, we can deduce additional conclusions regarding our exploit-based hunting technique:
Essentially, both the attribution and the hunting are more complicated as the exploit framework masks many telltale-signs of the individual exploit developer.
In contrast to the previous blog post on Volodya, we decided this time to perform an additional “Background Check” on PlayBit. Being unfamiliar with this actor, we thought it would be a good chance to better understand how they work. In addition, we could test how well our exploit-based hunting technique works by comparing the found list of advertisements to the actual samples we caught.
Funnily enough, attributing the exploits to our exploit writer was quite simple. It turns out that alongside the use of numerous underground forums, there are also public YouTube channels advertising the actor’s exploits.
Figure 11: A screenshot from one of PlayBit’s YouTube channels.
For some unknown reason, there are actually two YouTube channels: one for earlier exploits, and another one (still active) for more recent exploits. As the videos publicly state which CVE is being exploited, the attribution process was very short.
When trying to learn more about this actor, we only found a single slim report. Therefore, we decided to include a detailed profile of the actor in this blog post.
Aside from the YouTube channels we mentioned earlier, the actor used multiple platforms to advertise the vulnerabilities.
Figure 12: Forum advertisement for CVE-2019-1069.
Whether the ads were placed on underground forums, YouTube, or even Pastebin, they all shared a common template:
Ring0 LPE Exploit CVE-2015-0057 [All win versions]
Vulnerability: CVE-2015-0057 (Published: February 10, 2015)
Supported versions: XP/2003/Vista/2008/W7/W8/2012/W8.1/2012R2/W10TP
Supported architecture: x86/x64
Development stage: v1.1.1900 (stable)
Shellcode size x86: 13Kb
Shellcode size x64: 16Kb
Bypass all possible Windows security defences:
There are no public POCs on this vulnerability. Shellcode has ready for immediate use in your projects. The test demo sources are supplied. Exploit is extremely stable, no bsods or error messages. Can be run under Guest account from Low Integrity Level.
Successfully bypasses proactive defences of:
These extensive ads emphasize the fact the exploit isn’t detected by AV vendors, and that public POCs do not exist or are of poor quality when compared to the exploit. The wide range of supported Windows versions is also evident: If a given Windows version is vulnerable to the exploited vulnerability, you can be sure that PlayBit’s exploit supports it.
We successfully traced PlayBit to various exploits and tools going as far back as 2012. On average, the actor sells a single Windows LPE 1-Day exploit per year, and that includes recent exploits for both CVE-2019-1069 (a SandboxEscaper vulnerability) and CVE-2020-0787 (yet another logical vulnerability).
While we caught samples of 5 memory-corruption Windows LPE vulnerabilities, the ads show that in the last year or so the actor shifted their interest. Both of the recently sold exploits are now more logical in nature, and may indicate a trend in the exploitation market. Knowing that PlayBit’s previous exploits relied on a design flaw that was fixed by Microsoft in Windows 10 RS 4 (released on April 30, 2018), it could be that Microsoft’s mitigations are one reason behind this shift in focus.
As previously reported by Kaspersky, Volodya sold 0-Day exploits at prices ranging from $85,000 (exploit from 2016) up to $200,000. While we don’t know what the selling price was for 1-Day exploits, we expected prices roughly in the same neighborhood. However, when going over the different ads published by PlayBit, we saw a wide pricing gap when compared to Volodya.
All Windows LPE exploits were advertised with a price tag ranging between $5,000 and $10,000. We even found the actor using a fake nickname and claiming to sell a 0-Day exploit, which was in fact the 1-Day exploit for CVE-2016-7255. The asking price for this “0-Day” was still $35,000, way below the $85,000 for which Volodya sold the real 0-Day exploit of the same vulnerability. In addition, we couldn’t find any pricing trend for the different exploits, as all pretty much sold for the same price from 2015 to 2020.
Although not intuitive at first, the fact that we didn’t see ads for other CVEs (of the same exploitation template) is actually good news. It means that our technique worked better than expected: A fully technical hunt for PlayBit’s exploits, without any intelligence, still managed to cover all of their exploits that originated from the exploit template with which we initially started.
Aside from Windows LPEs, we found two more interesting tools that PlayBit is developing/collaborating with.
Figure 13: Message printed when executing EternalBlack, developed by PlayBit.
The “customers” i.e. malware who use PlayBit’s exploit, either directly or by using an exploit framework, are all crimeware. Most prominent are the popular ransomware that use PlayBit’s exploits to escalate their privileges before encrypting the victim’s disk. These ransomware include Maze, Locky, LockCrypt, and REvil (Sodin, Sodinokibi). Other malware are popular Trojans like Ramnit and Dyre.
In this article, we demonstrated another case in which we were able to fingerprint an exploit developer, without prior knowledge about the developer or any public profiles. All we started with was a single sample. We showed how PlayBit, similar to Volodya, has a unique set of choices, approaches, methodologies and combinations of implementation decisions. By gathering all the pieces, we managed to understand and profile PlayBit, as well as attribute samples to the actor. We also took the opportunity to compare PlayBit to Volodya, and highlight the differences between their coding styles and preferences.
Aside from the technical aspects, this is the first time that PlayBit has been thoroughly described by researchers. We took a look at the exploit market, the advertisements, YouTube channels and collaborations between exploit developers and malware authors. Developing an exploit is just the beginning. The next step is to monetize the “product” and sell the customers a high-quality piece of software that is relatively stable and supports as many versions as possible.
Following our success with profiling both PlayBit and Volodya, we believe that our research methodology can be used to identify additional exploit writers as well. We therefore recommend that other researchers try our approach and add it to their toolbox.
Check Point Threat Emulation provides protection against this threat:
CVE-2015-1701 (Also contains an exploit for CVE-2015-0057):