Analysis of Malicious PDF attachments delivering XWorm Payloads

Let’s dive into an interesting attack campaign which attempts to lure unsuspecting victims into downloading and running an Adobe “plugin” in order to deliver a RAT (remote access trojan) known as XWorm.

Despite its name, XWorm functions as a RAT rather than a worm. Its main purpose is to stealthily infect systems and provide the attacker with command and control functionality over the affected host. Compared to other RAT software, XWorm is relatively new and took a sharp rise in popularity at the end of 2022 when it was identified as part of a study of the EvilCoder project.

The chain of events that led up to the XWorm infection are also rather interesting. It includes several interesting forms of CMD and PowerShell obfuscation, and in-memory PowerShell process injection which leads up to the final payload being executed on the host. We’ll dive into this in greater detail further down.

Attack chain overview

As with many attacks targeting personal and business users, this campaign begins with a phishing email sent to the user. The email contains a single attachment of a PDF that lures the user into clicking and downloading a “plugin” in order to view the document.  The downloaded file is a password protected .zip file that contains a single .vhd file. Once mounted, the user is lured to execute the single batch file to install the “plugin” needed to view the PDF. At this point code execution begins with the final goal of executing the XWorm payload.

Phishing email analysis

The original phishing email follows a pretty standard scheme where it attempts to lure the user into opening a file attachment which is related to a missed or failed package delivery. The sender attempts to masquerade as “UPS Choice” with an original sender as marquezracing@centurylink[.]net. The usage of an ISP email domain is interesting and it could mean that the attackers are sending these phishing emails from compromised accounts.

The sending email appears to be a legitimate compromised account at a CenturyLink email address.

PDF file attachment analysis

The email attachment “45e53a83-2c12-40c0-843c-70b251d5df0c.pdf” contains an intentionally blurred image of a UPS shipping label with a fake error message stating that the user must install a free plugin in order to view the file’s contents.

The “Download Now!” button links to an external resource containing a zip file from hxxps://www.sendspace[.]com/pro/dl/kw6pge which downloads the file “pdf-plugin_installer.zip”.

ZIP and VHD payload analysis

The zip file can be extracted using the password “123” from the body of the PDF attachment. The zip file contains a single virtual hard disk file (VHD). While ISO files are much more common with other malware types, such as Qakbot, .vhd files are still in use today. Both formats can be used in an attempt to circumvent MOTW restrictions built into Windows.

When executed by the user, the virtual disk will mount as another hard disk, and its contents will be presented to the user. This is another method to circumvent antivirus detections. Oftentimes, AV will not be configured to scan mounted devices such as F:\ for example.

Contents of pdf-plugin_installer.zip:

Contents of pdf-plugin_installer.vhd:

The figure above gives us the contents of the newly mounted hard disk “pdf-plugin_installer.vhd”. Typically the “$RECYCLE.BIN” and “System Volume Information” will be hidden from the user. In most normal cases, the user will be presented with the single file “pdf_reader-plugin.bat” When executed by the user, our code execution begins.

Code Execution: pdf_reader-plugin.bat

The contents of the “pdf_reader-plugin.bat” file are heavily obfuscated using some known methods of batch obfuscation, mostly variable substitution in this case.

Code Execution: PowerShell

After deobfuscating the batch script we’re presented with a PowerShell script which also contains plenty of obfuscation, again using mostly variable substitution.

Deobfuscating the PowerShell script returns some interesting results. Essentially, the purpose of this script is to:

  1. Take the first line of the original batch script (found in Figure 4)
  2. Split it into two strings separated by “:”
  3. Decrypt the byte values using the base64 encoded key and IV values
  4. Reflectively load the decoded binary data into the spawned PowerShell process using the Assembly.Load Method.

The binary data gets reflectively loaded using the $LOueb and $cZGKe variables. We’ll use those two variables to reference the binary files from here on since they have no names.

For the purpose of binary analysis, we can extract the byte code by modifying the deobfuscated script. Instead of reflectively loading the decrypted string, we can simply output it to the terminal and save it as raw binary data for analysis.

XWorm – Binary file analysis

We mentioned earlier that there were two binary payloads generated by the previous PowerShell script which get reflectively loaded into the main PowerShell process. This is important and something we’ve been seeing with modern malware. Reflectively loading a binary into a hollowed or injected process will keep the payloads from being written to disk, thus making analysis difficult from an AV or EDR platform.

The first binary ($cZGKe) is loaded from the second ($LOueb). The purpose of the second is to act purely as a loader which reinjects the process with the main CAMPAIGN#NAME payload. Both binary files are heavily obfuscated.

Both files use almost identical obfuscation techniques including deobfuscation functions which we’ll get into in the next section.

$LOueb payload analysis

This payload coded in .NET was clearly obfuscated using a packer or some other obfuscation tool.  Almost all contained strings were completely unreadable. Once we were able to deobfuscate the code modified by the packer, there was once again another layer of obfuscation which leveraged a separate function to manipulate bite values of known strings.

The figure below shows the obfuscation used in the program’s main function:

Now with the rest of the application deobfuscated, we’re able to analyze some of its other functions.

