TaxOff: um, you’ve got a backdoor…

Ivanti EPMM RCE Vulnerability Chain Exploited in the Wild | Wiz Blog

Summary :

A new cyber threat group named TaxOff has emerged, targeting Russian government agencies through sophisticated phishing tactics and the use of a multithreaded backdoor known as Trinper. This group employs various malicious techniques for espionage and data exfiltration, making their attacks particularly challenging to detect. #CyberThreats #TaxOff #Trinper

Keypoints :

  • TaxOff targets Russian government structures using phishing emails.
  • The group utilizes the Trinper backdoor, a multithreaded C++ application.
  • Phishing emails often include links to malicious content on platforms like Yandex Disk.
  • Trinper is designed for espionage and allows for parallel execution of multiple tasks.
  • TaxOff employs various MITRE techniques for executing attacks and exfiltrating data.

MITRE Techniques :

  • Initial Access (T1566.002): Phishing – TaxOff used phishing emails with links to malicious files.
  • Execution (T1204.002): User Execution – TaxOff utilized bait files to run the Trinper backdoor.
  • Defense Evasion (T1055.012): Process Injection – The Trinper backdoor injected code into processes.
  • Credential Access (T1187): Forced Authentication – TaxOff employed a false authorization form.
  • Discovery (T1083): File and Directory Discovery – The backdoor collected file system information.
  • Collection (T1115): Clipboard Data – The backdoor accessed clipboard data.
  • Command and Control (T1071): Application Layer Protocol – The backdoor connected to C2 using HTTP/HTTPS.
  • Exfiltration (T1020): Automated Exfiltration – The backdoor automatically exfiltrated command execution results.

Indicator of Compromise :

  • [file name] Материалы.img
  • [file name] История поисков.html
  • [file name] BK_new2.2.EXE
  • [file hash] fdeb5b2771785dc412227904127e1cae6e7bf3ef4e53efea9a7b0446f498545e8dc517dcdd3a609b7beb35fb2527e7ca1450ad40569b3ffbf67d84811fcf8ff09096d823
  • [url] drive.google.com
  • Check the article for all found IoCs.

Author: 

Vladislav Lunin, Senior Specialist of the Positive Technologies Expert Security Center Sophisticated Threat Research Group

  1. A new group was discovered targetting Russian government structures: TaxOff.
  2. TaxOff phished using legal and financial emails.
  3. TaxOff used the Trinper backdoor in its attacks.
  4. Trinper is a multithreaded backdoor written in C++ with flexible configuration using the template method as a design pattern, STL containers, and a buffer cache to improve performance. It has numerous malicious capabilities.

In Q3 2024, the Positive Technologies Expert Security Center (PT ESC) TI Department discovered a series of attacks on Russian government agencies. We were unable to establish any connection with known groups using the same techniques. The main goal was espionage and gaining a foothold to follow through on further attacks. We dubbed the group TaxOff because of their legal and finance-related phishing emails leading to a backdoor written in at least C++17, which we named Trinper after the artifact used to communicate with C2.

TaxOff uses phishing emails. We found several of them, including one with a link to Yandex Disk with malicious content for 1C and another with a fake installer for special software used by government employees to submit annual income and expense reports. This software is updated every year and targeted by attackers who distribute malware pretending to be updates.

One email had a link to Yandex Disk with the file Materials.img containing the following:

  • DCIM.lnk — a shortcut used to start the Trinper backdoor
  • drive.google.com — the Trinper backdoor
  • Encrypteddata — merged encrypted RAR archives with trimmed headers 
  • История поисков.html — a phishing form like the image below
Figure 1.png
Figure 1. Phishing form

The other vector contained the Spravki BK software used by government employees in Russia to submit income and expense reports. This software has also been targeted by group to spread the Konni backdoor as the renamed WEXTRACT.EXE.MUI file usually responsible for extracting compressed CAB files. In our case, it contains two executable files instead: bk.exe (Figure 2, Spravki BK) and DotNet35.exe, the Trinper backdoor.

