Communications with Controller
PoisonFrog relies solely on DNS A records for communications. These communications are issued via calls to .NET class method [System.Net.Dns]::GetHostAddresses. To receive tasking, PoisonFrog generates DNS requests and interprets the received IP address responses. Once tasking is received, it processes the tasks and sends the results back to its controller. This process is performed via more complex, specially-crafted DNS requests.
To build a DNS query properly, PoisonFrog first generates an agent ID used for building all future DNS requests. The generation procedure involves using the first ten characters of the string “atag121234567890,” where UUID is obtained from a WMI query for Win32_ComputerSystemProduct’s UUID property, after removing dashes.
A DNS request is built by calling a function with several parameters. The most important parameters are the action, the payload, an associated file name, and whether the malware is sending tasking results or receiving tasking. When calling the function to create a request for tasking, the payload and associated file names are empty. These parameters are populated only when sending results back to the controller, a process which will be discussed later in this article.
Checking For and Receiving Tasks
For requests to receive or check for tasking, PoisonFrog builds a query in the following format:
[control data][management data].[domain]
Here, [control data] is the agent ID into which a one-character action and three-character request number are randomly inserted. The positions of these randomly-inserted values are subsequently embedded in management data so the controller knows where to find them.
Next, [management data] is built as follows:
[1 to 7 random hex characters]A[index of request number][index of action]7
The characters ‘A’ and ‘7’ are hardcoded separators that indicate the zero-based indices where the request number and action can be found the control data.
Consider an example DNS query of ata005g1128931B75FEC6A357.myleftheart[.]com where the offset for the request number is 005 with a chosen random offset of 3 and an action of 1 with a chosen offset of 5. PoisonFrog first inserts the action at the chosen offset and then the request number. The table below illustrates how this process is completed:
To understand the entire DNS request generated by PoisonFrog to check for tasking, consider the following example of ata000g1028931B75FEC6A357.myleftheart[.]com, which breaks down as follows:
Action values indicate in which mode the malware is operating and have the following meanings:
After checking for tasking, the controller will send the appropriate IP address in response. The following table shows the various IP addresses that can be sent and their meanings. In the table, the step value indicates the order in which these steps will occur to successfully transfer tasking to PoisonFrog:
Once the tasking is saved to a file, PoisonFrog will exit its receive loop and begin to process the tasking. The tasking is processed by examining the last character in the filename received in step 1 above () and performing the following operations:
Sending Task Results
After processing the tasking, PoisonFrog transmits the results back to the controller by sending the controller DNS requests encoded with the exfiltrated data. PoisonFrog then breaks up the data into smaller messages to be sent with payload chunks of up to a maximum size of 60 bytes. The controller data is sent using the DNS request builder function from above, this time in “send” mode. The send mode DNS request now includes more fields for this payload data and an associated file name, both of which are encoded using a function called “resolver” which marshals the data to be transmitted by rearranging the nibbles of each byte. The resolver function is explained in further detail below.
Once the payload has been resolver-encoded, PoisonFrog prepends the string “bWV0YT” (without quotes) to it to indicate the start of the transmission of tasking results. Next begins a loop of DNS requests, each containing a chunk of the payload until the contents have been completely transferred. To signal completion of the file transfer, PoisonFrog will issue a final DNS request containing a payload solely consisting of the string “bWV0YTZW5k” (without quotes). When transmitting tasking results to the controller, an action mode of “2” is used.
The table below shows an example of the complete exfiltration of a file containing the output of the ‘hostname’ command:
Using the example above, a more detailed breakdown of chunk #0 is provided below:
For each DNS request issued, the controller can respond with an IP address of 126.96.36.199 (indicating the transmission should be cancelled) or an IP address of the format 1.2.3.[X], where [X] is used to request sending the next chunk of data.