Summary
- SharpRhino is based on open-source project ThunderShell
- Delivered to victims as an NSIS installer that drops PowerShell scripts
- Powershell scripts contain encoded .NET assemblies
- NET payload is used to communicate with the C2 server
- Can remotely execute commands
- Network traffic is encrypted with RC4 and encoded in Base64 format
Introduction
Hunters International, a well-known threat group known for their ransomware-as-a-service operations, has started using new RAT malware. The first incident featuring this software was spotted at the start of August 2024 and was named SharpRhino due to its C# language. The trojan is delivered to victims as legitimate software and grants remote access to the victim's machine. Using this software, attackers can execute different commands and propagate other malware.
Technical details
Overview
The analyzed sample is delivered to victims as an installer that was built with the Nullsoft Scriptable Install System. This file has ‘Angryip.org’ in the description and a valid digital certificate, but the company name is fake and does not exist.
This installer contains an additional installer, password-protected archive and additional files that will be used during malware execution.
Installation
When executed, the sample drops all embedded files to the ‘C:\ProgramData\Microsoft\WindowsUpdate24’ folder and executes an ‘ipscan-3.9.1-setup.exe’ file, which is an installer of legitimate software: Angry IP Scanner.
While the user is distracted by this installer, the malware extracts files from the password-protected archive UpdateFull.zip. Then, to unpack the archive, it uses an embedded 7za.exe program. In the command line we can see the password for the archive:
C:\ProgramData\Microsoft\WindowsUpdate24\7za.exe x C:\ProgramData\Microsoft\WindowsUpdate24\UpdateFull.7z -pTG98HJerxsdqWE45 -oC:\ProgramData\Microsoft\WindowsUpdate24
The contents of the archive are as follows:
The sample creates a new folder — ‘C:\ProgramData\Microsoft\LogUpdateWindows’ — after extraction, and copies files extracted from the archive to the new folder. Using two different installation folders can help attackers to gain persistence and stay on the system in case one of the folders is removed, as files in those folders are similar in the execution process. Next, it adds a new registry key to the ‘HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run’ path that points to the ‘Microsoft.AnyKey.lnk’ file. This file is a shortcut and contains the next target:
C:\ProgramData\Microsoft\LogUpdateWindows\Microsoft.AnyKey.exe abnormal c:\programdata\%username%0 cmd /c C:\ProgramData\Microsoft\LogUpdateWindows\LogUpdate.bat
The executable, ‘Microsoft.AnyKey.exe’, which also was dropped from the archive, is a legitimate program that is a part of Node.js tools for Visual Studio and is named ‘Microsoft.NodejsTools.PressAnyKey.exe’.
Execution
The ‘LogUpdate.bat’ and ‘WindowsUpdate.bat’ files have the same functionality, but they load different files.
‘Wiaphoh7um.t’ and ‘kautix2aeX.t’ files both contain obfuscated data. The raw data and the key are different for those files, but the result data will be the same. After the decoding process, the sample defines this data as .NET assembly and calls one method with some parameters.
After dumping all data from the script, we can observe the next variables:
$var1, $var2, $var3 variables determine referenced assemblies and when concatenated from the next string:
System.Drawing.dllSystem.Web.Extensions.dllSystem.Windows.Forms.dll
$var4 is different for each file and contains a C2 server address. Below is a table representing arguments that are used in .NET assembly call for each file:
‘$fjwZrHB1k2RF’ represents .NET Assembly that is loaded to the memory. After dumping data, we can observe C# code. The PowerShell script calls a function from the ‘Bzxmlpi’ namespace and ‘OyrWkb’ class. At the start of this class, we can observe some additional imports load and unreadable variable names.
In fact, this file is a modified version of the open-source project ‘ThunderShell’. Several changes were made to the source project:
- Removed keylogger, screenshot and .NET Assembly loading functions, as well as the server’s commands that represented those functions.
- All classes, functions and variables’ names were renamed.
- Added default values that will be used if the payload is executed without arguments.
This function first generates a 16-byte random string. When initializing the Random class, the sample uses the current date, time and process ID as a seed. Next, it gets some environment variables, such as COMPUTERNAME, USERDOMAIN and USERNAME. All those data will be formatted:
As a result, the next string is generated:
Next, the sample passes this string to a function that will send it to the server. Here, it encrypts data using an RC4 cipher with a key that was passed as the second argument.
After the encryption process, it adds some data to the request and also encodes the encrypted string in Base64 format. All this data is then sent to the server.
At this first connection, the response from the server is ignored. When the sample enters a loop, it connects to the server again, but both arguments are ‘null’. Next, the response is saved and compared with saved values. If the ‘delay’ command is received, the sample takes an additional argument and changes the value that will be passed to the sleep function. If the ‘exit’ command was obtained, it would break the loop and terminate execution. If it obtained any data other than ‘delay’ or ‘exit’, it will create a new thread with a function, which will take the obtained data as an argument. All those actions will be repeated with a 95-second delay between each loop iteration.
The response that comes from the server is passed to the deserialization function in ‘zWxFlnVASjHYb’ class, which grabs and stores the next data: ‘UUID’, ‘ID’ and ‘Data’.
C2 server
While the link that was presented in the sample had already gone offline, we can use the server from the source project to see how communication works. First, we need to change the server configuration. It contains a number of fields, including the server IP address, encryption key, GUI settings and HTTP and HTTPS settings. Second, we need to change ‘callback-url’, ‘gui-host’ and ‘encryption-key’ parameters. We will take the encryption key parameters from a SharpRhino sample.
The server is a Python application and requires a running Redis server. After starting, it outputs some information about the server.
This includes a Web GUI address. When opened, the user must first be logged in. While it doesn’t matter what username they input, the password must be used from the configuration file. When logged in, the dashboard section is displayed. It contains information about sessions and logs.
The payload can be built in the Web GUI. The IP address of the server must be provided, as well as the payload type.
After choosing a session, the attacker can interact with it. Entering ‘help’ shows all supported commands that can be used within the session.
C2 communications
Those commands have predefined strings that will be appended to data that the attacker enters as arguments. For example, using ‘shell [command]’ will append ‘cmd.exe /c’ to the start of the string that will be sent. Another example is a ‘ps’ command, which will send the PowerShell script to the client:
The command comes to the client encrypted with RC4 and encoded in Base64 format. It contains ID and UUID parameters, where ID is the client ID and UUID is a command ID.
All this data is passed to the new thread. The function in this thread uses PowerShell modules to execute given commands.
Using the pipeline, the sample gets the output of the executed command. This data will then be encrypted and sent back to the server.
Conclusion
ThunderSharp, an old open-source project that was last updated almost four years ago, was used by Hunters International to deliver malware to victims. It arrives as an Angry IP Scanner utility installer, which drops and executes malicious PowerShell scripts. Using PowerShell capabilities, those scripts execute encoded .NET assemblies, so there is no need to bring any additional compiled executable — the malicious code is invoked and executed in the memory.
While the original code was modified, it retained its main functionality: remotely executing commands on targeted systems. This is the danger of such open-source projects. They are typically developed for education or pen-testing purposes but used for real attacks.