Figure 2.png
Figure 2. Information about the bk.exe file

Similar to CAB files, the RCData resource section contains attributes of the execution sequence of the files it stores. The first attribute, RUNPROGRAM, contains instructions to execute a specific program or command at the start and launches bk.exe.

Figure 3. RUNPROGRAM attribute contents
Figure 3. RUNPROGRAM attribute contents

The second attribute, POSTRUNPROGRAM, contains instructions to launch the executable file after RUNPROGRAM has been executed. So after bk.exe is run, DotNet35.exe is launched.

Figure 4. POSTRUNPROGRAM attribute contents
Figure 4. POSTRUNPROGRAM attribute contents

To improve general understanding of how the backdoor works, the sections below include an explanation of its architecture, STL, design pattern, custom serialization, and buffer cache as a preface to its functional description.

Like any other multithreaded application, Trinper is built on a parallel programming paradigm, specifically thread parallelism. Tasks are broken down into sequential steps as shown on the diagram below, each of which can be performed in parallel with others.

Figure 5. Trinper's architecture
Figure 5. Trinper’s architecture

One aspect of thread parallelism is data transfer between threads using global variables that can be divided into the following groups:

  1. Group 1 include a container for storing instances of the class communicating with C2 (CommHTTP_instance).
  2. Group 2 include a container for storing information about code injections (map_TaskInject).
  3. Group 3 include containers for storing running commands (vector_RunningTasks, deque_shared_RunningTasks, map_RunningTasks).
  4. Group 4 include containers for storing the operation of background commands (map_shared_ptr_BgJobs, deque_BgJobKeylogger, unordered_map_BgJobKeylogger).

The Standard Template Library provides a set of common generic algorithms, containers, means of accessing their contents, and various functions in C++ used by the backdoor. The main sign of STL runtime is the error messages for various containers.

Figure 6.png
Figure 6. Error strings related to STL container runtime

std::string and std::wstring

Strings are objects represented as a sequence of characters. Symbols can either have ASCII or wide encoding, which makes these containers clearly distinguishable. In std::string, the maximum length of the predefined buffer can’t exceed 15 bytes, otherwise a heap buffer will be allocated. As for std::wstring, the length of the predefined buffer can’t exceed 7 bytes. This runtime is for comparing the length of the stored string and possible subsequent allocation of a heap buffer, which allows one of the containers used to be determined precisely.

Figure 7.png
Figure 7. Recognizing the std::string and std::wstring runtime

std::vector<T>

Vectors are containers for array-like sequences that can vary in size. One way to recognize the runtime of a vector is to compare successive memory addresses and then assign a new value to one of them. If the pointer to the first vector element is equal to the pointer to the last element (for example, when adding a new element), then the vector will have to change its current size, allocate additional memory before adding it, and redefine the pointer to the last element.

