to je to
Categories
General

GlassWorm – Malware Analysis

It started with code that wasn’t there.

While reviewing a set of Git repositories during a penetration test, we noticed something unusual: files that appeared clean in the editor but behaved differently at runtime. The only visible clue was a mismatch in character counts.

That discrepancy led to the discovery of a stealthy malware campaign we now track as GlassWorm. A multi-stage Node.js implant that hides in plain sight using invisible Unicode characters and retrieves its command-and-control infrastructure via the Solana blockchain and BitTorrent DHT.

What initially looked like a minor anomaly turned out to be a widespread supply chain attack affecting over 100 public repositories.

At the time of publication, we detected the code in approximately ~100 public repositories on GitHub.

“Invisible” Code

The malicious code hides itself using invisible Unicode characters from the ranges U+E0000–U+E007F and U+FE00–U+FE0F. These characters are not rendered by most text editors, making them difficult to spot during manual review. In Visual Studio Code, the presence of the code is only visible through the character selection count — the actual content remains invisible.

Malicious code injected into a git repository
Invisible Unicode characters

Once loaded, the program decodes the hidden characters into valid JavaScript and executes it using the eval() function. The result is a generator that first waits 500 ms, then decrypts and executes the next stage using AES-256-CBC. The key and initialization vector are hardcoded directly in the code.

Dynamic C2 Resolution

Rather than hardcoding a C2 server address, GlassWorm retrieves it dynamically — from the metadata of the latest transaction on the Solana wallet BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC. The value of the link field in the metadata is a Base64-encoded URL that, once decoded, points to http://217.69.11.99/axtyituCswaN5AamyO692g==.

The server returns the next-stage payload tailored to the victim’s operating system (Windows, macOS, or Linux). Before execution, it checks whether at least 2 days have passed since the initial infection, which slows down sandbox analysis. The code is additionally protected: Base64-encoded and AES-256-CBC encrypted, with the key and IV passed in the HTTP response headers (ivbase64 / secretkey). It appears to execute in isolation using Node.js’s vm module. Further analysis reveals, however, that references to console and process are passed via context — system execution remains.

Execution automatically terminates if the program detects it is running on a system with Russian language settings or timezone.

Data Theft

Windows

The Windows payload is extensive and largely composed of legitimate libraries. The malicious portion performs the following activities:

  • Downloading and decrypting additional modules from server 217.69.11.99
  • Theft of npm and git credentials
  • Data theft from crypto wallets (desktop apps and browser extensions)
  • Theft of saved passwords from password managers
  • Downloading and executing a .NET binary, if Ledger Live is installed on the system

The program downloads a ZIP archive from the server 217.69.11.99 using the following path: /get_arhive_npm/1B89Udneo8JJwdQlbr1w6w==. The archive is saved to %TMP%\kkXqPAFp and extracted to %TMP%\rKeKMWikl. Two files are then decrypted using AES-128-CBC:

  • %TMP%\kkXqPAFp\w.node -> decrypted and written to %TMP%\cTdTMfItnz\tlESkme
  • %TMP%\rKeKMWikl\f_ex86.node ->hash is verified using SHA-256, decrypted and written to %TMP%\cTdTMfItnz\WujOBGtse

Both decryption operations use the following parameters (Base64-decoded before use):

Key: caTY0D6roK1LHa02cA80jA==
IV:     /sXfxpU5Dr0kuXoihE6JFQ==

Stolen data is exfiltrated to http://208.85.20.124/wall via POST.

.NET Binary (ggsuuck.exe)

If a Ledger Live installation is detected, a .NET binary is downloaded from http://217.69.11.99/led-win32 and saved as %TMP%\ggsuuck.exe. The file is added to the startup programs via a PowerShell command writing to the registry key HKCU\Software\Microsoft\Windows\CurrentVersion\Run with the value UpdateLedger.

The application pretends to be part of Ledger Live software suite and prompts the user to enter their 24-word recovery phrase, which it validates against an internal dictionary (Assaac.WordBookHealth.thisRectangleWord). The entered values are transmitted to 45.150.34.158:8080 over a TCP connection.

Validation and transmission of the 24-word phrase

Before displaying the window, the program checks the victim’s location via https://ipapi.co/xml. Execution is aborted for systems located in: Armenia, Russia, Kyrgyzstan, Moldova, Tajikistan, Uzbekistan, or Kazakhstan.

Victim location retrieval and comparison

macOS

The macOS variant is structurally similar to the Windows version. The malicious code begins at line 1380, preceded by the legitimate yauzl library for ZIP archive handling.

