Skip to content
Grit Blog

BianLian GOs for PowerShell After TeamCity Exploitation

Contributors: Justin Timothy, Threat Intelligence Consultant, Gabe Renfro, DFIR Advisory Consultant, Keven Murphy, DFIR Principal Consultant

Introduction

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:

  • BianLian’s exploitation of TeamCity vulnerabilities and post-exploitation behaviors
  • BianLian’s PowerShell implementation of their GO backdoor
  • Details focusing on attribution of the PowerShell backdoor to BianLian

Let’s get into this.

Initial Access Begins with TeamCity

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.

BianLian Pivots to PowerShell

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.

First Level Analysis

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

Second Layer Analysis

At first glance, the second layer of the PowerShell script was an absolute mess, so we were less than excited to proceed. 

Figure 2: Obfuscated Second Stage PowerShell Script

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:

  • There were two functions called cakes and cookies.
    • cookies gets called in the last line of the script.
  • Within the 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”
    • Each of these statements alluded to the connection with a specific command and control (C2) server, although during this initial stage of review, we were unsure whether this was for continuous operations (like we would expect to see in a backdoor) or something more simplistic, such as a download of a subsequent payload.
  • There is one explicitly casted script block, but it was not possible to discern its role at the initial stages of review.
  • Multiple methods were called throughout the script regarding SSL streams and TCP sockets, which gave this script more of a tunnel or backdoor feel than a simple downloader, but more analysis was needed to be sure.

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.

Figure 3: Deobfuscated PowerShell Contents

Final (Deobfuscated) Analysis

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.

The cakes Function

The 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.

Figure 4: IP address resolution and TCP Socket Creation

The cookies Function

As 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.

Figure 5: cookies function parameters

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.

Figure 6: Runspace Pool Creation

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.

Figure 7: PowerShell Object Creation and Asynchronous Execution

Network Capability Callouts

At this stage of analysis, we have all but confirmed that this is a backdoor that allows for a remote attacker to arbitrarily conduct 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.

Figure 8: SSL Certificate Validation

Once the certificate has been validated, the SSL stream is established, leveraging the IP address passed as a parameter during execution.

Figure 9: Establishing the SSL Connection

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.

Attribution to BianLian

As previously mentioned, the last line of the PowerShell script we analyzed showed the calling of the cookies function with some specified parameters. 

Figure 10: Invocation of cookies function with specific 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.

Figure 11: C2IntelFeeds association of IP Address to BianLian Infrastructure

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.

Wrap-up

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!

Indicators of Compromise

INDICATORTYPEDESCRIPTION
web.ps1FilenamePowerShell Implementation of BianLian GO Backdoor
136[.]0[.]3[.]71IP AddressBianLian C2 Infrastructure
88[.]169[.]109[.]111IP AddressIP Address associated with malicious authentication to TeamCity
165[.]227[.]151[.]123IP AddressIP Address associated with malicious authentication to TeamCity
77[.]75[.]230[.]164IP AddressIP Address associated with malicious authentication to TeamCity
164[.]92[.]243[.]252IP AddressIP Address associated with malicious authentication to TeamCity
64[.]176[.]229[.]97IP AddressIP Address associated with malicious authentication to TeamCity
164[.]92[.]251[.]25IP AddressIP Address associated with malicious authentication to TeamCity
126[.]126[.]112[.]143IP AddressIP Address associated with malicious authentication to TeamCity
38[.]207[.]148[.]147IP AddressIP Address associated with malicious authentication to TeamCity
101[.]53[.]136[.]60IP AddressIP Address associated with malicious authentication to TeamCity
188[.]166[.]236[.]38IP AddressIP Address associated with malicious authentication to TeamCity
185[.]174[.]137[.]26IP AddressIP Address associated with malicious authentication to TeamCity
977ff17cd1fbaf0753d4d5aa892af7aaMD5Web.ps1
1af5616fa3b4d2a384000f83e450e4047f04cb57SHA1Web.ps1
7981cdb91b8bad8b0b894cfb71b090fc9773d830fe110bd4dd8f52549152b448SHA256Web.ps1
hxxp://136[.]0[.]3[.]71:8001/win64.exeURLBianLian C2 Infrastructure
hxxp://136[.]0[.]3[.]71:8001/64.dllURLBianLian C2 Infrastructure