Figure 8. Recognizing the std::vector<T/> runtime” loading=”lazy” width=”0″ height=”0″ decoding=”async” data-nimg=”1″ class=”HtmlContent_image-next__g1zfK” src=”https://pt-global.storage.yandexcloud.net/Figure_8_1da5aeff83.png”><figcaption>Figure 8. Recognizing the std::vector<T> runtime</figcaption></figure>
<h3>std::list<T></h3>
<p>Lists are sequence containers that allow constant-time insertion and erasure of elements anywhere in the sequence, as well as iteration in both directions. One way to recognize the runtime of a doubly linked list is to compare the selected buffer with the subsequent one to see if the end has been reached when iterating the elements.</p>
<figure class=Figure 9. Recognizing the std::list<T/> runtime” loading=”lazy” width=”0″ height=”0″ decoding=”async” data-nimg=”1″ class=”HtmlContent_image-next__g1zfK” src=”https://pt-global.storage.yandexcloud.net/Figure_9_b135c189a9.png”><figcaption>Figure 9. Recognizing the std::list<T> runtime</figcaption></figure>
<h3>std::map<K, T></h3>
<p>Maps are associative containers that store elements formed by a combination of a key and mapped value in a specific order. One way to recognize map runtime is that the map needs to know if there’s already an element with the provided key before inserting a new key-value pair or returning a value based on the key.</p>
<figure class=Figure 10. Recognizing std::map<K, T/> runtime” loading=”lazy” width=”0″ height=”0″ decoding=”async” data-nimg=”1″ class=”HtmlContent_image-next__g1zfK” src=”https://pt-global.storage.yandexcloud.net/Figure_10_f1a9aac69b.png”><figcaption>Figure 10. Recognizing std::map<K, T> runtime</figcaption></figure>
<h3>std::unordered_map<K, T></h3>
<p>Unordered maps are associative containers that store elements formed by a combination of a key and mapped value, which allows individual elements to be quickly found by their keys. One of the ways to recognize the runtime of an unordered map is how its elements are stored in hash tables, as the hash sum will always be calculated for any element index regardless of the operation.</p>
<figure class=Figure 11. Recognizing the std::unordered_map<K, T/> runtime” loading=”lazy” width=”0″ height=”0″ decoding=”async” data-nimg=”1″ class=”HtmlContent_image-next__g1zfK” src=”https://pt-global.storage.yandexcloud.net/Figure_11_53d68c640e.png”><figcaption>Figure 11. Recognizing the std::unordered_map<K, T> runtime</figcaption></figure>
<h3>std::deque<T></h3>
<p>Deques are dynamically sized sequence containers that can expand or contract at the front (head) or back (tail). One method of recognizing the runtime of a deque is to access elements in the blocks. Their size is always a multiple of two, so access uses bitwise operations to split the index into a block and an offset.</p>
<figure class=Figure 12. Recognizing the std::deque<T/> runtime” loading=”lazy” width=”0″ height=”0″ decoding=”async” data-nimg=”1″ class=”HtmlContent_image-next__g1zfK” src=”https://pt-global.storage.yandexcloud.net/Figure_12_9798c030e1.png”><figcaption>Figure 12. Recognizing the std::deque<T> runtime</figcaption></figure>
<h3>std::shared_ptr<T></h3>
<p>Smart pointers control pointer storage and provide limited trash collection, potentially sharing this control with other objects. One way to recognize the runtime of a smart pointer is with atomic operations. If the number of shared pointers to an object decreases to zero, then the control block is deleted.</p>
<figure class=Figure 13. Recognizing the std::shared_ptr<T/> runtime” loading=”lazy” width=”0″ height=”0″ decoding=”async” data-nimg=”1″ class=”HtmlContent_image-next__g1zfK” src=”https://pt-global.storage.yandexcloud.net/Figure_13_2e8fd95d38.png”><figcaption>Figure 13. Recognizing the std::shared_ptr<T> runtime</figcaption></figure>
<h3>std::filesystem</h3>
<p>std::filesystem provides means for performing operations on file systems and their components, including paths, regular files, and directories. One of the ways to recognize its runtime is the presence of functions with the _std_fs_* prefix, which indicates operations with the file system.</p>
<figure class=Figure 14. Recognizing the std::filesystem runtime
Figure 14. Recognizing the std::filesystem runtime

To avoid creating structures manually, we need to include header files. To determine their location, we run the x86/x64 Native Tools Command Prompt for VS 20XX (depending on the bit depth of the executable file) and enter the echo %INCLUDE% command. Then we copy all the paths and paste them in Options > Compiler > Include directories. We also specify -target x86_64-pc-win32/i386-pc-win32 -x c++ as arguments to include C++ header files.

Figure 15. Including header files
Figure 15. Including header files

In most cases, the element type of containers is set at compile time, so you can’t just include a vector header file (for example) and expect all the element types to be included. Instead, you need to create a separate header file where the container element type will be defined explicitly.