The FileGrabber.run() function collects:

  • Keychain file
  • Cookies and passwords from Safari, Firefox, and Chrome
  • User notes (Notes app)
  • SSH and AWS configuration files (.ssh, .aws)
  • Documents from the Documents folder
  • Data from browser extensions (MetaMask, Phantom, Exodus, Ledger …)
    FileGrabber.run() function

    Collected files are copied to /tmp/ijewf/. After FileGrabber.run() completes, an AppleScript script is launched via an osascript subprocess. The script attempts to extract the Chrome password executing the command security find-generic-password -ga “Chrome”. Passwords are saved to /tmp/ijewf/pwd. If extraction fails, a fake system dialog is displayed prompting the user for manual authentication.

    Collected data is archived and exfiltrated to http://208.76.223.59/p2p via POST, using non-standard HTTP headers:

    • uuid: 57f432c1-c5b7-4b51-8667-044847c63470
    • buildid: 2026-03-06T07:35:05.258Z
    • uuid_machine: dynamically obtained via the ioreg command
    Data exfiltration (POST with non-standard HTTP headers)

    For persistence, the script installs the Node.js v23.5.0 runtime to ~/.config/system/.data/.nodejs/ and creates a LaunchAgent at ~/Library/LaunchAgents/com.user.nodestart.plist, which executes Base64-encoded JavaScript on system startup.

    Persistence — LaunchAgent and Node.js installation

    Finally, via the functions ZOZgdRcMWJ(), GgFYYlKGIY(), and envExfiltration(), git credentials, npm keys, SSH keys, and files from .vscode directories are stolen. The collected data is archived to /tmp/h.zip and sent to http://208.85.20.124/wall.

    Possible indicator of Russian origin: a comment in the code responsible for stealing GitHub SSH keys is written in Russian.

    ZOMBI — Persistent C2 Component

    ZOMBI is a JavaScript component that operates independently of any fixed C2 address. It implements two mechanisms for dynamically resolving the IP address of the attacker’s server.

    C2 Address Resolution

    The primary mechanism is the BitTorrent DHT protocol. ZOMBI connects to three public servers and queries for a value signed with a hardcoded ed25519 public key. The signature is verified using the crypto_sign_verify_detached function, ensuring the device only connects to the attacker’s server. The IP address is refreshed every 50 seconds.

    • libtorrent.org:25401
    • bittorrent.com:6881
    • utorrent.com:6881
    DHT client initialization with public key

    The secondary mechanism falls back to the latest transaction on Solana wallet BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC. The retrieved value is a DHT node, which is added to the client for a new query. A following list of public Solana RPC endpoints is used to access the network:

    • https://go.getblock.us/86aac42ad4484f3c813079afc201451c
    • https://solana-mainnet.gateway.tatum.io/
    • https://solana-rpc.publicnode.com
    • https://api.blockeden.xyz/solana/KeCh6p22EX5AeRHxMSmc
    • https://sol-protect.rpc.blxrbdn.com/
    • https://solana.drpc.org/
    • https://solana.leorpc.com/?api_key=FREE
    • https://solana.api.onfinality.io/public
    • https://solana.api.pocket.network/
    • https://api.mainnet-beta.solana.com
    • https://public.rpc.solanavibestation.com/
    Interval-based C2 IP resolution

    Capabilities

    Once the C2 address is resolved, ZOMBI connects to a WebSocket on port 4789. The program includes the value _partner: “mulKRsVtolooY8S” in outgoing requests. Attackers can execute the following commands:

    • Execution of arbitrary JavaScript code via eval().
    • Uploading binary files to the infected device.
    • SOCKS Proxy Server functionality—the infected device effectively becomes part of the attack infrastructre.
    WebSocket message handlers

    Indicators of Compromise (IOCs)

    Network IOCs

    Type Value
    IP 217.69.11.99
    URL http://217.69.11.99/axtyituCswaN5AamyO692g==
    URL http://217.69.11.99/get_arhive_npm/1B89Udneo8JJwdQlbr1w6w== — ZIP archive (Win)
    URL http://217.69.11.99/led-win32
    IP 208.85.20.124 — exfiltration /wall
    IP 208.76.223.59 — exfiltration /p2p
    IP:port 45.150.34.158:8080
    WebSocket [C2]:4789 — ZOMBI C2 channel

    Blockchain / DHT

    Type Value
    Solana wallet BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC
    DHT dht.libtorrent.org:25401
    DHT router.bittorrent.com:6881
    DHT router.utorrent.com:6881

    Files and Paths — Windows

    Type Value
    Directory %TMP%\kkXqPAFp
    Directory %TMP%\rKeKMWikl
    File %TMP%\kkXqPAFp\w.node
    File %TMP%\rKeKMWikl\f_ex86.node
    File %TMP%\cTdTMfItnz\tlESkme
    File %TMP%\cTdTMfItnz\WujOBGtse
    File %TMP%\ggsuuck.exe
    File %HOME%\init.json
    Reg. key HKCU\Software\Microsoft\Windows\CurrentVersion\Run → UpdateLedger

     Files and Paths — macOS

    Type Value
    Directory /tmp/ijewf/
    File /tmp/ijewf/pwd
    File /tmp/h.zip
    Directory ~/.config/system/.data/.nodejs/
    File ~/Library/LaunchAgents/com.user.nodestart.plist
    File ~/init.json

    Cryptographic Artifacts

    Type Value
    AES-256-CBC key zetqHyfDfod88zloncfnOaS9gGs90ONX
    AES-256-CBC IV a041fdaa0521fb5c3e26b217aaf24115 (hex)
    AES-128-CBC key caTY0D6roK1LHa02cA80jA==
    AES-128-CBC IV /sXfxpU5Dr0kuXoihE6JFQ==
    SHA-256 (f_ex86.node) a89dd9e5c813bf66d0738a70a616d97f6438917c423de347560e5ed2db3df5ff

    Other Artifacts

    Type Value
    HTTP header uuid: 57f432c1-c5b7-4b51-8667-044847c63470
    HTTP header buildid: 2026-03-06T07:35:05.258Z
    HTTP header uuid_machine: dynamic (ioreg)
    WebSocket token _partner: mulKRsVtolooY8S

    Conclusion

    GlassWorm is a multi-stage campaign that exploits developer trust in open-source ecosystems. What makes it particularly concerning is the combination of advanced techniques — steganographic hiding using invisible Unicode characters, C2 resolution via blockchain and DHT, and a modular architecture that allows attackers to remotely upgrade capabilities. Its presence across ~100 public repositories points to a systematic campaign rather than an isolated incident.

    We recommend organizations audit their npm dependencies and git history for invisible Unicode characters, monitor network traffic to the identified IP addresses, and check for the presence of an init.json file in the home directory on developer machines.

