Contributors: Justin Timothy, Threat Intelligence Consultant, Gabe Renfro, DFIR Advisory Consultant, Keven Murphy, DFIR Principal Consultant
Ever since Avast released a decryptor for BianLian in January 2023, the group has moved to extortion-only operations. Since this time, GuidePoint’s Research and Intelligence Team (GRIT) has been keeping a close eye on BianLian’s operations. In conjunction with GuidePoint’s DFIR team, we responded to an incident that began with the exploitation of a TeamCity server which resulted in the deployment of a PowerShell implementation of BianLian’s GO backdoor.
In this blog, we will dive into the following topics:
Let’s get into this.
In a recent intrusion, GuidePoint’s DFIR team observed malicious activity within a client’s network. The threat actor identified a vulnerable TeamCity server and leveraged CVE-2024-27198 /CVE-2023-42793 for initial access into the environment, creating users in TeamCity and invoking malicious commands under the TeamCity product’s service account. The logs required to determine which of the two CVEs the threat actor exploited were not available at the time of analysis.
After initial access into the environment, the threat actor discovered additional infrastructure in the victim’s network by using Windows native commands, including net user
, systeminfo
, nltest
, and–perhaps the most common of all CLI commands–whoami
. As the threat actor continued their post-exploitation effort, they discovered two build servers in the environment from which they could pivot for further exploitation. The threat actor leveraged two files, winpty-agent.exe and winpty.dll to the build servers, which are legitimate files for winpty used to create an interface to run Windows commands. The threat actor used winpty-agent.exe on the build servers to remotely run commands from the exploited TeamCity server and leveraged BITSAdmin to deploy additional tools, including a malicious PowerShell script, web.ps1
, to the server. At several points before the download and execution of web.ps1
, the threat actor attempted to deploy several DLLs that were ultimately quarantined based on the Windows AV signature Win64/BianDoor.D
, providing some hypotheses of what the functionality of web.ps1
could be. Other deployed tools included additional malicious binaries, which communicated to the threat actor’s C2 server. The threat actor also used tools from FuzzySecurity’s PowerShell Suite to attempt to dump credentials.
The TA was also able to create a new account on one of the build servers and add the new account to user groups. The threat actor was detected in the environment after attempting to conduct a Security Accounts Manager (SAM) credential dumping technique, which alerted the victim’s VSOC, GuidePoint’s DFIR team, and GuidePoint’s Threat Intelligence Team (GRIT) and initiated the in-depth review of this PowerShell backdoor.
After multiple failed attempts to execute their standard GO backdoor, the threat actor pivoted to living off the land and leveraged a PowerShell implementation of their backdoor, which provides an almost identical functionality to what they would have with their GO backdoor.
The PowerShell backdoor was obfuscated but didn’t leverage any novel techniques that significantly hindered analysis. The first level of obfuscation involved an encrypted byte array that leveraged a simple decryption routine to decrypt and execute the next level of obfuscated PowerShell. This obfuscation was easily defeated by a small manipulation to the malicious script which replaced the iex command with Out-File .\LayerTwo.ps1
which gave us a separate second layer file to work with.
[byte[]] $payload = 88,83,97,68,74,8,40,40,85,8,0,22,25,10,25,45,38,57,117,30,58,16,9,15,37,2,51,3,116,35,47,9,12,49,57,62,8,25,115,42,46,60,46,62,52,17,63,62,100,24,…redacted for brevity…85,24,14,29,59,41,78,65,85,42,103,86,60,68,120,32,95,39,32,93,30,43,77,70,2,86,88,34,81,40,30,86,77,64,116,86,88,32,93,45,100,43,61,74,4,34,86,81,66,97
function x($pt, $key)
{
$ct = ""
$kp = 0
$ka = $key.ToCharArray()
$pt.ToCharArray() | foreach-object -process {
$ct += [char]([byte][char]$_ -bxor $ka[$kp])
$kp += 1
if ($kp -eq $key.Length) {$kp = 0}
}
return $ct
}
$key = <redacted>
$ps = [System.Text.Encoding]::UTF8.GetString($payload)
$cmd = x $ps $key
$cmd | iex
Figure 1: Initial PowerShell Script
At first glance, the second layer of the PowerShell script was an absolute mess, so we were less than excited to proceed.
We did a quick scan of the script in my text editor and realized it wasn’t as bad as we had originally thought, it was still ugly and going to be a bit annoying to deal with, but it was going to be manageable and quick to beautify. Specifically, the following characteristics stood out during the initial review:
cakes
and cookies
.
cookies
gets called in the last line of the script.cookies
function, there were two Write-Host
statements that helped provide some context of what we were likely analyzing:
Write-Host “Connecting to Server. . .”
Write-Host “Connected”
The last thing that we noticed as we proceeded through our initial review was that there was some very basic string substitution that was going on within the script, so we decided that our tried and true “Find and Replace” methodology was going to be the way to go. We proceeded through the script contents, performing a very similar process to what most of us would do in IDA or Ghidra with renaming variables, and a short while later, we ended up with something quite a bit more tolerable to work with.
Now that we had a clean and deobfuscated script to work with, the analysis went quite quickly. Within the first couple of minutes, we were able to confirm several of our initial hypotheses from our first review of this script, namely that this script is not a downloader. Let’s dive a bit deeper into some of the interesting components that we observed during analysis.
cakes
FunctionThe cakes
function was a great starting point since it was short and sweet (pun totally intended). The intent of this function is to resolve an IP address based on what is provided as a parameter.
As the script executes the previously mentioned ScriptBlock, contents are read from an established SSL stream and used as part of a conditional statement to confirm or resolve an IP address from either a C2-provided IP address or hostname. After the intended IP address is confirmed, it is used to establish a TCP socket for additional network communication.
cookies
FunctionAs we continued our analysis, we realized that the cookies function was responsible for a majority of the network connection management and high-level execution performed by the suspected backdoor. The first thing that stood out was the inclusion of 0x7F000001
as a default value for its first parameter. Something that doesn’t get discussed often is that IP addresses can be represented as a hexadecimal number, which in this case, represents 127.0.0.1.
Another interesting aspect of the cookies function was the use of Runspace Pools. Runspace Pools allow PowerShell to execute code efficiently and asynchronously. Past examples of PowerShell malware have used jobs for this purpose, but leveraging .NET allows for increased performance in its place.
Perhaps the most interesting component of this whole backdoor was the innovative use of the Runspace Pool in conjunction with the .NET PowerShell.Create() method to invoke a ScriptBlock with asynchronous capabilities, all while leveraging an SSL stream to pass data between the C2 server and the infected system. In past analysis of malicious PowerShell scripts, attackers have commonly leveraged Invoke-Command
or Invoke-Expression
as a means of executing malicious code, which provides a less asynchronous and potentially more detectable method of executing commands. With an encrypted SSL channel passing commands asynchronously, the attacker achieves a higher performance and potentially less detectable means of post-exploitation activity.
At this stage of analysis, we have all but confirmed that this is a backdoor that allows for a remote attacker to arbitrarily conduction operations on an infected system, much the same as BianLian’s GO trojan allows for. What puts the icing on the cake (it’s ok to be shaking your head right now) is confirming all the networking capabilities associated with this script and confirming that these are the same types of capabilities observed with other backdoors and, especially, BianLian’s GO backdoor.
One thing that BianLian is known for in regard to their GO backdoor is the use of certificates for authentication; in fact, that’s how many security researchers proactively identify their infrastructure. This type of behavior has been replicated in the PowerShell implementation of their backdoor as well. Specifically, the PowerShell implementation leverages RemoteCertificateValidationCallback
to verify the remote SSL certificate used for authentication. Similarly, the script also leverages the GetCertHashString
method to obtain a hexadecimal string that contains the hash value for the X.509 certificate. Within the execution flow of the script, we see that a hexadecimal value is passed as an argument to be used as validation for the remote C2 server.
Once the certificate has been validated, the SSL stream is established, leveraging the IP address passed as a parameter during execution.
At this stage of the execution, the now-confirmed backdoor is able to communicate with the C2 server and asynchronously execute based on the remote attacker’s post-exploitation objectives. It is important to note that due to the nature of this backdoor, we are unable to determine all post-exploitation capabilities that an attacker could leverage in conjunction with this backdoor. The main advantage of this backdoor, as we have seen with BianLian’s GO implementation, is that it provides flexibility during post-exploitation activities while masking activity within an encrypted tunnel.
As previously mentioned, the last line of the PowerShell script we analyzed showed the calling of the cookies function with some specified parameters.
When the hexadecimal value passed in Cookies_Param1
is converted into decimal notation, the value observed is 136[.]0[.]3[.]71
. Doing some quick OSINT searching shows that, according to C2IntelFeeds, this IP address is associated with a server that was running the BianLian GO backdoor as of March 6th, 2024, which corresponds to activity observed within this incident.
Separately, GuidePoint’s incident response team observed several detections for the Microsoft AV signature Win64/BianDoor.D
shortly before the first successful execution of the PowerShell backdoor.
Based on these findings of shared infrastructure and AV detections, GRIT assesses with a high confidence that the analyzed PowerShell script is a PowerShell implementation of the BianLian GO Backdoor.
As we have seen throughout 2023 and into 2024, BianLian continues to prove how they can adapt to a changing environment, especially in regards to the exploitation of emerging vulnerabilities. This behavior aligns with what GRIT has assessed and hypothesized in our 2024 ransomware report, and we expect this type of behavior to continue to grow, especially for groups that leverage a data-exfiltration-only approach to ransomware.
As we collectively move forward into 2024, our biggest recommendations focus on preparedness and, more specifically, patching your externally facing applications. Similarly, practicing your incident response plans, moving forward with threat intelligence-informed pentests, and focusing on finding ways to leverage threat intelligence to keep up with current trends in the threat landscape will aid your teams in becoming more effective and efficient at preventing these types of attacks from occurring. A well-informed preventative and preparedness mentality coupled with an extremely effective response capability will ensure that you are ready for anything that BianLian, or any other threat actor, has to throw at you.
Until next time, happy hunting!
INDICATOR | TYPE | DESCRIPTION |
web.ps1 | Filename | PowerShell Implementation of BianLian GO Backdoor |
136[.]0[.]3[.]71 | IP Address | BianLian C2 Infrastructure |
88[.]169[.]109[.]111 | IP Address | IP Address associated with malicious authentication to TeamCity |
165[.]227[.]151[.]123 | IP Address | IP Address associated with malicious authentication to TeamCity |
77[.]75[.]230[.]164 | IP Address | IP Address associated with malicious authentication to TeamCity |
164[.]92[.]243[.]252 | IP Address | IP Address associated with malicious authentication to TeamCity |
64[.]176[.]229[.]97 | IP Address | IP Address associated with malicious authentication to TeamCity |
164[.]92[.]251[.]25 | IP Address | IP Address associated with malicious authentication to TeamCity |
126[.]126[.]112[.]143 | IP Address | IP Address associated with malicious authentication to TeamCity |
38[.]207[.]148[.]147 | IP Address | IP Address associated with malicious authentication to TeamCity |
101[.]53[.]136[.]60 | IP Address | IP Address associated with malicious authentication to TeamCity |
188[.]166[.]236[.]38 | IP Address | IP Address associated with malicious authentication to TeamCity |
185[.]174[.]137[.]26 | IP Address | IP Address associated with malicious authentication to TeamCity |
977ff17cd1fbaf0753d4d5aa892af7aa | MD5 | Web.ps1 |
1af5616fa3b4d2a384000f83e450e4047f04cb57 | SHA1 | Web.ps1 |
7981cdb91b8bad8b0b894cfb71b090fc9773d830fe110bd4dd8f52549152b448 | SHA256 | Web.ps1 |
hxxp://136[.]0[.]3[.]71:8001/win64.exe | URL | BianLian C2 Infrastructure |
hxxp://136[.]0[.]3[.]71:8001/64.dll | URL | BianLian C2 Infrastructure |