Figure 16. Vector structure
Figure 16. Vector structure

A design pattern in software engineering is a recurring architectural construct offering a solution to a design problem within a frequently occurring context. This is a rare find in malicious code and indicates that the programmer who wrote the backdoor is an experienced professional. The backdoor uses the template method, which is a behavioral design pattern that defines the skeleton of an algorithm and defers certain steps to subclasses. The pattern allows subclasses to redefine the algorithm’s steps without changing its overall structure.

Figure 17. The template method
Figure 17. The template method

This backdoor pattern is used to create command subclasses that are inherited from the base class and redefine its methods and fields.

Figure 18. Template method in use
Figure 18. Template method in use

In addition to encryption, the backdoor uses custom serialization to store the configuration and increase flexibility, as it allows fields to have multiple values in the same token.

Figure 19. Serialized configuration
Figure 19. Serialized configuration

For example, if a container token is negative, then it has another container in its value that may also only be part of a sequential nesting of containers or unequivocally determine the value of the token (for example, store a string).

Figure 20. Deserialization of the configuration
Figure 20. Deserialization of the configuration

A buffer cache is a data structure designed for the temporary storage of data to speed up access to it. The Trinper backdoor uses caching to reduce access time to frequently used data, minimize latency, and improve overall program performance.

Figure 21. Use of buffer cache
Figure 21. Use of buffer cache

At the start, the backdoor deserializes the configuration and gets the name it should have. If it’s different, execution is stopped, but if the names match, the backdoor continues initialization and calls a function to obtain information about the victim’s computer and collect it with the following type of VictimInfo structure:

struct struct_VictimInfo
{
	DWORD magic;
	struct_VictimData VictimData;
};

struct struct_VictimData
{
	GUID guid;
	BYTE pbSecret[16];
	BYTE UserNameW[64];
	BYTE hostname[32];
	BYTE disks[32];
	BYTE h_addrs[20];
	DWORD KeyboardLayout;
	BYTE dwOemId;
	BYTE val_64;
	BYTE dwMajorVersion;
	BYTE dwMinorVersion;
	BYTE Authority;
	BYTE FileNameW[64];
	BYTE AdaptersAddresses[6];
};

The fields of the VictimInfo structure have the following purposes:

Member Purpose
magic Magic number 0xB0B1B201
VictimData
Member Purpose
guid Generated GUID
pbSecret Session key for AES-128-CBC
UserNameW Username
hostname Host name
disks Disk names
h_addrs Host address list
KeyboardLayout System language used
dwOemId Information about the architecture
val_64 Constant value 64
dwMajorVersion Major version of the system
dwMinorVersion Minor version of the system
Authority Level of integrity
FileNameW File path
AdaptersAddresses Addresses of network adapters

After filling in the VictimInfo structure, the backdoor creates and runs these class instances for execution in different threads:

  • CommHTTP — the class for the thread for communication with C2 servers
  • BgJobFileCapture — the class for the thread that monitors the file system
  • BgJobKeylogger — the class for the thread where keystrokes will be intercepted

In its thread, the CommHTTP class parses the deserialized configuration it will use to communicate with C2, generates a session key for AES-128-CBC (with the initialization vector equal to zero), imports the public RSA key, and enters a communication loop with C2 servers where:

  • Commands are received
  • Results about command operations are received and sent
Figure 22. CommHTTP class instance execution cycle
Figure 22. CommHTTP class instance execution cycle

An instance of the BgJobFileCapture class monitors the file system in its thread, loops through all connected disks, and searches recursively for .doc, .xls, .ppt, .rtf, and .pdf files stored on disks. It also stores execution results in a map with a key (file name) and value (the structure containing information about the file, including its contents).

Figure 23. Receiving information about the file system
Figure 23. Receiving information about the file system

An instance of the BgJobKeylogger class intercepts keystrokes in its thread and stores them in a deque, with data from the clipboard stored in an unordered map.

