In a recent blog post (link here) we analysed the first part of an operation likely conducted by APT38/Lazarus, which targeted various organizations, including financial and banking ones. We already described the initial phase of the kill chain where we get to describe the fact that the actor implemented in the operation two different first-stage payloads to be released to the victims on the basis of their system architecture. These payloads are used in order to carry out a first recognition phase. Beyond this, we have already described a first-level backend script used by the threat actor inside a compromised website to manage victims and to release an additional payload if the victims are of interest.
The object of this new analysis is the second-stage payload contained in the first-stage backend script, which is decrypted, loaded into the first-stage implanter and then executed.
In particular, this post will focus on the interaction between the second-stage payload and a new remote second-stage backend VBS script that we had the opportunity to analyze.
// Second-Stage C2 Backend
We started the analysis with a brief look at the backend page. The compromised websites, used as a C2 for the executable counterpart, include a second-stage ASP page with an obfuscated VBScript which acts as a backend for the main backdoor. It contains functions called by the second-stage payload in order to regulate its behaviour, to issue commands in the context of the infected system and to grab the exfiltrated data.
The main section of the second stage backend script, executed when processing an incoming HTTP POST request, does the following:
- it executes a setFile Sub which logs a doubly encrypted and encoded line with the date and time of the request, the ip of the client host, its user agent, and all the fields in the body of the request, appending it in the file fav.jpg
- it decodes and decrypts the body of the request which contains four url-encoded parameters
- uses the decoded and decrypted data of the request to perform several actions based on a switch-case statement which takes a command string, given in the request, as an input.
The first field of the body of the HTTP request, called id, is composed of two parts; the first 13 chars contain the encoded key which is used to decrypt the rest of data, the subsequent characters contain the encoded and encrypted names of three other fields of the body in the form “%s:%s:%s”.
The role of those fields depends on their position in that string: the field with the first name contains the communication identifier “strBoardID”, the field with the second name contains the command string “strUserID”, given as an input to the switch case that decides which function to execute in the backend script, the field with the last name “strBase64” is used to carry additional information, such as the content of user files or other exfiltrated data.
An example of a request body, taken from a communication between the backdoor and the script, is the following:
The preceding body was taken from a “Connect” command which is the first action taken by the backdoor and it will be detailed in the next paragraph.
// First Connection
As soon as the backdoor is executed, it tries to instantiate a communication channel with the C2 script, selected from a array of compromised websites, by performing the following actions:
- At first, the DLL calculates an encoded base64 string, called id, used to perform the interactions with the C2 server. The first 13 characters of the string are used as key to encrypt the remaining characters of the string.
- The characters encrypted are the parameters used for the three body arguments sended in the POST request used for the interaction.
The parameters generated change for each interaction performed. The first parameter contains the communication identifier strBoardID, the second parameter contains the string “T1B7D95256A2001E” that represents the command to invoke the “Connect” function on the backend, used to initialise the communication channel between the DLL and the C2, and the last parameter is empty.
- The “connect” function in the C2 maintains a log for the each specific connection storing in the “/KB93″+ “strBoardID” + “.jpg” file the encrypted strBoardID identifier and the victim IP, used as token to keep trace of the connection.
- To check whether to proceed or not, during the “connect” execution function, the C2 contacts the killswitch IP located at IP 18.104.22.168 on port 8000. The address is contained in “image.dat”, an encrypted file stored in the C2 filesystem. If the the killswitch server is reachable, the C2 responds to the malware with the strBoardID that indicates to proceed with the DLL execution, else it responds with a 0000 to abort the execution.
// Operating logic
If a communication channel is successfully instantiated, the backdoor sends a second request with an empty command string for the variable strUserID, which results in the execution of the default case of the backend script. The default case lands on sub “TransFile“.
The TransFile Sub is the core function of the backend script, since it is used both to save exfiltrated user data on the server and to send following commands issued by the attacker.
It’s behaviour varies according to the length of the strBoardId passed in the HTTP POST request: if the strBoardId is 4 chars or less, it saves the data passed in the strBase64 field of the request on the C2 filesystem and proceeds its execution; if it’s longer, it discards the first character and proceeds its execution.
The second part of the TransFile sub is a cycle which looks for a file named image201[4/5]<strBoardID> (for example image20151033), sleeping through each cycle up to 400 times. The file contains the encoded command that has to be executed on the backdoor DLL. If the file is found during the cycles, it’s read and the encoded command is sent back to the client.
While analyzing the backdoor we observed that the initial strBoardID generated by the DLL during the connection phase (first request) is a random 4 digits number. In the second request another digit is appended, thus resulting in a 5 digits strBoardId with the last 4 digits being the same.
This bypasses the file saving part described above and goes directly to the instruction part of the sub, haveing a strBoardID which is the same first 4 digits.
// Instruction decoding and execution in the backdoor
As described in the preceding paragraph, the TransFile sub reads the next command issued by the attacker from a file and returns it to the backdoor.
In fact, after the Connect request and the first TransFile request, the second-stage payload waits for the data and extracts a value used to select which branch should be taken in a switch-case statement.
The switch-case is the core of the second-stage payload and contains all the backdoor functionalities, ranging from sending disk info, file attributes, file contents, active RDP sessions, system information, processes information and more .
This threat actor appears to be very prolific and active in various sectors, ranging from governments and institutions to private financial organizations. The pattern observed within this operation consists of a two stage attack: a first-stage implanter is used to deliver the second stage backdoor to the selected victims (more info on the selectivity on the previous post). The operation is carried out through interactions with a series of compromised classic ASP websites used as CnC. We conclude this post by highlighting a peculiar killswitch control, which suggests an increasing attention of the actor for the security of its operation.
// Indicators of Compromise
Domain Name (compromised): curiofirenze.it
Domain Name (compromised): elite4print.com
IP Address: 22.214.171.124
IP Address: 126.96.36.199
Further information about this campaign, the full set of indicators of compromise and detection rules are available consulting the investigation ATR:78456 on our cyber threat intelligence portal.