Unknown Malware Using Azure Functions as C2
On August 28, 2025, an ISO named Servicenow-BNM-Verify.iso
was uploaded to VirusTotal from Malaysia with very low detections:
The ISO image contains 4 files, two of them hidden.
servicenow-bnm-verify.lnk
, a shortcut file that simply executes PanGpHip.exePanGpHip.exe
, a legitimate Palo Alto Networks executablelibeay32.dll
, a legitimate OpenSSL library (hidden)libwaapi.dll
, a malicious library (hidden)
servicenow-bnm-verify.lnk
only executes the legitimate Palo Alto executable. The metadata of the LNK file reveals the machine used to create the link (desktop-rbg1pik
), the user (john.GIB
), and the creation date (08/25/2025 (04:39:00.540) [UTC]
), 3 days before the LNK ISO was uploaded to VirusTotal. The target path of the LNK points to the executable in the excluded
folder. This is likely a location in the threat actor’s development environment. Even though that path does not exist on the victim’s device, the LNK falls back to its same directory, where PanGpHip.exe
also resides.
LNK metadata:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[Link Info]
Location flags: 0x00000001 (VolumeIDAndLocalBasePath)
Drive type: 3 (DRIVE_FIXED)
Drive serial number: fa5a-f20e
Volume label (ASCII):
Local path (ASCII): C:\Users\john.GIB\Desktop\excluded\paloalto\PanGpHip.exe
[Distributed Link Tracker Properties]
Version: 0
NetBIOS name: desktop-rbg1pik
Droid volume identifier: 711034a2-0123-44ae-ae6c-462a77afcd54
Droid file identifier: 6b9dc172-816d-11f0-a497-7c214a295e9f
Birth droid volume identifier: 711034a2-0123-44ae-ae6c-462a77afcd54
Birth droid file identifier: 6b9dc172-816d-11f0-a497-7c214a295e9f
MAC address: 7c:21:4a:29:5e:9f
UUID timestamp: 08/25/2025 (04:39:00.540) [UTC]
UUID sequence number: 9367
Payload Injection
The presence of hidden DLLs and a legitimate executable is typically indicative of DLL side-loading. The libwaapi.dll
library contains malicious logic that is executed when it is dynamically loaded by the legitimate PanGpHip.exe
executable using LoadLibraryW
.
This DLL, although malicious, has almost no detection in VirusTotal:
The only exported function in libwaapi.dll
that implements code is wa_api_setup
. The rest of the exports do not have any code.
The wa_api_setup
export:
- Uses an array of function pointers to call
GetConsoleWindow
,SetForegroundWindow
,GetForegroundWindow
, andShowWindow
with its second argument set to 0, which isSW_HIDE
according to the API documentation. This is a common technique to hide the console from the victim - It then creates/checks mutex
47c32025
via theCreateMutexExW
API - If the mutex does not exist, it executes a payload injection function that I renamed to
fn_payload_injection
The fn_payload_injection
function implements logic to inject payload in memory. This function starts by computing the SHA-256 hash of string rdfY*&689uuaijs
. This hash (B639D4DC948B66A2AAB5B59D0B4114B4B11229E9DED0F415B594B8ADE11F8180
) is subsequently used as the RC4 key for payload decryption.
If the SHA2 computation is successful, it proceeds to deobfuscate the string chakra.dll
with a simple algorithm that resembles a Caesar cipher.
The legitimate chakra.dll
is loaded from the C:\Windows\System32\
folder and a loop is implemented to find the first readable + executable section in the DLL.
When that section is found, its memory permissions are set to writable (PAGE_READWRITE
) via the ZwProtectVirtualMemory
API and the content is zeroed out. The injector then proceeds to base64-decode a payload stored in the .data
section of the DLL to the target section in the loaded chakra.dll
. After decoding the payload, it is RC4 decrypted with the previously computed key (B639D4DC948B66A2AAB5B59D0B4114B4B11229E9DED0F415B594B8ADE11F8180
).
Once the deobfuscated/decrypted payload is written to the DLL, an integrity check is implemented by comparing the SHA2 hash of the injected payload to a hard-coded SHA2 value (550c27fd8dc810df2056f1ec4a749a94ab4befc8843ba913c5f1197ef381a0a5
). If the integrity check passes, memory permission is restored to PAGE_EXECUTE_READ
and it proceeds to execute the injected payload.
Injected Payload
The injected payload is an obfuscated shellcode that loads an embedded DLL. We can quickly find the embedded payload by loading the shellcode in a hex editor. However, we can see that the embedded payload needs to be processed before execution. It is not a clean PE.
Reviewing the shellcode, we can see that the buffer with the embedded portable executable is processed by the RtlDecompressBuffer
API using 0x102
as the first argument.
Looking at the prototype of RtlDecompressBuffer
, we can see that the first argument is the compression format:
1
2
3
4
5
6
7
8
NT_RTL_COMPRESS_API NTSTATUS RtlDecompressBuffer(
[in] USHORT CompressionFormat,
[out] PUCHAR UncompressedBuffer,
[in] ULONG UncompressedBufferSize,
[in] PUCHAR CompressedBuffer,
[in] ULONG CompressedBufferSize,
[out] PULONG FinalUncompressedSize
);
In order to understand what the 0x102
means, we can check the ReactOS documentation. Here we can see that macro definitions indicate that 0x0100
is COMPRESSION_ENGINE_MAXIMUM
and 0x0002
is COMPRESSION_FORMAT_LZNT1
. So, essentially, the embedded payload has maximum compression for LZNT1
.
We can then decompress the final payload embedded within the shellcode. The decompressed payload is an obfuscated DLL (SHA2: c0fc5ec77d0aa03516048349dddb3aa74f92cfe20d4bca46205f40ab0e728645) which I could not correlate to any payload I’ve seen before - possibly due to the obfuscation. I am still working on deobfuscating this payload, but here are some initial observations. The DLL timestamp is May 5, 1984, which was likely modified. The malicious functionality is implemented in the DllUnload
exported function.
A quick string review via emulation suggests that the DLL implements module unhooking to avoid detection.
This final payload implements a loop to the C2, sending a POST request with victim profile data to logsapi.azurewebsites[.]net/api/logs
. The data is sent encoded/encrypted in a POST request.
The Azure websites C2 hosts Azure Functions. Azure Functions is a serverless solution that operates with event-driven triggers and bindings.
The encrypted data sent to the C2 can be captured before it is encrypted. We can see that it is an XML containing the computer name, user name, the OS uptime, protocol, process running the malware, parent process, and other values that I am still reviewing.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="utf-8"?>
<root>
<c331219780 type="int">64</c331219780> // likely architecture
<c693503181 type="int">3</c693503181>
<c278266627 type="int">3916</c278266627>
<c335283027 type="int">3380</c335283027>
<c375980915 type="int">60</c375980915>
<c446104534 type="int">30</c446104534>
<c581502030 type="int">1759243228</c581502030>
<c660735130 type="int">805074430</c660735130>
<c1666058129 type="bool">false</c1666058129>
<c269419238 type="str">%random string%</c269419238>
<c327025478 type="str">v2.17.3</c327025478> //unknown version
<c589169778 type="str">HTTP_HTTPS</c589169778>
<c441910204 type="str">SUE48</c441910204>
<c671024323 type="str"></c671024323>
<c228262600 type="str">Windows 10.0 (OS Build 1337)</c228262600> // OS build (1337 is an interesting value...)
<c610731141 type="str">%COMPUTERNAME%</c610731141>
<c467272698 type="str">0d 6h 43m</c467272698> //uptime
<c613221510 type="str">%COMPUTERNAME%\%USER%</c613221510> // computer name and user name
<c869336422 type="str">%PROCESS%</c869336422> //process the malware is executing from
<c968295862 type="str">%PARENTPROCESS%</c968295862> //parent process
</root>
I am still deobfuscating this final payload to understand all the details, and I may post a follow up blog post once I am done. This sample seems to be quite unique, but @L3hu3s0 found another DLL (SHA2: 28e85fd3546c8ad6fb2aef37b4372cc4775ea8435687b4e6879e96da5009d60a
) with the same imphash (B74596632C4C9B3A853E51964E96FC32
) uploaded from Singapore on September 5, 2025. I reviewed that DLL and it is pretty much the same thing, with some minor differences.
IOCs
- Servicenow-BNM-Verify.iso: 0ba328aeb0867def650694c5a43fdd47d719c6b3c55a845903646ccdbf3ec239
- servicenow-bnm-verify.lnk: 9e312214b44230c1cb5b6ec591245fd433c7030cb269a9b31f0ff4de621ff517
- libeay32.dll: 1fa3e14681bf7f695a424c64927acfc26053ebaa54c4a2a6e30fe1e24b4c20a8
- libwaapi.dll: b03a2c0d282cbbddfcf6e7dda0b4b55494f4a5c0b17c30cd586f5480efca2c17
- PanGpHip.exe: b778d76671b95df29e15a0af4d604917bfba085f7b04e0ce5d6d0615017e79db
- Decrypted shellcode: 550c27fd8dc810df2056f1ec4a749a94ab4befc8843ba913c5f1197ef381a0a5
- Decompressed DLL: c0fc5ec77d0aa03516048349dddb3aa74f92cfe20d4bca46205f40ab0e728645
- Related DLL: 28e85fd3546c8ad6fb2aef37b4372cc4775ea8435687b4e6879e96da5009d60a
- C2: logsapi.azurewebsites[.]net