Skip to content
Nouman Ahmed
All research
Threat ResearchTLP:CLEARTLP:CLEAR — Disclosure is not limited. This material may be shared publicly without restriction.

Halfmast Loader: Eleven Days Inside an Exposed Staging Directory

A world-readable build server, 1,184 logged check-ins, and a TLS certificate that has outlived three hosting providers.

Published
Reading time
9 min
Analyst
Nouman Ahmed
Region
Asia
  • Loader
  • Command & Control
  • Exposed Directory
  • Detection Engineering

An exposed directory on a staging host left a full loader toolkit readable to anyone who found it: build scripts, an operator log, and a configuration file that named the next three targets. This post walks through what was on the box, how the loader stages its payload, and what to look for on the wire.

The host stayed open for eleven days. That was long enough to watch the operators iterate — two rebuilds, a change of C2 domain, and a rushed cleanup that missed the log directory entirely.

Key findings

  • A staged loader, tracked here as Halfmast, retrieved its second stage over plain HTTP from a hard-coded IP and wrote it straight to %LOCALAPPDATA%.
  • The operator log recorded 1,184 check-ins across eleven days, from hosts in three sectors — logistics, regional government, and a single managed service provider.
  • Configuration on disk named three follow-on targets that had not yet been contacted at the time of collection.
  • The build script embedded a compilation timestamp and a username, both of which survived into the shipped binaries.
  • Infrastructure reuse links the staging host to two earlier clusters by TLS certificate serial.

The exposed directory

The host was found through routine sweeping for open directory listings on non-standard ports. It answered on 8080 with a default index — no authentication, no directory protection.

Directory listing on the staging host, showing build artefacts and an operator log
Figure 01: Directory listing on the staging host. The logs/ folder survived the operators' cleanup.

Contents changed twice during the collection window:

CapturedFilesNotable change
Day 114Initial capture. build.sh, stage2.bin, logs/
Day 617stage2.bin rebuilt; C2 domain changed
Day 96Cleanup attempt — binaries removed, logs/ left behind

The day-9 cleanup is the useful one. Removing the binaries but leaving the operator log is the sort of mistake that happens when someone is working from a checklist rather than an inventory.

Loader behaviour

Halfmast is a small C loader. It does three things: resolve its configuration, pull a second stage, and hand over execution. There is no persistence in the loader itself — that is the second stage's job.

Configuration is XOR-encoded with a single-byte key and appended to the binary after the .rdata section. Decoding it is trivial:

Python

1import sys
2
3def decode(blob: bytes, key: int = 0x5C) -> bytes:
4    return bytes(b ^ key for b in blob)
5
6with open(sys.argv[1], "rb") as fh:
7    data = fh.read()
8
9# Config is the last 512 bytes, null-padded
10marker = data.rindex(b"\x00" * 16)
11print(decode(data[marker + 16:]).decode("utf-8", "replace"))

Which yields the staging URL and the check-in interval:

JSON

1{
2  "c2": "http://192.0.2.44:8080/upd/stage2.bin",
3  "interval": 900,
4  "jitter": 0.3,
5  "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
6  "kill_date": "2026-09-30"
7}

Retrieval and staging

The second stage is fetched with a plain WinHttpSendRequest call and written to %LOCALAPPDATA%\Microsoft\Vault\vaultsvc.dat before being mapped and executed in place. No signature check, no TLS.

Network capture showing the plaintext second-stage retrieval
Figure 02: The second stage transits in the clear, which makes it trivial to catch at the perimeter.

Because the request is unencrypted and the URI path is fixed, this is straightforward to write a network rule for:

Raw

alert http $HOME_NET any -> $EXTERNAL_NET any (
  msg:"Halfmast loader second-stage retrieval";
  flow:established,to_server;
  http.method; content:"GET";
  http.uri; content:"/upd/stage2.bin"; endswith;
  http.user_agent; content:"Mozilla/5.0 (Windows NT 10.0; Win64; x64)"; depth:44;
  classtype:trojan-activity;
  sid:9000001; rev:1;
)

Host-side detection

The write path is specific enough to be worth a rule on its own. vaultsvc.dat is not a real Windows artefact, and nothing legitimate creates it under the Vault directory.

