## En Route with
#### Part 2: Observing the Comings and Goings
###### Version 1.0 • October 2016
-----
# En Route with Sednit
#### Part 2: Observing the Comings and Goings
###### Version 1.0 • October 2016
-----
##### Table of Content
**Executive Summary** **5**
**Introduction** **6**
The Sednit Group 6
The Second Part of the Trilogy 7
Attribution 8
Publication Strategy 8
**Xagent: Backdoor Specially Compiled for You** **10**
Identikit 10
Timeline 11
Context 12
Initialization 14
Modules 15
Communication Channels 21
Conclusion and Open Questions 27
**Sedreco: The Flexible Backdoor** **28**
Identikit 28
Context 29
Dropper Workflow 29
Payload Workflow 30
Conclusion and Open Questions 35
**Xtunnel: Reaching Unreachable Machines** **36**
Identikit 36
Timeline 37
Big Picture 38
Traffic Proxying 39
Additional Features 42
Conclusion and Open Questions 45
**Closing Remarks** **46**
**Indicators of Compromise** **47**
Xagent 47
Sedreco 48
Xtunnel 49
**References** **51**
-----
##### List of Tables
Table 1. Xagent version 2 Linux modules 15
Table 2. AgentKernel accepted commands 20
Table 3. Xagent version 2 Linux channels 21
Table 4. Sedreco payload commands 31
Table 5. Xtunnel Parameters 43
##### List of Figures
Figure 1. Timeline of 0-day vulnerabilities exploited by the Sednit group in 2015. 6
Figure 2. Main attack methods and malware used by the Sednit group since 2014,
and how they are related 7
Figure 3. Xagent major events 11
Figure 4. Partial directory listing of Xagent source files 12
Figure 5. Xagent communication workflow 18
Figure 6. CryptRawPacket data buffer format 19
Figure 7. URL for GET and POST requests, X.X.X.X being the C&C server IP address 22
Figure 8. Format of the token value 22
Figure 9. Proxy server source files 23
Figure 10. Communication workflow between an Xagent infected computer using
MailChannel and its C&C server, via a proxy server 24
Figure 11. Email subject generated by the P2 protocol. 25
Figure 12. Dropper workflow with the developers’ names for each step 29
Figure 13. Extract of Sedreco configuration. The names of the fields are those created
by ESET’s analysts. Field sizes are in bytes. 30
Figure 14. Command registration — CMD functions are the commands handlers 31
Figure 15. Data flow between Sedreco on a compromised host and its C&C server 32
Figure 16. Network contact message format. Computer name is a variably-sized field 32
Figure 17. Inbound file format. Field sizes are in bytes 33
Figure 18. Outbound file format. Field sizes are in bytes 33
Figure 19. Extract of LZW algorithm C source code 34
Figure 20. Plugin Init export 35
Figure 21. Plugin UnInit export 35
Figure 22. XTunnel major events 37
Figure 23. Xtunnel core behavior 38
Figure 24. Xtunnel communication workflow 39
Figure 25. Extract of T initialization code 40
Figure 26.1 Message to open tunnel 0x100 on IP address 192.168.124.1 and port 4545 41
Figure 26.2 Message to open tunnel 0x200 on domain name test.com and port 4646 41
Figure 27.1 Xtunnel CFG before obfuscation 44
Figure 27.2 Xtunnel CFG after obfuscation 45
-----
### En Route with Sednit
##### Executive Summary
The Sednit group — also known as APT28, Fancy Bear and Sofacy — is a group of attackers
operating since 2004 if not earlier and whose main objective is to steal confidential information
from specific targets.
This is the second part of our whitepaper “En Route with Sednit”, which covers the Sednit’s group
activities since 2014. Here, we focus on Sednit’s espionage toolkit, which is deployed on targets
deemed interesting after a reconnaissance phase (described in the first part of the whitepaper).
The key points described in this second installment are the following:
- The Sednit group developed two different spying backdoors for long term monitoring,
named Sedreco and Xagent, in order to maximize the chance of avoiding detection
- The Xagent backdoor can communicate with its C&C server over email with a custom
protocol, which in some cases is based on Georgian words
- The Sednit group developed a network proxy tool, named Xtunnel, to effectively transform
a compromised computer into a network pivot, in order to contact machines that are normally
unreachable from the Internet
- The Xagent source code, the Xagent C&C server configuration, and the Xtunnel binaries
all contain traces of Russian, strongly reinforcing the hypothesis that this is the language
employed by the Sednit group’s members
[For any inquiries related to this whitepaper, contact us at: threatintel@eset.com](mailto:threatintel%40eset.com?subject=En%20Route%20with%20Sednit%20Part%202)
-----
### En Route with Sednit
##### Introduction
_Readers who have already read the first part of our Sednit trilogy might want to skip the following section_
_(duplicated from the previous part) and go directly to the specific introduction of this second part._
###### The Sednit Group
The Sednit group — variously also known as APT28, Fancy Bear, Sofacy, Pawn Storm, STRONTIUM
and Tsar Team — is a group of attackers operating since 2004 if not earlier, whose main objective
is to steal confidential information from specific targets. Over the past two years, this group’s activity
has increased significantly, with numerous attacks against government departments and embassies
all over the world.
Among their most notable presumed targets are the American Democratic National Committee [1],
the German parliament [2] and the French television network TV5Monde [3]. Moreover, the Sednit
group has a special interest in Eastern Europe, where it regularly targets individuals and organizations
involved in geopolitics.
One of the striking characteristics of the Sednit group is its ability to come up with brand-new 0-day [4]
vulnerabilities regularly. In 2015, the group exploited no fewer than six 0-day vulnerabilities, as shown
in Figure 1.
**CVE-2015-3043**
Flash
**CVE-2015-1701**
Windows LPE
**CVE-2015-2590**
Java
**CVE-2015-4902**
Java click-to-play bypass
**CVE-2015-7645**
Flash
**APR** **MAY** **JUN** **JUL** **AUG** **SEP** **OCT**
**CVE-2015-2424**
Office RCE
Figure 1. Timeline of 0-day vulnerabilities exploited by the Sednit group in 2015
This high number of 0-day exploits suggests significant resources available to the Sednit group, either
because the group members have the skills and time to find and weaponize these vulnerabilities,
or because they have the budget to purchase the exploits.
Also, over the years the Sednit group has developed a large software ecosystem to perform
its espionage activities. The diversity of this ecosystem is quite remarkable; it includes dozens
of custom programs, with many of them being technically advanced, like the Xagent and Sedreco
modular backdoors (described in the second part of this whitepaper), or the Downdelph bootkit
and rootkit (described in the third part of this whitepaper).
We present the results of ESET’s two-year pursuit of the Sednit group, during which we uncovered
and analyzed many of their operations. We split our publication into three independent parts:
1. “Part 1: Approaching the Target” describes the kinds of targets the Sednit group is after,
and the methods used to attack them. It also contains a detailed analysis of the group’s
most-used reconnaissance malware.
-----
### En Route with Sednit
2. “Part 2: Observing the Comings and Goings” describes the espionage toolkit deployed on some
target computers, plus a custom network tool used to pivot within the compromised
organizations.
3. “Part 3: A Mysterious Downloader” describes a surprising operation run by the Sednit group,
during which a lightweight Delphi downloader was deployed with advanced persistence
methods, including both a bootkit and a rootkit.
Each of these parts comes with the related indicators of compromise.
###### The Second Part of the Trilogy
Figure 2 shows the main components that the Sednit group has used over the last two years,
with their interrelationships. It should not be considered as a complete representation of their
arsenal, which also includes numerous small custom tools.
**ATTACK** **FIRST-STAGE** **SECOND-STAGE** **PIVOT**
**METHODS** **MALWARE** **MALWARE** **MALWARE**
**Seduploader** **Seduploader** **Sedreco** **Sedreco**
**Xtunnel**
dropper payload dropper payload
Sedkit
**Usbstealer**
Email
attachments
**Downdelph** **Xagent**
Fake webmail
login panels
En Route with En Route En Route
Sednit with Sednit with Sednit
**Part 1** **Part 3** **Part 2**
Figure 2. Main attack methods and malware used by the Sednit group since 2014,
and how they are related
We divide Sednit’s software into three categories: the first-stage software serves for reconnaissance
of a newly compromised host, then comes the second-stage software intended to spy on machines
deemed interesting, while the pivot software finally allows the operators to reach other computers.
In this second part, we focus on Sednit’s espionage toolkit, which serves for long term monitoring
of compromised computers. The components described in this second part are outlined in blue
in Figure 2, which includes the two spying backdoors Sedreco and Xagent, and the network
tool Xtunnel.
The usual workflow of Sednit’s operators is to deploy both Sedreco and Xagent on a newlycompromised computer, after a reconnaissance phase with first-stage malware (Seduploader,
described in the first part of this whitepaper, or Downdelph, described in the third part). Deploying
both spying backdoors at the same time allows them to remain in contact if one of them becomes
detected. The network tool Xtunnel comes later, in order to reach other accessible computers.
|Col1|Col2|Col3|Col4|Col5|
|---|---|---|---|---|
||||||
||||||
||||||
||||||
||||||
|Seduploader Seduploader Sedreco Sedreco Xtunnel dropper payload dropper payload Sedkit Usbstealer Email attachments Downdelph Xagent Fake webmail login panels En Route with En Route En Route Sednit with Sednit with Sednit Part 1 Part 3 Part 2|Col2|
|---|---|
|||
|||
**SECOND-STAGE**
**MALWARE**
**Sedreco** **Sedreco**
dropper payload
**Xagent**
En Route
with Sednit
**Part 2**
**ATTACK**
**METHODS**
Sedkit
Email
attachments
Fake webmail
login panels
-----
### En Route with Sednit
All the components shown in Figure 2 are described in this whitepaper,
with the exception of Usbstealer, a tool to exfiltrate data from air-gapped
machines that we have already described at WeLiveSecurity [5]. Recent
versions have been documented by Kaspersky Labs [6] as well.
Readers who have already read the first part of our Sednit trilogy may skip the following sections
and go directly to Xagent’s analysis.
###### Attribution
One might expect this reference whitepaper to add new information about attribution. A lot has
been said to link the Sednit group to some Russian entities [7], and we do not intend to add anything
to this discussion.
Performing attribution in a serious, scientific manner is a hard problem that is out of scope
of ESET’s mission. As security researchers, what we call “the Sednit group” is merely a set of software
and the related network infrastructure, which we can hardly correlate with any specific organization.
Nevertheless, our intensive investigation of the Sednit group has allowed us to collect numerous
indicators of the language spoken by its developers and operators, as well as their areas of interest,
as we will explain in this whitepaper.
###### Publication Strategy
Before entering the core content of this whitepaper, we would like to discuss our publication strategy.
Indeed, as security researchers, two questions we always find difficult to answer when we write
about an espionage group are “when to publish?”, and “how to make our publication useful to those tasked
_with defending against such attacks?”._
There were several detailed reports on the Sednit group published in 2014, like the Operation Pawn
Storm report from Trend Micro [8] and the APT28 report from FireEye [9]. But since then the public
information regarding this group has mainly came in the form of blog posts describing specific
components or attacks. In other words, no public attempts have been made to present the big
picture on the Sednit group since 2014.
Meanwhile, the Sednit group’s activity has significantly increased, and its arsenal differs from those
described in previous whitepapers.
Therefore, our intention here is to provide a detailed picture of the Sednit group’s activities over
the past two years. Of course, we have only partial visibility into those activities, but we believe
that we possess enough information to draw a representative picture, which should in particular
help defenders to handle Sednit compromises.
We tried to follow a few principles in order to make our whitepaper useful to the various types
of readers:
- Keep it readable: while we provide detailed technical descriptions, we have tried to
make them readable, without sacrificing precision. For this reason we decided to split
our whitepaper into three independent parts, in order to make such a large amount of
information easily digestible. We also have refrained from mixing indicators of compromise
with the text.
- Help the defenders: we provide indicators of compromise (IOC) to help detect current Sednit
infections, and we group them in the IOC section and on ESET’s GitHub account [10]. Hence,
the reader interested only in these IOCs can go straight to them, and find more context
in the whitepaper afterwards.
-----
### En Route with Sednit
- Reference previous work: a high profile group such as Sednit is tracked by numerous entities.
As with any research work, our investigation stands on the shoulders of the previous
publications. We have referenced them appropriately, to the best of our knowledge.
- Document also what we do not understand: we still have numerous open questions
regarding Sednit, and we highlight them in our text. We hope this will encourage fellow
malware researchers to help complete the puzzle.
We did our best to follow these principles, but there may be cases where we missed our aim.
[We encourage readers to provide feedback at threatintel@eset.com, and we will update](mailto:threatintel%40eset.com?subject=Sednit)
the whitepaper accordingly.
-----
### En Route with Sednit
##### Xagent: Backdoor Specially Compiled for You
-----
### En Route with Sednit
###### Timeline
The dates posited in the timeline mainly rely on Xagent compilation timestamps, which we believe
have not been tampered with because they match up with our telemetry data. These dates may
be later than the actual events though, as we do not have all Xagent samples, but enough
are present to give a good approximation. In particular, we dated the appearance of Xagent
as independent malware in November 2012, but fellow malware researchers reported to us privately
that parts of its code were used before that.
##### 2012
**November**
Introduction of Xagent
version 1 for Windows
##### 2016
**May**
Xagent found on
the servers of the
Democratic National
Committee (DNC)
##### 2014
**February**
Introduction of Xagent
version 2 for both Linux
and Windows
##### 2015
**December**
Introduction of Xagent
version 3 for Linux
##### 2014
**September**
Xagent deployed
with Sedkit exploit kit
Introduction of
version 3 for Windows;
Modules now have
obfuscated Run-Time Type
Information (RTTI)
##### 2015
**February**
Xagent for iOS found
by Trend Micro _[13]_
Figure 3. **Xagent major events**
-----
### En Route with Sednit
###### Context
During our investigations, we were able to retrieve the complete Xagent source code for the Linux
operating system. To the best of our knowledge, this is the first time this Xagent source code
has been found and documented by security researchers.
This source code is a fully working C++ project, which was used by Sednit operators to compile
a binary in July 2015 (at least). The project contains around 18,000 lines of code among 59 classes;
a partial directory listing of the source files is shown in Figure 4.
Figure 4. Partial directory listing of Xagent source files
-----
### En Route with Sednit
We believe the Linux source code is derived from the Windows version of Xagent. In other words,
OS-specific operations have been re-implemented, but the core logic remains the same on both
platforms. As an example of this lineage, the following code snippet shows some Windows API calls
for thread termination commented out by the developers, and replaced with a call to the Linux
pthreads [14] interface.
```
if(handleGetPacket != 0)
{
pthread_exit(&handleGetPacket);
//TerminateThread(handleGetPacket, 0);
//CloseHandle(handleGetPacket);
}
```
According to its internal version numbering, this source code is version 2 of Xagent, while currently
distributed Windows and Linux binaries are version 3. Nevertheless, there appear to be only minor
differences between the two versions, and the source code matches the core logic of the most recent
samples on both Windows and Linux platforms. Also, the iOS version of Xagent found by Trend
Micro [13] — not documented in this white paper — is based on this source code, according
to our own analysis.
Therefore, we decided to present an analysis of Xagent mainly based on the source code,
and not on binaries, to ease the explanations.
In order to facilitate the reading of the source code, we made the following syntactic choices:
- Parts of the code not relevant to our analysis have been replaced by […]
- As the code is heavily commented by its developers, we decided to leave those comments
untouched. For the reader this comes at the price of enduring poorly-worded English
comments, but this allows a finer understanding of what the developers were thinking.
- Our own comments on the code appear after the snippets, and are indicated by numbered tags
- When the developers’ comments are in Russian, we added the translation in the form
of /* Translates to: …*/
-----
### En Route with Sednit
###### Initialization
We begin our journey through Xagent source code in the file main.cpp in the function
```
startXagent(), which contains the instantiations of the main objects, as shown below.
int startXagent(wstring path)
{
[...]
```
`AgentKernel krnl( (wchar_t *)path.c_str() );` ➊
`IAgentChannel* http_channel = new HttpChannel();` ➋
```
//IAgentChannel* smtp_channel = new MailChannel();
```
`IAgentModule* remote_shell = new RemoteShell();` ➌
```
IAgentModule* file_system = new FSModule();
//IAgentModule* key_log = new RemoteKeylogger();
```
`krnl.registerChannel(http_channel);` ➍
```
//krnl.registerChannel(smtp_channel);
krnl.registerModule(remote_shell);
krnl.registerModule(file_system);
//krnl.registerModule(key_log);
```
`krnl.startWork();` ➎
```
[...]
}
```
➊ Instantiation of an AgentKernel object, called “kernel” hereafter, which is the Xagent
execution manager.
➋ Instantiation of an IAgentChannel object, called “channel” hereafter, which is the means
of communication with the C&C server. The source code contains two different channel
implementations, one over HTTP and one over email. Here the developers have commented
out the email channel instantiation.
➌ Instantiations of several IAgentModule objects, called “modules” hereafter, which implement
Xagent functionalities. Here the developers have commented out the keylogger
module instantiation.
➍ Calls to the AgentKernel::registerChannel() and AgentKernel::registerModule()
methods, through which the kernel starts managing these modules’ executions, and pass
their communications through the registered channel. Registrations of the unused channel
and module are commented out.
➎ Call to the AgentKernel::startWork() method, which creates execution threads
on the worker methods of each registered module and channel.
Commenting out module and channel instantiations is a strategy we previously observed when
analyzing Xagent binaries. Each sample does indeed come with a specific combination of modules
and channels, even though the Xagent kernel is completely capable of managing all of them
in parallel (including multiple channels).
By doing so, operators probably intend to adapt Xagent binaries for specific targets, and avoid
exposing the whole Xagent code to security researchers. Moreover, operators may still deploy
additional modules and channels during execution, as we will explain later.
-----
### En Route with Sednit
###### Modules
The core Xagent functionalities lie in its modules. As shown in the startXagent() snippet,
Xagent Linux source code contains three modules, plus the kernel which is itself also a module.
These modules are listed in Table 1:
Table 1. **Xagent version 2 Linux modules**
Name ID Purpose Name of equivalent module
on Windows
`AgentKernel` `0x0002` Manages Xagent execution and relay
communications between the modules
and the C&C server
```
AgentKernel
```
`RemoteKeylogger` `0x1002` Logs keystrokes `ModuleRemoteKeyLogger`
`FSModule` `0x1122` Provides wrappers for file system
operations (find, read, write, execute, etc)
`RemoteShell` `0x1302` Executes supplied commands in Linux
command-line interpreter /bin/sh
```
ModuleFileSystem
ProcessRetranslatorModule
```
As shown in the second column, each module is identified by a 2-byte ID, which is a combination
of a version number and a module identifier. For example, when AgentKernel ID is set to 0x0002,
it corresponds to version 2 and the module numbered 0.
Currently distributed Xagent binaries possess a kernel ID of 0x3303,
thus corresponding to kernel version 3 and the module — strangely — numbered 33. The oldest Xagent versions had a kernel ID of 0x0001.
Each Linux Xagent module has an equivalent module in the Windows version, as shown in the fourth
column of Table 1 (Windows names come from Run-Time Type Information (RTTI) [12] left in some
binaries). Due to operating system peculiarities, the module implementations differ between
Windows and Linux, but their IDs and the commands they accept are the same.
In the following section, we will present an in-depth description of the kernel module, leaving aside
the other, more straightforward, modules.
While recent versions of Xagent for Windows only have the modules
described in Table 1, older versions have been seen with additional modules,
such as:
- `DirectoryObserverModule, which monitors all mounted volumes for files`
with specific extensions (.doc, .docx, .pgp, .gpg, .m2f, .m2o)
- `ModuleNetFlash, which monitors removable drives for C&C messages,`
in a similar way to Usbstealer _[5]_
- `ModuleNetWatcher, which maps network resources`
-----
### En Route with Sednit
###### Kernel
As described in Table 1, AgentKernel is the execution manager, and the only module
that has to be present in all Xagent binaries.
Constructor
Our analysis of AgentKernel begins in its constructor:
```
AgentKernel::AgentKernel(wchar_t *path_Xagent)
{
[...]
```
`local_storage_ = new LocalStorage(path_Xagent);` ➊
```
[...]
cryptor_ = new Cryptor(kernel_main_crypto_key, sizeof(kernel_main_crypto_
```
`key));` ➋
```
[...]
```
`channel_controller_ = new ChannelController(this);` ➌
`reserved_ = new ReservedApi();` ➍
```
[...]
```
`modules_.insert(modules_.begin(), this);` ➎
```
}
```
➊ Instantiation of a LocalStorage object, which is the kernel store. It contains both
a file-based storage for the communications with the C&C server, and an SQLite3 [15]
database to store various configuration parameters.
➋ Instantiation of a Cryptor object, which is the cryptographic engine of the kernel.
It will serve in particular to encrypt the communications with the C&C server.
➌ Instantiation of a ChannelController object, which is the interface to contact
the C&C server, as we will explain later.
➍ Instantiation of a ReservedApi object. It implements some helper functions used by the kernel,
like ReservedApi::initAgentId() to generate a 4-byte ID for the Xagent infected computer.
➎ The kernel being a module, it inserts itself in the list of modules whose execution will be managed.
In the kernel constructor code and elsewhere, important strings are accessed through a class
named Coder, which is a wrapper around an encrypted string. The string is then decrypted on-demand
by an exclusive-or (XOR) with a key defined at the time the Coder object was instantiated.
-----
### En Route with Sednit
For example, in the following code snippet KERNEL_PATH_MAIN_KEY is the encrypted string
and mask the key, while the decrypted string is then retrieved by calling the method
```
Coder::getDencodeAscii() [sic].
Coder* coder = new Coder((u_char *)KERNEL_PATH_MAIN_KEY,
sizeof(KERNEL_PATH_MAIN_KEY), mask, sizeof(mask) );
string name_bd = coder->getDencodeAscii();
```
This mechanism theoretically allows Xagent to keep strings encrypted until they are used.
Nevertheless, a macro in the source code allows them to be left unencrypted (the key in Coder
being forced to zeros), which is actually the case in all Linux binaries we analyzed. On the other
hand, the Coder class is indeed used with encrypted strings in Windows Xagent.
The kernel constructor code refers to some configuration parameters whose
values are hardcoded in the header file AgentKernel.h. The definitions
of these parameters appear to have been automatically extracted from
a XML file, as shown for example below for the Xagent mutex name.
```
/* */
/* */ /* */
/*
*/
/* */ ; /*
config> */
/* */
```
-----
### En Route with Sednit
###### Core Logic
As for all modules, the core logic of the kernel lies in its run() method, on which an execution thread
has been created by the previously described startWork() method. The purpose of the kernel run()
method is to relay the communications between the modules and the C&C server, as shown in Figure 5,
and as described below.
Modules
AgentKernel::giveMessage() AgentKernel::run()
AgentKernel::takeMessage()
Reports to C&C server
RemoteShell::giveMessage()
the list of installed modules
RemoteShell::takeMessage()
FSModule::giveMessage() Fetches messages from
modules for the C&C server
FSModule::takeMessage()
Fetches messages
RemoteKeylogger::giveMessage() from C&C server for modules
RemoteKeylogger::takeMessage()RemoteKeylogger::takeMessage()
AgentKernel::translateToModule() AgentKernel::translateToController()
1. Decrypts message 1. Encrypts message
2. Transfer to intended module 2. Stores it into LocalStorage
_get_questions Local Storage
(C++ vector) (File on harddrive)
ChannelController::getDataToServer() ChannelController::sendDataToServer()
If there is an inbound
If currently selected
packet in currently selected channel is not working, Fetches message from Sends it through currently
channel, writes it into switch to another channel LocalStorage selected channel
```
_get_questions vector
```
IAgentChannel::getRawPacket() IAgentChannel::sendRawPacket()
**Legend**
Data flow
Unencrypted messages
(ModuleMsg objects)
Data flow
Encrypted messages
(CryptRawPacket objects)
C&C Server Control flow
connected to Internet C++ method
Figure 5. **Xagent communication workflow**
-----
### En Route with Sednit
Hello Message
First things first, AgentKernel::run() reports the list of installed modules to the C&C server.
More precisely, the kernel behaves as if it had received a command called PING_REQUEST from
the C&C server (the kernel’s commands will be described in the following section). It then builds
a report in a ModuleMsg object, which is the class encapsulating messages to or from modules,
and whose important fields are shown in the following code snippet.
```
class ModuleMsg
{
private:
// ID агента от/кому предназначено сообщение
/* Translates to: The agent ID from/to whom the message is intended */
int agentId;
// ID модуля от/кому предназначено сообщение
/*Translates to: The module ID from/to whom the message is intended */
u_short modId;
// ID команды, которую выполнил модуль или которую нужно выполнить
/* Translates to: ID of the command that was executed, or will be executed */
u_char cmdId;
// Указатель на память, где лежат данные команды
/* Translates to: Pointer to the memory where data are */
u_char* data;
[...]
}
```
In this report message the modId field is set to the kernel ID 0x0002, cmdId to PING_REQUEST,
and data points to the list of installed module IDs separated by the character #.
The ModuleMsg object is then passed to the AgentKernel::translateToController() method,
which takes charge of its encryption, resulting in a CryptRawPacket object. This object just contains
a pointer to a buffer whose format is described in Figure 6.
Header
**0** **4** **8** **n-15** **n-4** **n**
Agent ID Checksum Serialized ModuleMsg `DATA_TOKEN` RC4 register
**Legend**
Unencrypted text data
RC4-encrypted data
Figure 6. `CryptRawPacket data buffer format`
The buffer starts with a header composed of the agent ID and a checksum calculated on the rest
of the data. This checksum is a 2-byte cyclic redundancy check (CRC) [16] calculated on the data
with a 2-byte pseudo-randomly generated polynomial. These two values are appended to each other
to form the checksum field 4-byte value.
-----
### En Route with Sednit
Then comes the serialized ModuleMsg object followed by an 11-byte value named DATA_TOKEN, both
RC4-encrypted. The DATA_TOKEN value is hardcoded in the source code and probably serves to check
the integrity of the message during decryption by the C&C server. The key used for RC4-encryption
is the concatenation of a hardcoded 50-byte value and a pseudo-randomly generated 4-byte value,
named register and appended to the encrypted data.
The exact same 50-byte value is used to form an RC4-key, also with
a “register”, in Downdelph and Seduploader.
As shown in Figure 5, the resulting buffer is written into a file maintained by the LocalStorage
object. The encrypted data are then retrieved from this file and sent to the C&C server
by the ChannelController::sendDataToServer() method, through the currently selected
channel (channel implementation will be described in the next section).
Communications Loop
As shown in Figure 5, AgentKernel::run() then enters in an infinite loop relaying communications
between the modules and the C&C server:
- It fetches ModuleMsg objects from the modules, which are then transmitted to the C&C server
by the process previously described for the initial report. For example, the RemoteKeylogger
module regularly sends a message containing the captured keystrokes to the C&C server.
- It retrieves CryptRawPacket objects sent by the C&C server from a C++ vector dubbed _get_
```
questions and filled by the ChannelController::getDataFromServer() method. Those
```
objects are decrypted and deserialized into ModuleMsg objects, which are then transmitted
to the intended module. For example, the C&C server can send a message with the command
```
START for the RemoteKeylogger module, which then begins its keylogging activity.
```
Accepted Commands
The kernel accepts 12 different commands from the C&C server, as listed in Table 2. In practice these
commands are integer values corresponding to macros defined in the source code.
Table 2. `AgentKernel accepted commands`
Name Integer Purpose
Value
`GET_AGENT_INFO` 1 Reports IDs and settings of modules and channels to the C&C server
`PING_REQUEST` 2 Reports IDs of modules to the C&C server
`CHANGE_PING_TIMEOUT` 31 Sets the parameter defining the amount of time to wait before initially
contacting the C&C server to the given value
`CHANGE_STEP_TIME` 32 Sets the parameter defining the amount of time to wait between
two attempts to reach the C&C server to the given value
`SET_PARAMETERS` 33 Saves the two previous parameters current values into the LocalStorage
SQLite3 database, such that those values will be re-used at next startup
`CHANGE_CHANNEL` 41 Changes the currently selected channel to the channel identified
by the given ID (see next section for details on the channels)
-----
### En Route with Sednit
Name Integer Purpose
Value
`CHANNEL_SET_` 42 Changes the settings of the channel identified by the given ID.
`PARAMETERS` For example, it may be used to change the C&C server address.
`LOAD_NEW_MODULE` 51 Instantiates an IAgentModule object from the given data, and
registers this new module with the kernel
`UNLOAD_MODULE` 52 Unloads the module identified by the given ID
`LOAD_NEW_CHANNEL` 53 Instantiates an IAgentChannel object from the given data,
and registers this new channel with the kernel
`UNLOAD_CHANNEL` 54 Unloads the channel identified by the given ID
`UNINSTALL_XAGENT` 61 Kills the Xagent process (no uninstallation procedure implemented)
###### Communication Channels
The ChannelController object is in charge of contacting the C&C server through the currently
selected communication channel, as shown in Figure 5. This controller is unaware of the underlying
implementation of the channel, and can use for that purpose any object implementing the abstract
class named IAgentChannel.
The Linux source code contains two channels, one using HTTP and one using emails, as described
in Table 3.
Table 3. **Xagent version 2 Linux channels**
Name ID Network Protocols Name of equivalent channel
on Windows
`HttpChannel` `0x2102` HTTP `WinHttp`
`MailChannel` `0x2302` SMTP to send emails and POP3
to receive emails (over TLS)
```
AgentExternSMTPChannel
```
(only to send emails)
Each channel is identified by a 2-byte ID similar to the previously described module ID. There exists
an implementation for the HTTP-based channel on Windows, while we only found a channel to send
emails, without the ability to receive emails, on this platform.
By implementing the IAgentChannel abstract class, the channels provide a getRawPacket()
method to fetch a message from the C&C server, and a sendRawPacket() method to send
a message to the C&C server. As previously explained, those messages are CryptRawPacket objects.
We describe in this section the implementations of these methods for the two Linux channels.
While Xagent samples usually come with only one channel, the Channel```
Controller object can manage several of them in parallel. In particular it
```
will automatically switch to a different channel — if there is one — in case the
currently selected one is broken, as shown in Figure 5. Additionally, the operators can deploy a completely new channel through the previously described
```
LOAD_NEW_CHANNEL kernel command.
```
-----
### En Route with Sednit
###### HttpChannel
The HttpChannel::getRawPacket() method is implemented as a HTTP GET request — the message
from the server being then in the HTTP answer body — while HttpChannel::sendRawPacket()
is an HTTP POST request, whose body contains the message. The C&C IP address is hardcoded
in the associated header file HttpChannel.h.
Both GET and POST requests are done on a URL following the format pictured in Figure 7.
Series of randomly
chosen characters
from base64 alphabet
|Col1|Series of ra chosen cha|
|---|---|
||chosen ch from base|
|||
```
http://X.X.X.X/path/?parameter1=value1¶meter2=value2&...&mark-token&...
```
Chosen among
15 possible values
|eter1=value1¶me|Col2|
|---|---|
|||
||Chosen a|
Figure 7. URL for GET and POST requests, X.X.X.X being the C&C server IP address
Roughly summarized, this URL is a series of pseudo-randomly chosen parameters associated
with pseudo-randomly generated values, except for a special parameter called mark. This special
parameter (whose value is set to ai in the Linux source code) is associated with a so-called token,
which is a 20-byte value encoding the agent ID in the format pictured in Figure 8.
**0** **5** **9** **16** **20**
Junk Key `URL_TOKEN xor key` Agent ID
**Legend**
Randomly chosen Base64
characters from encoded data
base 64 alphabet
Figure 8. Format of the token value
In this token, the Key is pseudo-randomly generated, while URL_TOKEN is hardcoded in the source
code and probably serves to check the integrity of the message by the C&C server.
The bodies of the POST requests, and of the responses to GET requests, follow exactly the same
format as the token, except that they contain a CryptRawPacket object in place of the agent ID.
Also, the hardcoded value is a different one, called DATA_TOKEN by the developers.
###### MailChannel
The MailChannel object is an implementation of Xagent communication channel over emails,
where messages are sent and received as attachments to emails.
During an investigation, we discovered the source code of a proxy server employed to relay traffic
between Xagent infected computers using MailChannel (dubbed “agents” hereafter) and a C&C server.
This source code was left in an open directory on the proxy server, which was then indexed
by the Google search engine.
-----
### En Route with Sednit
The proxy code is a set of Python scripts containing more than 12,200 lines of code among 14 files;
the files are shown in Figure 9. It also contains some log files indicating it was in use from April 2015
to June 2015.
```
$ls -hog
877B 27 Feb 2015 ConsoleLogger.py
4.8K 14 Apr 2015 FSLocalStorage.py
6.9K 14 Apr 2015 FSLocalStorage.pyc
1.6K 27 Feb 2015 FileConsoleLogger.py
2.6K 7 Apr 2015 FileConsoleLogger.pyc
5.8K 27 Feb 2015 MailServer.py
11K 7 Apr 2015 MailServer2.py
9.6K 16 Apr 2015 MailServer3.py
2.3K 7 Apr 2015 P2Scheme.py
2.2K 7 Apr 2015 P2Scheme.pyc
1.6K 7 Apr 2015 P3Scheme.py
2.4K 7 Apr 2015 P3Scheme.pyc
745B 27 Feb 2015 WsgiHttp.py
2.3K 14 Apr 2015 XABase64.py
3.1K 14 Apr 2015 XABase64.pyc
0B 6 Apr 2015 __init__.py
2.9M 19 Jun 2015 _w3.log
12K 16 Apr 2015 _w3server.log
1.5K 3 Apr 2015 quickstart.py
2.4K 15 Apr 2015 settings.py
1.6K 15 Apr 2015 settings.pyc
4.2K 15 Apr 2015 w3s.py
605B 27 Feb 2015 wsgi.py
```
Figure 9. Proxy server source files
As can be seen from the files’ names, the proxy is actually more than a simple relay of communications:
it translates the email channel protocol from the agents into HTTP requests for the C&C server.
Therefore, we decided to include this proxy in our analysis of the email communication channel.
Figure 10 represents the whole communication workflow that will be described in this section.
-----
### En Route with Sednit
**P2Scheme**
(”Level 2 Protocol”)
Proxy Server
**P3Scheme**
(”Level 3 Protocol”)
Email received at
exfil@example.com
Email received at
orders@example.com
|MailServer.py For all known agents Fetch new email Send “TO” folder content as email attachment Validate email subject if valid Save attachment in “FROM” folder of the sender agent Server Storage folders for agent 9312312 FROM TO w3s.py Send “FROM” folder content Ask C&C server for data to C&C server and stores it into “TO” folder For all known agents eme rotocol”)|Col2|Col3|Col4|
|---|---|---|---|
||MailServer.py For all known agents Fetch new email Send “TO” folder content as email attachment Validate email subject if valid Save attachment in “FROM” folder of the sender agent Storage folders for agent 9312312 FROM TO w3s.py Send “FROM” folder content Ask C&C server for data to C&C server and stores it into “TO” folder For all known agents|||
C&C Server
connected to Internet
Figure 10. Communication workflow between an Xagent infected computer using
```
MailChannel and its C&C server, via a proxy server
```
-----
### En Route with Sednit
The proxy source code contains a few unused instructions related to agents
communicating over HTTP, i.e. using HttpChannel rather than MailChan```
nel. Nevertheless, the main class responsible for relaying HTTP traffic
```
from agents — named W3Server — is absent and its instantiation has been
commented out. Similar to Xagent, the operators therefore seem to deploy
the components of the proxy server only if needed, and this one was intended
to relay MailChannel traffic only.
On the Agent
The MailChannel::sendRawPacket() method is in charge of sending CryptRawPacket objects
as email attachments. For that purpose, the code contains an SMTP server address with an email
address and a password to log in, plus a recipient email address to which the emails will be sent.
Depending on the sample, this recipient email address may belong to a freemail provider, a custom
Sednit domain, or even a hacked target.
Building a C&C protocol over email brings at least two problems for the operators: they need
to be able to distinguish Xagent emails from unrelated emails in the inbox (like spam emails),
and they need to bypass spam filters. To do so, they implemented a protocol named P2Scheme
(and dubbed “P2” hereafter), which defines the format of the emails. This protocol is described
as a “level 2 protocol” by the developers, and defines the following email fields:
- The email subject is the base64 encoding of a value following the format pictured in Figure 11.
**0** **5** **12** **16**
Key `SUBJ_TOKEN` Agent ID xor
xor key key
Figure 11. Email subject generated by the P2 protocol.
In this format, the Key is pseudo-randomly generated, while SUBJ_TOKEN is a 7-byte value
hardcoded in the source code and strangely containing the string “china” (prefixed with bytes 0x55
```
0xAA). This specific subject serves to distinguish Xagent emails from unrelated emails in an inbox,
```
as we will explain.
- The email body and the attachment name are the base64 encodings of pseudo-randomly
generated values.
- The boundary value, used to separate a MIME multipart message in parts [17], is a pseudorandomly generated value.
Nevertheless, in practice only the boundary is actually generated with the P2 protocol, as the code
to generate the others fields has been commented out in the Linux source code. Instead, these fields
are set to fixed values, likely chosen to avoid attracting attention from Georgian targets:
- the email subject is set to piradi nomeri, which refers to a national ID number in Georgian
- the email body is set to gamarjoba, which means hello in Georgian
- the attachment name is set to detaluri_X.dat, where X is the current time (detaluri
means detailed in Georgian)
-----
### En Route with Sednit
Georgian institutions are well-known targets of the Sednit group,
as documented by FireEye in 2014 [9].
Once the email has been built, the CryptRawPacket object is added as an attachment. Finally,
the email is sent with the SMTP protocol over TLS to the recipient email address (exfil@example.com
in Figure 10). It will be retrieved by the proxy server, and the message will be forwarded
to the C&C server, as we will describe below.
In the other direction, the MailChannel::getRawPacket() method retrieves emails containing
messages from the C&C server with the POP3 protocol over TLS. The email address to receive messages
is a different one than the one used to send messages (orders@example.com in Figure 10). For each
received email, the method checks that the subject is set to piradi nomeri and, if so, instantiates
a CryptRawPacket object from the attachment, which is then transmitted to the intended module.
On the Proxy Server
The MailServer.py script manages the communications by emails with the agents. To do so,
it regularly fetches emails from the inbox agents have sent their messages to (exfil@example.com
in Figure 10).
The script then checks for each email whether the subject matches the P2 protocol; that is, if once
decoded it contains the SUBJ_TOKEN value (see Figure 11). Alternatively, it checks whether the subject
is set to piradi nomeri, which is the case with the Linux source code as we just explained.
If the subject is valid, MailServer.py stores the email attachment into a “FROM” folder associated
with the sender agent, using a custom format defined in a class named P3Scheme. This format, dubbed
“level 3 protocol”, is a variation of the one presented in Figure 8 for the HTTP token: namely,
the length of Junk is set to 9 and the hardcoded value is different.
The script LocalStorage.py manages a storage with a “FROM” and “TO”
folder for each agent that sent an email to the monitored inbox (the agent ID
being retrieved from the CryptRawPacket attached to the email).
The second important script is w3s.py, which manages the HTTP communications with the C&C server.
For all known agents, the script retrieves the messages dropped in the “FROM” folder, and sends them
to the C&C server in the body of a HTTP POST request. The URL for this request is built by the following
Python code:
```
BASE_URL = “http://” + XAS_IP + XAS_GATE
def url_for_agent(agent_id):
url = BASE_URL + “?s=” + P3_Scheme.pack_service_data(struct.pack(“