# Inside the APT28 DLL Backdoor Blitz **[threatvector.cylance.com/en_us/home/inside-the-apt28-dll-backdoor-blitz.html](https://threatvector.cylance.com/en_us/home/inside-the-apt28-dll-backdoor-blitz.html)** The BlackBerry Cylance Threat Research Team [This blog post is a follow-up to Flirting With IDA and APT28, where we covered generating](https://threatvector.cylance.com/en_us/home/flirting-with-ida-and-apt28.html) IDA Pro signatures to identify and eliminate benign library code. In doing so, we can focus our attention on the bespoke code responsible for defining the implant’s behavior. This time around we perform a deep dive into the same APT28 sample by analyzing its capabilities and providing insight into its features. ## Overview **Hash:** B40909AC0B70B7BD82465DFC7761A6B4E0DF55B894DD42290E3F72CB4280FA44 **File Type: Windows x64 DLL** **PE Compilation Timestamp: 4 July 2018 14:38:54th** _Figure 1: APT28 sample details_ Analysis reveals the implant is a multi-threaded DLL backdoor that gives the threat actor (TA) full access to, and control of, the target host. When commanded by C2, the implant can upload or download files, create processes, interact with the host via a command shell and connect to C2 according to a defined sleep/activity schedule. As covered in [Part 1, the implant is written in C++ and statically linked against OpenSSL and](https://threatvector.cylance.com/en_us/home/flirting-with-ida-and-apt28.html) the Poco C++ framework. Since the file is packaged as a DLL, the intention would be to inject it into a long-running process that is granted Internet access (such as a NetSvc service ----- group) or one having local firewall permissions. We do not believe this DLL is intended to operate as a module for a larger tool. ## Entry Point Malicious code entry occurs via the DllMain export. The implant’s first task is to load the legitimate Microsoft npmproxy.dll found in “c:\windows\system32”. With this loaded, the addresses of the five implant exports, “DllCanUnloadNow”, “DllGetClassObject”, “DllRegisterServer”, “DllUnregisterServer” and “GetProxyDllInfo” are set to the addresses of the same, benign exports found in the Microsoft DLL. The reason for this is unconfirmed, but most likely serves a defensive measure to evade end point protection that scans export addresses looking for code changes (when compared to a predetermined signature database), or against a database of known-malicious code. Perhaps by setting its own exports to those of the benign copy, the implant is attempting to remain undetected: _Figure 2: Substitution of PE export addresses_ With export addresses replaced, a thread is launched to execute the main code path. Within this, a second thread is launched responsible for send and receive operations with C2. A global variable forms the basis of inter-thread synchronization for processing of C2 messages. ## Mutex The primary thread’s first task is the creation of a Globally Unique ID (GUID) mutex “1b8232f6-6806-4733-901d-62bf3ef33e6c”. The GUID string can be found as plain text within the binary, offering a potential (albeit trivially replaceable) IoC. As is customary, if mutex creation fails the sample terminates with no further action taken. ## Machine Fingerprint Following mutex creation, the implant generates a unique CRC-32 host fingerprint using the primary network interface’s ethernet (MAC) address, the host name, and Windows version string. The final CRC-32 result is then XOR’d with fixed constant 0x64113. The generated host fingerprint is used later to build the C2 beacon URL, and presumably identifies the implant’s malicious use on each infected machine. ## Command-and-Control (C2) ----- The main communication protocol with the C2 server is RSA encrypted, Base64 encoded JSON exchanged over HTTPS (TLS, port 443), or as fallback, on plain HTTP using port 80. During our analysis the implant did not attempt to use any other application protocols. The user-agent string for HTTP requests is populated from either the return value of the “ ObtainUserAgentString” API call, or if that fails, a hard-coded alternate (see IoCs below). Support for egress proxy servers is included through a call to “ WinHttpGetIEProxyConfigForCurrentUser”. The result is parsed and supplied to the Poco framework’s “ HTTPClientSession::setProxyConfig” prior to C2 activity. A 1024-bit RSA key pair is embedded within the implant and used to encrypt and decrypt communication between host and C2. The private key decrypts inbound traffic while the public key encrypts outbound. No stream cipher(s) or session keys are negotiated. The initial HTTPS beacon to “malaytravelgroup[.]com” is a GET request consisting of a randomly selected URL path concatenation, together with a query string containing the parameter split count, the XOR constant 0x64113 (also used when generating the host CRC32), and the computed CRC-32 fingerprint. The query string is padded with random data to prevent ad-hoc analysis and finally Base64 encoded: **Field** **Name** **Bytes** **Value** **Comment** 1 - 1 1-254 Parameter split count as ASCII value. 2 “aid” 4 0x64113 XOR constant used when generating host CRC-32. Possibly a unique implant ID. 3 “bid” 4 _variable_ CRC-32 host fingerprint. _Table 1: C2 beacon query parameters_ The URL path component is built as one to three strings (“/” separated), generated from a set of encrypted string tables. The decrypted versions are provided in the Appendix. The Base64 encoded data is split into a random number of parameters and padded as a means of obfuscation. The query parameter’s names are randomly generated using 1-4 upper/lower case characters: **Name** **Value** **Explanation** ----- <2_rand_chars> + b64() <2_rand_chars> + b64( + ) <2_rand_chars> + b64( + ) Specifies the number of parameters across which the beacon data is split Value contains first part of encoded data, preceded by 2 random characters Value contains second part of encoded data, preceded by 2 random characters ... ... ... <2_rand_chars> + b64( + ) _Table 2: Query parameter deconstruction_ Examples of beacon request URLs: Value contains last part of encoded data, preceded by 2 random characters GET /pricing/training/news/?GPFi=mLMg&CYlp=Tj9RNBBg%3D%3D&JOM=uJfgAz9Zpw GET /forum/feedback/switch/? LnY=YNA&D=TH%2FRM%3D&rMuo=BFXUEG&cs=bkqgA%3D&HZql=bXgTP1mnA%3D HTTP/1.1 GET /activity/? FLVE=JNA&Y=vKYxNB&F=Hg6wY%3D&Slq=QBuAAz&ux=lSGfWacA%3D%3D HTTP/1.1 _Figure 3: Beacon URL examples_ Using the first example in Figure 3, the first query parameter indicating the beacon data split count would be Base64 decoded as: GPFi=mLMg >> b64_decode(Mg) >>0x32 ("2") All successive query parameters have the first two characters removed prior to Base64 decoding. The first byte of the decoded result is then discarded to arrive at the final value: ----- CYlp=Tj9RNBBg== >> b64_decode(9RNBBg==) >> F5 13 41 06 JOM=uJfgAz9Zpw >> b64_decode(fgAz9Zpw) >> 7E 00 33 F5 9A 70 0x00064113 >> XOR constant/implant ID 0x709AF533>> Host CRC-32 fingerprint Once the beacon is received and decoded, the next phase of interaction is to issue commands that drive the implant’s functions, such as the provision of an activity schedule/sleep interval limiting implant activity. ## Domain Generation Algorithm (DGA) The primary C2 domain of “malaytravelgroup[.]com” is used for the initial beacon. Like all sensitive strings, it is XOR encoded and revealed only when needed. The implant also contains a Linear Congruential Generator (LCG) based algorithm for generating what appear to be backup C2 domain names. Curiously the implementation is 100% deterministic owing to the use of a fixed seed value (0xC31) as shown in Figure 4. Every invocation of the DGA will produce the same five domains: schooltillhungryprocess[.]com reasonwithusefulpolicy[.]com streetunderrelevantpeople[.]com experiencewithweakkid[.]com systembeforeniceparent[.]com _Figure 4: Encoded C2 servers_ Once the domains are generated, they are XOR encoded. The LCG implementation can be seen here, together with its constant seed value: _Figure 5: DGA LCG using fixed seed value_ Domain names are generated as the concatenation of 4 string-table lookups from 3 encrypted string tables. Table 3 is referenced twice during generation. The Top-Level Domain (TLD) suffix is hardcoded to “.com”. **Table** **Number of strings** ----- 1 99 2 31 3 149 _Table 3: String table sizes for domain generation_ Assuming the continued adoption of a four-part domain name, the LCG would be capable of generating millions of unique permutations. The reason for limiting its output to the same five, irrespective of date, time, host identity, or other input variable is unclear. A copy of the decrypted string tables is provided in the Appendix. By manually decreasing the delay between check-in attempts, we accelerated the amount of C2 activity generated by the implant. Curiously, during a 24-hour observation window, no attempts were made to communicate with the generated domains. Different reachability scenarios were tested, ranging from malformed responses to unreachable IP addresses. At no point did the implant generate any DNS or HTTP traffic relating to the generated domains. It’s conceivable the backup domains are accessed via HTTP 302 redirects issued by the primary site, but this would seemingly defeat the purpose of having primary and backup domains to cater for failure, migration, or shutdown. It’s also possible the generated C2 domains are active only for certain implant commands such as file upload or download. Lacking any evidence for their direct use, we can speculate the generated domains may be operating as a honeypot. Access to them from any Internet addresses would immediately be considered “suspicious” by virtue of their hidden existence only within the implant code. The source of such requests could be directly attributable to threat researchers or analysts investigating the implant’s inner workings. ## Functions The implant lacks any modularity and is therefore limited to eight functions. Each function is invoked from C2 by supplying a value from which a known CRC-32 is calculated. The computed CRC-32 value serves as a key or look-up to execute the corresponding function. Parameters for each backdoor supported function are supplied with each command and detailed in Table 4: **CRC-32** **Function** **Parameters** **Description** ----- 15512FB9 Spawn process file_name, file_path, args 76BCDC67 Create file file_name, file_path, body Spawn a process using the supplied arguments. Creates a file with the supplied body, i.e. file is pushed (downloaded) from C2. Files have the DOS hidden attribute set by default. Deletes file or folder. Optional recursive parameter for folder and contents deletion. Launches COMSPEC (cmd.exe) shell. Stdin, stdout, stderr relayed over main C2 channel. Read a file, i.e. upload to C2. B21CEBD4 Delete file/folder 406C9E35 Launch shell file_name, file_path, recursive start, stop, status, bash 72E99D37 Read file file_name, file_path 04365407 Set C2 check-in interval 99598005 Set C2 checkin/activity schedule 1E46EC18 Get status information _Table 4: Implant functions_ timeout Sets the interval between C2 check-in. Default is 3 hours. day_of_month, day_of_week, hour, Sets day of month/week and hour that implant should attempt to reach C2. Default setting is 0 for all values, meaning no exclusions; check-in would therefore be every 3 hours – the default sleep interval. _None_ Returns Build_Id of implant, Computer_Id, Full_Info. Details of last command and status (success/fail). The shell capability is perhaps the most interesting, giving the operators a full-duplex, interactive COMSPEC (cmd.exe) session, with stdin (input), stdout, and stderr (output returned by commands) redirected over the HTTPS C2 channel. Commands to the shell are issued by the TA with the resulting output being returned almost immediately. Despite the shell pipe creation taking place in (as identified by IDA signatures) the Poco framework’s “SMTPChannel” constructor, the implant makes no use of SMTP as a transport. The “bash” parameter, synonymous with Linux environments, hints at a multi-platform capability. However, in this instance it is used to send commands to the shell by writing the ----- accompanying value to stdin. Windows 10 does offer a Linux Subsystem that would make a bash shell available, but we have no evidence to suggest this is what the operators are installing or using: _Figure 6: Implant function dispatch_ ## String Encryption Thirteen unique XOR keys are used throughout the implant for runtime decoding of sensitive strings. Each implant function (as listed in Table 4) is provided with its own XOR key, as are general C2, URL/HTTP, and RSA related operations: **Key:** **Used during:** F226E34F0B64528CF0 Embedded RSA key decryption 371F41ABE4C8880BC1 URL/HTTP related operations 40A521B0866411BAC4 General string decryption key EFEA221C400E2D1227 C2 messaging 82EF8E95992055B6B5 C2 messaging 4F840D589769 Create process function 6EFEAF1AAA6932 Create file/download function 59938EF1C8EFBA79B Delete file/folder function 722C1B76 Shell handler function 1F4582D80B Read file/upload function 6A39E0FC68D6 Set C2 check-in interval function A24B726DFD Set C2 activity schedule function ----- 597EB47AAD Get host/install info function _Table 5: XOR encoding/decoding keys_ ## Conclusion Analysis shows the implant carries a feature set designed to provide the fundamental capabilities of a backdoor: file download, upload, remote command execution, and interactive shell access. Comparing the functions of this implant to published descriptions of APT-28’s “x-tunnel”, we find no tunneling, proxying, or VPN-like capabilities. It also lacks credential harvesting, network service scanning, or Windows registry manipulation. Given the lack of modularity only an updated version could provide these features. The alternative (and perhaps more likely) scenario would be for such capabilities to exist in subsequent tools downloaded and executed by this implant. ## Indicators of Compromise (IoCs) **SHA256:** b40909ac0b70b7bd82465dfc7761a6b4e0df55b894dd42290e3f72cb4280fa44 **C2 beacon domain:** malaytravelgroup[.]com **DGA domains:** schooltillhungryprocess[.]com reasonwithusefulpolicy[.]com streetunderrelevantpeople[.]com experiencewithweakkid[.]com systembeforeniceparent[.]com **Mutex:** 1b8232f6-6806-4733-901d-62bf3ef33e6c **Hard-coded User-Agent string:** “ Mozilla/5.0 (Windows NT 6.3; WOW64; rv:28.0) Gecko/20100101 Firefox/28.0” ## Yara Signature ----- rule apt28_backdoor_cls { strings: $st1 = "AES_256_poco" ascii $st2 = "TEncryption" ascii $st3 = "shell" ascii condition: all of them } rule apt28_backdoor_crc32 { strings: $xor1 = { 48 8B 07 39 48 0C 75 3A 44 8B 70 08 4C 8B 38 4D 85 C0 74 2E 45 85 E4 74 29 } condition: $xor1 } ## Appendix **Decrypted String Tables:** **Table 1** **Table 2** **Table 3** different used important every large available popular lonely basic known various difficult several unite historical hot useful mental scare additional at on in to into from before until till about for of with by after since during between near nearby street company part system number world case work party girl house woman life people year day way thing child group ----- emotional old political similar healthy financial medical traditional former entire strong actual significant successful electrical expensive pregnant intelligent interesting poor happy responsible cute helpful recent willing nice wonderful impossible serious huge rare visible typical competitive critical desperate immediate aware educational environmental global decent relevant accurate capable dangerous dramatic efficient powerful foreign hungry behind across above over under below along round around past through time area problem place hand service school guy country point week relationship end word family fact head month information power change question business development home side night money eye interest book teacher air court water manager form food ca moment level room car story market effect idea opportunity result use study job ----- friendly psychological severe suitable numerous sufficient unusual anxious cultural curious famous pure comprehensive obvious careful impressive unhappy acceptable aggressive boring inner eastern sudden reasonable strict weak civil name report body law face authority friend parent minute door minister road rate line hour war mother right office person reason view term period centre morning project research figure society history city police kind million community need tree price team game father kid student support program health field man example quality control ----- action process position education age course type manner order decision industry mind condition paper bank century activity table sense building experience staff language plan policy _Table 6: C2 DGA Strings_ **Table 1** ----- news nwshp section pagead ads forum general topic master explore features enterprise pricing article contact security about status blog training help feedback terms activity pricing switch _Table 7: URL Path String Table_ The BlackBerry Cylance Threat Research Team ## About The BlackBerry Cylance Threat Research Team The BlackBerry Cylance Threat Research team examines malware and suspected malware to better identify its abilities, function and attack vectors. Threat Research is on the frontline of information security and often deeply examines malicious software, which puts us in a unique position to discuss never-seen-before threats. -----