Figure 24. Installing the keylogger
Figure 24. Installing the keylogger

The configuration is encrypted and stored in the .data section, and decryption is carried out with a one-byte key for a regular Xor operation.

Figure 25. Decrypting the configuration
Figure 25. Decrypting the configuration

Here’s what the decrypted and deserialized configuration structure looks like:

struct struct_Config
{
	DWORD sleep_time;
	DWORD size;
	std::wstring UserAgent;
	std::wstring wstr_x86;
	std::wstring wstr_x64;
	std::vector<std::wstring> C2;
	QWORD *public_key;
	QWORD public_key_len;
	struct_Commands Commands;
	struct_TaskResults TaskResults;
};

struct struct_Commands
{
	std::wstring Uri;
	std::vector<std::string> Headers;
	struct_CommandsResponse CommandsResponse;
	struct_CommandsHeaders CommandsHeaders;
	QWORD HelloMessage;
	QWORD HelloMessageLen;
};

struct struct_CommandsResponse
{
	std::string TagOpen;
	std::string Encoder;
	std::string TagClose;
};

struct struct_CommandsHeaders
{
	std::string Header;
	std::string TagOpen;
	std::string Encoder;
	std::string TagClose;
};

struct struct_TaskResults
{
	std::wstring Uri;
	std::vector<std::string> Headers;
	struct_TaskResultsData TaskResultsData;
	struct_TaskResultsHeaders TaskResultsHeaders;
};

struct struct_TaskResultsData
{
	std::string TagOpen;
	std::string Encoder;
	std::string TagClose;
};

struct struct_TaskResultsHeaders
{
	std::string Header;
	std::string TagOpen;
	std::string Encoder;
	std::string TagClose;
};

The fields of the Config structure have the following purposes:

Member Purpose
sleep_time Timeout for a CommHTTP class instance in the C2 communication loop
size Sized of used buffer cache
UserAgent User-Agent used to communicate with C2 servers
wstr_x86 x86 wide string not used
wstr_x64 X64 wide string not used
C2 C2 addresses
public_key Public key for encrypting information about the victim and session key
public_key_len Length of the public key
Commands

Structure used to receive commands

Member Purpose
Uri Command request path
Headers Custom headers
CommandsResponse
Member Purpose
TagOpen Start of command mask
Encoder Command encoding algorithm
TagClose End of command mask
CommandsHeaders
Member Purpose
Header Header storing information about the victim
TagOpen Start of the header mask
Encoder Encoding algorithm
TagClose End of header mask
HelloMessage Command request string
HelloMessage Command request string length
TaskResults

Structure used to send command operation results

Member Purpose
Uri Path of command operation results
Headers Custom headers
TaskResultsData
Member Purpose
TagOpen Start of task results mask
Encoder Algorithm for encoding task results
TagClose End of task results mask
TaskResultsHeaders
Member Purpose
Header Header storing information about the victim
TagOpen Start of the header mask
Encoder Encoding algorithm
TagClose End of header mask

All communication with C2 is carried out by an CommHTTP class instance using calls to WININET.DLL library network functions. Information about the victim’s computer and session key is encrypted with the public RSA key, encoded using Base64, and sent to C2 in the Config.Commands.CommandsHeaders header with Config.Commands.HelloMessage in the request data. The commands received from C2 in response are enclosed between the Config.Commands.CommandsResponse.TagOpen and Config.Commands.CommandsResponse.TagClose markers and encoded using Base64. The task results are encrypted with the AES-128-CBC session key, encoded using Base64, and enclosed between the Config.TaskResults.TaskResultsData.TagOpen and Config.TaskResults.TaskResultsData.TagClose markers in the request data to C2.

Figure 26. POST request to receive commands
Figure 26. POST request to receive commands