The deobfuscation function “<Module>.smethod_0()” takes an obfuscated string and a set of integer values as input, subtracts the integer “int_1” from the character code of each character in the input string “string_0”, and then builds a new string from the resulting characters. Now, we’re able to leverage this for all obfuscated strings scattered throughout the application code.

Within the LOueb.dll binary file, included as a .NET resource is another binary file containing the actual payload of the XWorm RAT, simply referred to as “P”. Once extracted and analyzed, this is compiled with the file name XClient.exe, which is the default name given to client payloads generated by the server application console.

XClient.exe payload analysis

The XClient.exe payload is the main RAT software which would connect back to the attacker’s hosted C2 software. This particular binary is overall quite small, standing at a mere 64KB, was built on 4/27/2023. While the client version appears to be v1.0.0.0, we can identify that the XWorm server was built on version 3.1, which we’ll dive into later on.

Interestingly enough, it doesn’t appear that a packer was used on this payload to obfuscate identifiable strings. Antivirus products would most likely flag this payload as malicious, however since it’s being reflectively loaded into memory as a resource from another payload, there’s a good chance it won’t be detected regardless.

Xworm C2 capabilities

Upon execution, XWorm performs a sleep before performing some system checks. These checks include counter-analysis functions which detect whether or not a debugger or if the victim machine is running inside a VM. The attacker can issue commands to the client to the server. After analyzing the binary file’s code we were able to identify the following functionality:

recRestart application
CLOSEClose application
UninstallPurges all RAT files, registry keys, scheduled tasks then exits
updateRuns the uninstall function, decompresses file from byte stream, opens a new memory stream
DWWrites a .ps1 file from the attacker’s server and executes it using the command: powershell.exe -ExecutionPolicy Bypass -File “filename.ps1”
FMTakes an assembly from a provided byte array, then creates an instance of the assembly’s entry point type and invoke it.
LNDownloads a file and executes it using Process.Start(filename).
UrlopenPerforms an HTTP GET request to a provided URL for the default browser
UrlhideSame as Urlopen, but build the web connection within the binary itself, hidden from the user
PCShutdownShuts down the victim machine using the following command:
shutdown.exe /f /s /t 0
PCRestartRestarts the victim machine using the following command: shutdown.exe /f /r /t 0
PCLogoffLogs off the user using the following command: shutdown.exe -L
StartDDosBegins DDos to the target
StopDDosStops the DDos attack
StartReportThis attempts to abort the existing thread and then create a new thread for the instance with passed in parameters
StopReportStops the newly created thread
XchatOpen a socket and send specified data to the attacker’s machine
ngrokOpen a socket and use ngrok functionality
pluginUnknown: Appears to check for the existence of “plugin” related data
savePluginUnknown: processing of additional plugin-related data
OfflineGetPerforms connectivity check
CapCaptures the current user’s desktop
MessageBoxSends a message to the logged in user using MessageBox.Show();

A unique identifier is used for each victim computer. This is generated using the following system information:

  • Environment.ProcessorCount
  • Environment.UserName
  • Environment.MachineName
  • Environment.OSVersion,

XWorm – Keylogging

Once the software has passed the sleep, and anti-debugging and sandbox detection tests, the malware will immediately begin monitoring the victim computer’s keystrokes. The function below gives us an idea of what this might look like from the attacker’s point of view.

As you can see in the figure below, non-printable keys are also recorded such as [SHIFT], [BACKSPACE], [CTRL] and many more.

Xworm Persistence

The XWorm client is able to establish persistence through three main components. First it will use a well known registry key for running an application on startup. As seen in the figure below, this is established in:


The Xworm client also can persist using Windows scheduled tasks which calls the process “schtasks.exe”. A new task is created which runs every minute as either an administrator or standard user depending on the integrity level of the current running process.

schtasks.exe /create /f /RL HIGHEST /sc minute /mo 1 /tn “filename” /tr “C:\full\path\to\exe.exe”

schtasks.exe” /create /f /sc minute /mo 1 /tn “XClient” /tr “C:\Users\username\AppData\Roaming\XClient

Lastly, the malware will attempt to create a shortcut to the malware inside the user’s startup directory. It does this by leveraging the Startup environmental variable and linking to the filename and path variable.

C:\Users\username\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\XClient.exe.lnk

Xworm other capabilities

In addition to the aforementioned commands, the malware contains the following functionality. Like with many RATs the client executable is generated from the server application. Many features can be selected by the attacker generating the payloads so in some cases some features may be present where others might not be.

  • AV enumeration
  • Built-in string obfuscation
  • Sandbox and debugger detection
  • Self-propagation through infected USB devices

For reference (figure 9), some of these capabilities are user-selectable when building the XWorm client from the server application.

C2 and infrastructure

The Xworm client can be configured to connect to a remote server directly, or connect to a pastebin URL containing an IP and port combination. In this case, the attackers opted for the latter. We observed the binary making direct connections:

  • hxxps://pastebin[.]com/raw/Dh8E7H3R
  • 45.12.253[.]49:8989

The IP in question appears to be registered to the Netherlands under Des Capital B.V. ISP. Currently it is only blacklisted on 2/106 blocklists according to IPVoid, and has zero detections in VirusTotal.

Analyzed file hashes

File NameSHA256 (IoC)


Leave a Reply

Your email address will not be published. Required fields are marked *