Categories
General

Team Viris Competes at Insomni’hack 2025 CTF in Lausanne, Switzerland

We’re excited to announce that our team recently took part in the Capture the Flag (CTF) competition at Insomni’hack, one of Europe’s most respected cybersecurity events, held in Lausanne, Switzerland.

Categories
General

Hackron, Tenerife: A Blast with Our CTF Challenge!

At the Hackron Conference in sunny Tenerife, we did something pretty cool that got everyone turning their head. Together with local team we set up a Capture The Flag (CTF) challenge, but with a twist that made it super memorable for everyone involved. We brought city model to the life which you could hack. Rotating lights, right music and military environment brought proper CTF atmosphere into Auditorio de Tenerife.

Categories
General

My first CVE

In this blog post, I will take you through my personal journey of identifying a vulnerability, navigating the ethical considerations of reporting it, and the intricate process leading to my work being recognized with a CVE identifier. Join me as I share insights from this experience, aiming to illuminate the path for those interested in the field of information security, and to highlight the pivotal role of CVEs in our digital era.

Categories
General

CODE CTF Competition

In November 2023, we participated in a CTF competition in Munich, organized by the CODE Research Institute (https://www.unibw.de/code) in collaboration with the Localos CTF team.

Categories
General

Insecure MQTT Protocol Configurations

Open-source projects play a key role in technological advancement and community development, which is why we at Viris also strive to contribute our share. In this article, we present how we enhanced the open-source tool Responder by adding support for the MQTT protocol, which is also widely used in smart home automation.

Categories
General

More about CTF competitions

In our previous blog titled Cybersecurity for Beginners we described how to get involved in the cybersecurity community and provided some tips on how to get started in this field. In this post, we will take a closer look at cybersecurity competitions, also known as Capture The Flag (CTF) competitions.

Categories
General

Team Viris at Hack In the Box 2021 CyberWeek in Abu Dhabi

As part of the Balkan Squad team together with Miroslav Stampar and Igor Lukic, we had a great opportunity to be part of the CyberWeek event. We have been hosting HackerSpace CTF as part of the Capture All the Things Village.

CTF was prepared in such a way, that majority of the challenges were Jeopardy-style. Some of the challenges were actual hacking assignments and there were some IoT. Since we were traveling to the United Emirates, we couldn’t resist so prepare CTF in such a way that would easily fit into the local scene. The goal of our CTF was to be able to penetrate into the main building of the oil refinery. The challenges were chained together to bring players closer and closer to the final flag.

We even created one extreme challenge which consisted out of 3 steps to open the treasure chest and to achieve the final flag, which was hidden in a well-locked chest.

Capture All The Things Village – HITB+ CyberWeek 2021

Our CTF was as its name stated HackerSpace CTF and we had challenges from these areas:
– Reversing
– Mobile apps
– Cracking
– IoT (Radio, RFID, logic gates, DOS to create some service outage)
– System hacking

For two days we have been enjoying great people and some of the good players. It was true, that we competed in the same booth as the local CTF.ae team, which also prepared a great CTF, but we found out we could cooperate in different ways.
We also connected a rotating light in our booth, so every time a correct submission was made, the light was triggered.

We were honored to get a visit from such a great hacker as Chema Alonso is. We are still using one of the amazing tools called FOCA for document metadata searches.
In the end, the winner was the Red Team from Abu Dhabi led by Tudor Enache, who managed to score most of the points at our CTF. We are sure, that the reward went to the right hands and we hope to see him and his team again in the future.