For example, below is a backdoor request to C2 to receive commands. The greeting message in the data is mid=76&mod=TRINP, and you can see that the User-Agent header doesn’t display the content received from Config.UserAgent correctly. This is due to an error passing the header value to InternetOpenW. The problem is that InternetOpenW tries to convert the string for User-Agent from wide to ASCII encoding, but does so incorrectly because the pointer to the values from the configuration is passed incorrectly, leading to an undisplayable string generated at the output.

Figure 27. Request packet to receive commands
Figure 27. Request packet to receive commands

As mentioned earlier, commands are invoked not by calling a specific function, but by instantiating classes and adding them to a smart pointer wrapper to be added to a deque for execution, and then retrieved from there and called in the main thread loop. The table below includes descriptions of the commands.

ID Command Description
0x1213C7 Inject Code injection into process
0xF17E09 WriteFile Write to file
0xF17ED0 ReadFile Read from file
0xC033A4D Cmd Execute command using cmd.exe
0x6E17A585 GetRunningTasks Receive commands running currently
0xECEC Exec Reverse shell
0xCD Cd Change of directory
0x108 JobConf Add command in the background
0xD1E Die Backdoor shutdown
0x6177 KillTask End working command
0xC04F SetCommConfValue Configuration update

The TaxOff group tricks users by baiting them with time-sensitive material they’re expecting at work and attack using a sophisticated multithreaded backdoor called Trinper. After establishing persistent access to compromised systems, they can effectively manage multiple tasks simultaneously and follow through on various malicious actions without significantly impacting system performance. Multithreading provides a high degree of parallelism to hide the backdoor while retaining the ability to collect and exfiltrate data, install additional modules, and maintain communications with C2. This combination of convincing bait and a sophisticated multithreaded backdoor makes TaxOff’s attacks particularly dangerous and difficult to detect and prevent, highlighting the need for continuous user awareness of cyberthreats and the implementation of multi-layered security measures for protection.