YAML

1title: Halfmast Second Stage Written to Vault Directory
2id: 6f0d5b18-9c41-4a27-b6e2-3f1c8a5d0e77
3status: experimental
4logsource:
5  category: file_event
6  product: windows
7detection:
8  selection:
9    TargetFilename|endswith: '\\Microsoft\\Vault\\vaultsvc.dat'
10  condition: selection
11falsepositives:
12  - None known
13level: high

Targeting

The operator log recorded a check-in line per beacon. Fields were consistent across all 1,184 entries: timestamp, source address, hostname, OS build, and a campaign tag.

Raw

2026-07-11T04:22:19Z 198.51.100.19 WKS-LOG-114 10.0.19045 tag=logi-q3
2026-07-11T04:37:02Z 198.51.100.86 WKS-LOG-092 10.0.19045 tag=logi-q3
2026-07-11T05:01:44Z 203.0.113.7   SRV-GOV-004 10.0.20348 tag=gov-pilot

Two campaign tags were in use — logi-q3 against logistics operators, and gov-pilot, a much smaller set, against regional government hosts. The gov-pilot set accounted for 31 of the 1,184 check-ins but ran the entire eleven days, which suggests it was the campaign that mattered.

The volume is in logistics. The persistence is in government. When those two diverge, the low-volume set is usually the objective and the high-volume set is the cover.

Infrastructure

Three hosts were involved. All shared a self-signed TLS certificate on port 443 with an identical serial, which is what ties them together.

HostRoleFirst seenLast seen
192.0.2.44Staging / payload delivery2026-07-082026-07-19
198.51.100.203C2 (initial)2026-07-082026-07-14
203.0.113.91C2 (post-rebuild)2026-07-142026-07-19

The certificate serial also appears on two hosts outside this cluster, first seen in March 2026. Those are not covered here but are included in the indicators below for anyone tracking the same certificate.

Mitigations

  • Block outbound plain HTTP to non-standard ports at the perimeter. The loader has no TLS fallback — denying 8080 egress breaks it outright.
  • Alert on file creation under %LOCALAPPDATA%\Microsoft\Vault\ for any extension other than the two Windows genuinely writes there.
  • Hunt for the fixed user-agent string. It is a stale Chrome-era UA with no browser token, so it stands out in proxy logs.
  • Pivot on the certificate serial in the indicators table — it has outlived three separate hosting providers.

MITRE ATT&CK

IDTechniqueWhere it shows up
T1105Ingress Tool TransferSecond stage pulled over HTTP
T1071.001Application Layer Protocol: Web ProtocolsFixed-path HTTP check-in
T1027Obfuscated Files or InformationSingle-byte XOR config blob
T1620Reflective Code LoadingStage 2 mapped and run in place
T1036.005Masquerading: Match Legitimate Name or Locationvaultsvc.dat under Vault\
T1573Encrypted ChannelSelf-signed TLS on the C2 tier

Indicators

Network

IndicatorTypeNote
192.0.2[.]44IPv4Staging host, port 8080
198.51.100[.]203IPv4C2, first infrastructure
203.0.113[.]91IPv4C2, post-rebuild
hxxp://192.0.2[.]44:8080/upd/stage2[.]binURLSecond-stage retrieval
updates.example[.]netDomainResolved to C2 tier

Files

SHA-256FilenameNote
3f1c8a5d0e77b6e29c414a276f0d5b18...vaultsvc.datSecond stage
a27b6e23f1c8a5d0e779c416f0d5b189...svchost32.exeLoader

TLS

SerialSubject CNNote
00:c4:1a:9f:20:b7:e3:8dlocalhostSelf-signed, shared across cluster

Conclusion

Halfmast is not sophisticated. The interesting part is the operational discipline around it, or rather the lack of it: a hard-coded staging IP, a plaintext retrieval, a config that survives a single XOR, and an operator log left on a world-readable directory.

The certificate reuse is what will outlast this campaign. Hosts get rebuilt and IPs get rotated, but the same self-signed certificate has now followed these operators across three providers and five months. That is the indicator worth keeping.


Written by Muhammad Nouman Ahmed · Threat Intelligence Analyst