FILE MD5 SHA-1 SHA-256
Материалы.img fdeb5b2771785dc412227904127e1cae 6e7bf3ef4e53efea9a7b0446f498545e8dc517dc dd3a609b7beb35fb2527e7ca1450ad40569b3ffbf67d84811fcf8ff09096d823
История поисков.html e4da6bd811eb3b5adc4ec29fa859c08c e810613df0dbb5d8634e7e5321f5b14c62ccfcf6 00f433c593204eaa1facb18d1a0dec4caee06915bbc8a51ad6bf47bf9e865fe8
BK_new2.2.EXE 7815db832ef5124935d9b53445a72f49 d45c3392011070e7e827dd3f8d6797725384b1b3 f699c309f0d2547a85f6623dc74cc452a1471cd77af2360116447244043ee0dd
DCIM.lnk 468f4b71eac65391d3d59466e21ec379 9a083844696dd8ccce9a6f11d3a9f1227ea639ba 93b07ba651fb6dbebaaadb39cf45ddfea7af9d3943458a5630aa588080dcf335
Trinper
drive.google.com 463d8f6e597fc7c2acdb3f5a3bae37b6 8dfecf3417b8f2ab96a3591c93223d6802690fe3 2a0c6a66774cc535f51e1a12d81ba6aa346934aa542291cee0c57f3bc9373a8e
PhotoScreenSaver.scr 19354fc1fb24d2eb08de0d46d464b16b 62e27a7e392a48d6cf14040c6fe59dabb8df44a7 6d4fac9e4c36face9e0d0a7fdec1cc1403b3188ecf5c24f1ac6c32981f9c72b2
SearchApps.exe 62739a86a227ad89fa6c57f5c2335220 f5815561dfc63ad12f96a3e86e0f40cd39622373 7e82b3f1be69d34684a4aa4823ef0d5ae864db3501fae5a0c3697bcd28df5cef
DotNet35.exe f590d65dce86589b0e0d507cfeef9f68 c3012a66acaea8801446ee61f8213a663eb7a76a e93c1a0696b59a58e2444eb69ddf165eed71ad159624674a7fe6c91e9852443a
185.158.248.91
193.37.215.111
server.1cscan.net
usfna.global.ssl.fastly.net
usfnb.global.ssl.fastly.net
usfnc.global.ssl.fastly.net
cfn.global.ssl.fastly.net
fna.global.ssl.fastly.net
fnb.global.ssl.fastly.net
consult-asset-feed.global.ssl.fastly.net
consult-vendor-free.global.ssl.fastly.net
consult-zero-ads.global.ssl.fastly.net
rule PTESC_apt_win_ZZ_TaxOff__Backdoor__Trinper{
    strings:
        $s1 = "Task"
        $s2 = "TaskCd"
        $s3 = "TaskCmd"
        $s4 = "TaskExec"
        $s5 = "TaskGetRunningTasks"
        $s6 = "TaskInject"
        $s7 = "TaskDie"
        $s8 = "TaskJobConf"
        $s9 = "TaskKillTask"
        $s10 = "TaskReadFile"
        $code1 = {E8 ?? ?? ?? ?? 44 38 60 ?? 75 ?? 66 39 58 ?? 72 ?? 48 8B 40 ?? 8B 08 EB ??}
        $code2 = {48 89 4C 24 ?? 48 8B 44 24 ?? 0F B6 40 ?? 85 C0 75 ?? 48 8B 44 24 ?? 0F B7 40 ?? 83 F8 ?? 7D ?? 33 C0 EB ?? 48 8B 44 24 ?? 48 8B 40 ?? 8B 00 C3}
    condition:
        ((uint16(0) == 0x5a4d) and (all of($s*)) and (any of($code*)))
}
Initial Access
T1566.002 Phishing: Spearphishing Link TaxOff used phishing emails with links to malicious files
Execution
T1204.002 User Execution: Malicious File TaxOff used bait files to run the Trinper backdoor
Defense Evasion
T1055.012 Process Injection: Process Hollowing TaxOff used the Trinper backdoor to inject code into processes
Credential Access
T1187 Forced Authentication TaxOff used a false authorization form
T1056.001 Input Capture: Keylogging TaxOff used the Trinper backdoor to intercept keystrokes
Discovery
T1083 File and Directory Discovery TaxOff used the Trinper backdoor to collect file system information
Collection
T1115 Clipboard Data TaxOff used the Trinper backdoor to access the clipboard
T1056.001 Input Capture: Keylogging TaxOff used the Trinper backdoor to intercept keystrokes
Command And Control
T1071 Application Layer Protocol TaxOff used http (https) to connect the Trinper backdoor to C2
T1132.001 Data Encoding: Standard Encoding TaxOff used the Trinper backdoor to encode received information using Base64
T1573.001 Encrypted Channel: Symmetric Cryptography TaxOff used the Trinper backdoor to encrypt sent information using AES-256
T1573.002 Encrypted Channel: Asymmetric Cryptography: TaxOff used the Trinper backdoor to encrypt sent information using RSA
T1090.004 Proxy: Domain Fronting TaxOff used domain fronting to communicate with the Trinper backdoor
Exfiltration
T1020 Automated Exfiltration TaxOff used the Trinper backdoor to automatically exfiltrate results from executing commands
T1041 Exfiltration Over C2 Channel TaxOff used the Trinper backdoor to exfiltrate data to C2
apt_win_ZZ_TaxOff__Backdoor__Trinper
Suspicious_Connection
RunAs_System_or_External_tools
Run_Executable_File_without_Meta
Suspicious_Directory_For_Process
BACKDOOR [PTsecurity] Trinper (APT TaxOff) sid: 10012123
SUSPICIOUS [PTsecurity] Suspicious HTTP header Trinper (APT TaxOff) sid: 10012124, 10012125

Full Research: https://global.ptsecurity.com/analytics/pt-esc-threat-intelligence/taxoff-um-you-ve-got-a-backdoor