Tag: Malware

  • Hive ransomware affiliate jailed, years after FBI infiltrated the gang’s systems

    A Ukrainian man who carried out ransomware attacks for both the Nefilim and Hive gangs, including attacks on law firms and a healthcare provider during the COVID-19 pandemic, has been sentenced to 70 months in a US prison.

    Read more in my article on the Hot for Security blog.

    Source: Graham Cluley · 2026-10-28

  • Japanese internet giant GMO tells customers to shut down and disconnect PCs from the internet following data breach and ransomware threat

    Sead Fadilpašić reports: Japanese internet giant GMO Group has told its customers to scan their computers for viruses, back up all of their data, disconnect the devices from the internet and then shut them down. The announcement, which literally told customers, “unplug any cords connected to your PC,” was made in response to a cyberattack…

    Source: DataBreaches.net · 2026-10-28

  • Cron and its spares. Clear root’s crontab in one go, so the restore and watchdog lines are removed. Then kill any running zen2, devnull2, or serv processes; killed earlier, the watchdog restarts them within a minute. Remove the k.php beacons (/var/lib/asterisk/bin/zen2, devnull2, zen222, devnull312, devnull212, /tmp/.cache/update, /dev/shm/.systemd/kernel). Unlock (chattr -i, -a) and delete the eight crontab backups: /usr/lib/.systemd/.cache, /usr/share/.fonts/.config, /var/lib/.dbus/.data, /var/tmp/.X11/.Xauthority, /opt/.local/.bashrc, /var/cache/.fontconfig/.cfg, /etc/.ssl/.cert, and /root/.config/.pref.
  • Login and boot triggers. Remove the base64 stager from /root/.bash_profile, /root/.bashrc, and /etc/rc.local.
  • Accounts and SSH. Remove every extra UID-0 account and any account whose /etc/shadow hash begins with $1$nRz1Cbtk$ (legitimate service accounts with that hash need new passwords, not deletion). Restore sshd_config, where root login was re-enabled.
  • Web application. Remove the 12 webshell copies, the .htaccess, the freepbxusers row in ampusers, and /var/www/html/admin/modules/freepbx_ha/license.php.
  • Credentials. Only now rotate the secrets in the 17 files and across every account on the host.
  • Conclusion

    The hard part of the campaign used to be getting the implant off the box, and that has not changed. What has changed is that the box is no longer the whole problem: an organization that rebuilds but does not rotate has removed the operator’s calling platform and handed over its carrier account.

    The code ties this generation to the actor in our May report through the takeover script, backdoor hash, and staging host, and a gate rotated in step across JOMANGY and ZenharR.

    The operator is now rotating exactly the strings defenders were given, so detections built on provenance and behavior will outlast this build, and detections built on its hashes will not. CRIL continues to monitor INJ3CTOR3’s infrastructure.

    Indicators of Compromise

    Hashes and strings rotate between builds; use them to confirm a finding, not as your only detection.

    Value Type Context
    45[.]95[.]147[.]178 IPv4 Staging host since April
    160[.]119[.]69[.]4 IPv4 Second staging host and credential collector, new
    hxxp://45[.]95[.]147[.]178/hima_data/index.php URL Credential upload endpoint
    hxxp://160[.]119[.]69[.]4/hima_data/index.php URL Credential upload endpoint
    c6e64453ea8bc0856333b6f57567c9efd8c440410787cae135d1c4a248c07c0d SHA256 /x takeover script, identical on both hosts
    38edbfc4ac89619d2bdb3f4bb2626deaaf422868d6d7af640f59d7959903f838 SHA256 k.php, 45[.]95[.]147[.]178
    1c14a761620691a43b1a554a9eccd38d21c15d59463945250d4f57b10d20fce9 SHA256 k.php, 160[.]119[.]69[.]4
    b54a8d9e98ff36dfe63b2aea97a2003b670f7311595bb4dd072850fed5900a0b SHA256 wr.php, 45[.]95[.]147[.]178
    aa6dfd7ee90d9aea5af29ae39c14ff70cf8687118abadd7aa4fc98923f01ffd1 SHA256 wr.php, 160[.]119[.]69[.]4
    adeb015fdb37814edc3ed45230f48d2b0e87bb195a5a7e4487c01549b47c744c SHA256 JOMANGY webshell on disk, 45[.]95[.]147[.]178 build
    d345671e688ee807e1bb9b6fc45e6bb0611bbb1331c33888c8030ec2db47e672 SHA256 JOMANGY webshell on disk, 160[.]119[.]69[.]4 build
    trace_bd42a8a0d23ae16c85dede7d2abaec05, trace_7544725ebaaadac217dfaa7ca8e8fe7e String JOMANGY watermarks, one per build
    8b3a1d970fda0c17a0b785a990fb7b6a MD5 Webshell gate hash, JOMANGY and ZenharR
    $1$nRz1Cbtk$ Hash prefix Password hash set on backdoor and service accounts

    MITRE ATT&CK® Techniques

    Mapped from the September /x and k.php to MITRE ATT&CK v20; the last three rows are new in this generation.

    Technique ID Tactic Name Evidence
    T1059.004 Execution Command and Scripting Interpreter: Unix Shell /x and k.php run as bash scripts fetched by cron
    T1105 Command and Control Ingress Tool Transfer wget of /x, k.php and wr.php from the staging hosts
    T1053.003 Persistence Scheduled Task/Job: Cron Minute-level beacons, a restore line and a watchdog
    T1505.003 Persistence Server Software Component: Web Shell JOMANGY and ZenharR, 12 copies across the web root
    T1546.004 Persistence Event Triggered Execution: Unix Shell Configuration Modification Stager added to /root/.bash_profile and /root/.bashrc
    T1037.004 Persistence Boot or Logon Initialization Scripts: RC Scripts Stager added to /etc/rc.local
    T1136.001 Persistence Create Account: Local Account Backdoor accounts, several at UID 0
    T1098 Persistence Account Manipulation Shared password hash set on existing accounts; FreePBX admin row inserted
    T1027 Stealth Obfuscated Files or Information base64, base64 and ROT13 layers around the webshell; base64 cron payloads
    T1564.001 Stealth Hide Artifacts: Hidden Files and Directories Crontab spares in dot-paths such as /var/tmp/.X11/.Xauthority
    T1070.006 Stealth Indicator Removal: Timestomp touch -r copies footer.php’s timestamp onto the webshell
    T1070.003 Stealth Indicator Removal: Clear Command History Shell and MySQL histories cleared
    T1222.002 Defense Impairment File and Directory Permissions Modification: Linux and Mac Permissions chattr +i and +a on webshells and crontab spares
    T1685.006 Defense Impairment Disable or Modify Tools: Clear Linux or Mac System Logs Web server, Asterisk, cron, secure and audit logs truncated, then deleted
    T1686 Defense Impairment Disable or Modify System Firewall iptables rules dropping rival actors’ addresses
    T1496 Impact Resource Hijacking Victim’s PBX and trunks used to place premium-rate calls
    T1552.001 Credential Access Unsecured Credentials: Credentials In Files k.php reads 17 Asterisk, FreePBX, Issabel, Elastix and Postfix configuration files holding secrets
    T1119 Collection Automated Collection The 17 files are collected by hardcoded commands on every k.php run
    T1041 Exfiltration Exfiltration Over C2 Channel Multipart HTTP POST of each file to /hima_data/index.php on both staging hosts

    References

    1. Cyble Research & Intelligence Labs. JOMANGY: INJ3CTOR3’s Self-Healing FreePBX Toll Fraud Campaign, 21 May 2026.
    2. Fortinet FortiGuard Labs. Unveiling the Weaponized Web Shell: encystPHP, 28 January 2026.
    3. Palo Alto Networks Unit 42. ZenharR webshell and CVE-2021-45461 FreePBX exploitation, 2022.
    4. SANS Internet Storm Center. ISC Diary #32892, 13 April 2026.
    5. watchTowr Labs. CVE-2025-57819: FreePBX Endpoint module pre-authentication SQL injection, 2025.
    6. FreePBX Security Advisory. GHSA-vm9p-46mv-5xvw: CVE-2025-64328.
    7. The Hacker News, reporting Shadowserver Foundation data. 900 Sangoma FreePBX instances compromised, February 2026.
    8. beagle.sh: github.com/0x1da5/malware-campaigns

    Source: Cyble Research · 2026-10-28

  • Network: outbound HTTP POSTs from a PBX to any /hima_data/ path or to either staging host. A PBX seldom needs outbound web access beyond vendor updates, so egress allow-listing closes this channel.
  • Carrier: alert on trunk registrations from outside your own IP ranges, and on premium or international destinations, off-hours calling, and unusual concurrency. Set spend caps and destination blocks where your carrier offers them.

For Law Enforcement Agencies and CERTs

By design, victims’ credentials were collected on the two staging hosts, which stopped responding in late September 2026. Going offline does not end exposure: hosting providers may still retain server data, and infected PBXs keep trying to upload their credentials every minute to addresses that could be reassigned to someone else.

Both are reasons for law enforcement and national CERTs, which have the legal standing that researchers lack, to work with the providers on preserving that data and sinkholing the addresses, which would also identify victims for notification. We saw the uploads in code; we did not capture one in transit and hold no victim list.

Two Staging Hosts, Split by Encoding

An infected host now talks to both staging hosts, and which one depends on whether the command was written in plain text or base64. The /x takeover script is byte-identical on both.

Reference Encoding Points to
k.php line 2 (re-runs /x), eight cron schedules in /x, wr.php’s callback Plain text 160[.]119[.]69[.]4
Camouflaged cron payloads, login-triggered stager Base64 45[.]95[.]147[.]178
Credential upload Base64 Both

In April, all of these pointed to 45[.]95[.]147[.]178. We assess that the operator replaced the address in plain text and never re-encoded the base64 strings; the credential upload, which names both hosts, appears deliberate. This host is distinct from the scanner 160[.]119[.]76[.]250, which is named in our May report.

Defend: block both hosts in both directions, and decode every base64-encoded string in a crontab or shell profile before deciding which hosts a host talks to. A plain-text review would miss every channel that still reaches 45[.]95[.]147[.]178.

The Webshell: Same Program, New Identifiers

Decoded, the September JOMANGY panel is identical to April’s except for the values defenders were told to look for.

Per-build watermark. Our May report advised hunting for trace_e1ebf9066a951be519a24140711839ea, present in every April copy. The September builds carry trace_bd42a8a0d23ae16c85dede7d2abaec05 (45[.]95[.]147[.]178) and trace_7544725ebaaadac217dfaa7ca8e8fe7e (160[.]119[.]69[.]4), so that hunt now misses current infections.

One gate for two generations. JOMANGY and ZenharR share a single hardcoded MD5 gate hash, rotated together from a2f6863413c4192a4abfa360577b9961 to 8b3a1d970fda0c17a0b785a990fb7b6a. Our May report listed the April value under ZenharR only.

A forged administrator session. Behind the gate, the FreePBX button builds an admin session using FreePBX’s own ampuser class and setAdmin(); in our lab, it opened the full console without any password. Therefore, changing the FreePBX admin password affects neither the gate nor this session. (See Figure 3 below)

Figure 3: The panel's Freepbx and Elastix buttons forge an admin session without a password
Figure 3: The panel’s Freepbx and Elastix buttons forge an admin session without a password

Because each of these identifiers changes between builds, the detection approach later in this report focuses on who put a file on disk rather than on what the file contains.

The .htaccess Door and the Access-Log Gap

k.php writes a seven-line .htaccess to /var/www/html/admin/views/. It does not hide the webshell; it unblocks it, and it lets requests reach a copy without naming it.

RewriteEngine On
# enable symbolic links
Options +FollowSymLinks
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-l
RewriteRule ^\s+ config.php [L]
Request path Status What answered
/dir/zzz 404 Nothing
/dir/%20zzz, /dir/%09zzz (space, tab, etc) 200 config.php
/dir/+zzz 404 Nothing

Simulating an operator and a victim in an isolated environment, we confirmed that a request to a URL containing an encoded space returned a working webshell for the attacker. The access log records only the requested path, never the file that answered, so searching logs for the webshell by its filename can return nothing on a host that is serving it.

Defend: check every .htaccess across the web root for who put it there; one that no package, FreePBX module, or member of your team accounts for is suspect, whatever it contains. Because the takeover script wipes logs, treat log hunting as secondary: requests with %20, %09, or %0A directly after a slash that return 200 are worth a look where logs survive.

What the FreePBX Console Won’t Show You

FreePBX lists the trunks it created from its own database; Asterisk reads whatever is in its configuration files. In our lab, a trunk we wrote directly into /etc/asterisk/pjsip_custom.conf carried a call while the FreePBX Trunks page reported no records (See Figure 4 below). We did not see the campaign plant one, but its root-equivalent accounts and stolen trunk secrets give the operator everything needed to do so.

Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console
Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console

Defend: audit from the Asterisk CLI (pjsip show endpoints, pjsip show registrations, sip show peers, sip show registry) and compare with what the console lists. Review the *_custom.conf files for trunks or contexts that nobody on your team added.

What Keeps It There

Before detecting or cleaning, it helps to see the whole apparatus. Everything in Figure 5 is read from /x and k.php: ways the implant stays on the box, and doors allowing the operator to come back, through a system account or a single web request. Each piece can rebuild/repair all others under a minute, which is why removing any one of them on its own fails. (See Figure 5 below)

Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open
Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open

Detecting It Without IOCs

The operator rotates hashes, watermarks, gate values, and hosts between builds, so asking whether a file is known-bad quickly stops working. The better question is who put the file there: compare what is on disk with what the package manager or a clean install says it should be.

On the host: triage with beagle.sh

PBX admins can run beagle.sh, a report-only script that makes no changes to the host, to check a PBX server for signs of compromise. (See Figure 6 below)

Check What it flags
Packed shells Several identical, same-size PHP files across unrelated directories
Locked files chattr +i or +a under the web root or in hidden directories
Unowned .htaccess An .htaccess no installed package accounts for
Self-rebuilding cron A cron line that downloads a file and hands it to a shell
Accounts An extra UID-0 account, or a full-permission FreePBX admin, nobody created
Blocklist Addresses dropped in and out by iptables outside fail2ban’s chains
Figure 6: beagle.sh (Source: 0x1da5 GitHub)
Figure 6: beagle.sh (Source: 0x1da5 GitHub)

The script separated one infected server from one clean server of the same FreePBX version, a sample of one, so expect some legitimate findings. However, it cannot tell you whether the credentials have already been left: that happens during the first cron run, within a minute of infection, and long before anyone scans. The upload leaves no file behind, and the takeover script wipes what might have recorded it: the web server, Asterisk, cron and audit logs, plus shell and MySQL histories, which makes forensic timelines hard to reconstruct.

With telemetry

The most distinctive actions leave little on disk; in our detonation, backdoor accounts were created and deleted 27 seconds apart. These eleven behaviors are detection strategies to build into your own tooling:

Layer Behavior What it catches
Host crond spawns a shell that downloads a file and runs it The takeover script on its single run, before persistence and before credentials leave
Host The web server account spawns a shell The webshell’s command box in use
Host A cron child rewrites the crontab every minute without reading it first Beacon reinstallation
Host chattr +i or touch -r on a file in the web root The lock and the borrowed timestamp
Host Twelve PHP files were written to the web root in the same second The webshell copies, as they are written; fan-out
Network The PBX contacts staging host roughly every 60 seconds The beacon’s rhythm, whatever the address
Network Many configuration files read, then outbound POST requests Credentials leaving
Web A request with leading encoded whitespace returns 200 for a path not on disk The .htaccess door
Decoy Any read of a decoy config file that the implant reads, but nothing legitimate does Credential collection, with no false positives by design
Phone Channels originate over AMI or the CLI outside your dial plan A call asking for nothing legitimate
Phone CDRs with premium destinations, off-hours calling and unusual concurrency The fraud itself

The last two catch the fraud rather than the machinery, whatever the files are called, and whether you ever find the shell. The host rows need process telemetry that PBX appliances rarely have, which is part of why so many stay infected.

Why Cleanup Fails, and the Order That Works

First move Why it fails on its own
Delete the webshell Cron re-runs k.php within minutes and rewrites all 12 copies, the .htaccess, and the immutable flags.
Patch FreePBX Sangoma’s advisory for CVE-2025-57819 states the fix prevents new exploitation but does not clean a compromised system.
Change the admin password The gate and the forged session never use it, and the backdoor accounts bypass the FreePBX login.

Shadowserver data showed more than 900 compromised FreePBX instances in February 2026; over 700 of them were still compromised in May. Rebuilding from a clean image is the most reliable fix; if you clean in place, work from the system layer up, because it replants everything above it.

Preserve first

The takeover script truncates logs, then deletes them, and clears shell and database history, so evidence shrinks with every run:

  1. Cut the host off from the internet, or at least block all outbound traffic except to your SIP carrier. Blocking only the two known staging hosts is not enough if the operator has moved. With no route out, the minute-by-minute downloads fail, and nothing more is uploaded. One local loop survives: a watchdog cron line re-runs the cached copy of k.php at /var/lib/asterisk/bin/zen2 every minute, rebuilding the webshells offline, which is why cron comes first in the cleanup below.
  2. Capture all crontabs and the eight backups listed below, /etc/passwd, /etc/shadow, shell profiles, and the web root with lsattr output and change times.
  3. Export the FreePBX ampusers table, the call records database, and the Asterisk full log, and ask your carrier to preserve CDRs and registration logs.

Then clean, in this order

  1. Cron and its spares. Clear root’s crontab in one go, so the restore and watchdog lines are removed. Then kill any running zen2, devnull2, or serv processes; killed earlier, the watchdog restarts them within a minute. Remove the k.php beacons (/var/lib/asterisk/bin/zen2, devnull2, zen222, devnull312, devnull212, /tmp/.cache/update, /dev/shm/.systemd/kernel). Unlock (chattr -i, -a) and delete the eight crontab backups: /usr/lib/.systemd/.cache, /usr/share/.fonts/.config, /var/lib/.dbus/.data, /var/tmp/.X11/.Xauthority, /opt/.local/.bashrc, /var/cache/.fontconfig/.cfg, /etc/.ssl/.cert, and /root/.config/.pref.
  2. Login and boot triggers. Remove the base64 stager from /root/.bash_profile, /root/.bashrc, and /etc/rc.local.
  3. Accounts and SSH. Remove every extra UID-0 account and any account whose /etc/shadow hash begins with $1$nRz1Cbtk$ (legitimate service accounts with that hash need new passwords, not deletion). Restore sshd_config, where root login was re-enabled.
  4. Web application. Remove the 12 webshell copies, the .htaccess, the freepbxusers row in ampusers, and /var/www/html/admin/modules/freepbx_ha/license.php.
  5. Credentials. Only now rotate the secrets in the 17 files and across every account on the host.

Conclusion

The hard part of the campaign used to be getting the implant off the box, and that has not changed. What has changed is that the box is no longer the whole problem: an organization that rebuilds but does not rotate has removed the operator’s calling platform and handed over its carrier account.

The code ties this generation to the actor in our May report through the takeover script, backdoor hash, and staging host, and a gate rotated in step across JOMANGY and ZenharR.

The operator is now rotating exactly the strings defenders were given, so detections built on provenance and behavior will outlast this build, and detections built on its hashes will not. CRIL continues to monitor INJ3CTOR3’s infrastructure.

Indicators of Compromise

Hashes and strings rotate between builds; use them to confirm a finding, not as your only detection.

Value Type Context
45[.]95[.]147[.]178 IPv4 Staging host since April
160[.]119[.]69[.]4 IPv4 Second staging host and credential collector, new
hxxp://45[.]95[.]147[.]178/hima_data/index.php URL Credential upload endpoint
hxxp://160[.]119[.]69[.]4/hima_data/index.php URL Credential upload endpoint
c6e64453ea8bc0856333b6f57567c9efd8c440410787cae135d1c4a248c07c0d SHA256 /x takeover script, identical on both hosts
38edbfc4ac89619d2bdb3f4bb2626deaaf422868d6d7af640f59d7959903f838 SHA256 k.php, 45[.]95[.]147[.]178
1c14a761620691a43b1a554a9eccd38d21c15d59463945250d4f57b10d20fce9 SHA256 k.php, 160[.]119[.]69[.]4
b54a8d9e98ff36dfe63b2aea97a2003b670f7311595bb4dd072850fed5900a0b SHA256 wr.php, 45[.]95[.]147[.]178
aa6dfd7ee90d9aea5af29ae39c14ff70cf8687118abadd7aa4fc98923f01ffd1 SHA256 wr.php, 160[.]119[.]69[.]4
adeb015fdb37814edc3ed45230f48d2b0e87bb195a5a7e4487c01549b47c744c SHA256 JOMANGY webshell on disk, 45[.]95[.]147[.]178 build
d345671e688ee807e1bb9b6fc45e6bb0611bbb1331c33888c8030ec2db47e672 SHA256 JOMANGY webshell on disk, 160[.]119[.]69[.]4 build
trace_bd42a8a0d23ae16c85dede7d2abaec05, trace_7544725ebaaadac217dfaa7ca8e8fe7e String JOMANGY watermarks, one per build
8b3a1d970fda0c17a0b785a990fb7b6a MD5 Webshell gate hash, JOMANGY and ZenharR
$1$nRz1Cbtk$ Hash prefix Password hash set on backdoor and service accounts

MITRE ATT&CK® Techniques

Mapped from the September /x and k.php to MITRE ATT&CK v20; the last three rows are new in this generation.

Technique ID Tactic Name Evidence
T1059.004 Execution Command and Scripting Interpreter: Unix Shell /x and k.php run as bash scripts fetched by cron
T1105 Command and Control Ingress Tool Transfer wget of /x, k.php and wr.php from the staging hosts
T1053.003 Persistence Scheduled Task/Job: Cron Minute-level beacons, a restore line and a watchdog
T1505.003 Persistence Server Software Component: Web Shell JOMANGY and ZenharR, 12 copies across the web root
T1546.004 Persistence Event Triggered Execution: Unix Shell Configuration Modification Stager added to /root/.bash_profile and /root/.bashrc
T1037.004 Persistence Boot or Logon Initialization Scripts: RC Scripts Stager added to /etc/rc.local
T1136.001 Persistence Create Account: Local Account Backdoor accounts, several at UID 0
T1098 Persistence Account Manipulation Shared password hash set on existing accounts; FreePBX admin row inserted
T1027 Stealth Obfuscated Files or Information base64, base64 and ROT13 layers around the webshell; base64 cron payloads
T1564.001 Stealth Hide Artifacts: Hidden Files and Directories Crontab spares in dot-paths such as /var/tmp/.X11/.Xauthority
T1070.006 Stealth Indicator Removal: Timestomp touch -r copies footer.php’s timestamp onto the webshell
T1070.003 Stealth Indicator Removal: Clear Command History Shell and MySQL histories cleared
T1222.002 Defense Impairment File and Directory Permissions Modification: Linux and Mac Permissions chattr +i and +a on webshells and crontab spares
T1685.006 Defense Impairment Disable or Modify Tools: Clear Linux or Mac System Logs Web server, Asterisk, cron, secure and audit logs truncated, then deleted
T1686 Defense Impairment Disable or Modify System Firewall iptables rules dropping rival actors’ addresses
T1496 Impact Resource Hijacking Victim’s PBX and trunks used to place premium-rate calls
T1552.001 Credential Access Unsecured Credentials: Credentials In Files k.php reads 17 Asterisk, FreePBX, Issabel, Elastix and Postfix configuration files holding secrets
T1119 Collection Automated Collection The 17 files are collected by hardcoded commands on every k.php run
T1041 Exfiltration Exfiltration Over C2 Channel Multipart HTTP POST of each file to /hima_data/index.php on both staging hosts

References

  1. Cyble Research & Intelligence Labs. JOMANGY: INJ3CTOR3’s Self-Healing FreePBX Toll Fraud Campaign, 21 May 2026.
  2. Fortinet FortiGuard Labs. Unveiling the Weaponized Web Shell: encystPHP, 28 January 2026.
  3. Palo Alto Networks Unit 42. ZenharR webshell and CVE-2021-45461 FreePBX exploitation, 2022.
  4. SANS Internet Storm Center. ISC Diary #32892, 13 April 2026.
  5. watchTowr Labs. CVE-2025-57819: FreePBX Endpoint module pre-authentication SQL injection, 2025.
  6. FreePBX Security Advisory. GHSA-vm9p-46mv-5xvw: CVE-2025-64328.
  7. The Hacker News, reporting Shadowserver Foundation data. 900 Sangoma FreePBX instances compromised, February 2026.
  8. beagle.sh: github.com/0x1da5/malware-campaigns

Source: Cyble Research · 2026-10-28

  • Credentials leave on every run. k.php uploads 17 configuration files to both staging hosts every minute the host stays infected.
  • The fraud no longer needs your PBX. A stolen trunk secret lets the operator register and place calls as you from anywhere.
  • Last report’s identifiers have expired. Each build now carries its own watermark, and the webshell gate hash was rotated.
  • Two staging hosts. Plain-text commands now point to 160[.]119[.]69[.]4, while base64-encoded ones still use 45[.]95[.]147[.]178.
  • Clean-looking logs and consoles prove nothing. Requests through an encoded space reach the shell without being named in the access log, and trunks are written directly to /etc/asterisk; they do not appear in the FreePBX console.
  • The Campaign So Far

    INJ3CTOR3 has been abusing Asterisk-based phone systems for toll fraud since at least 2020. Check Point Research named the operation that November, when it exploited CVE-2019-19006 in FreePBX and used a basic webshell to read amportal.conf and sip_additional.conf by hand. Unit 42 reported a related operation against Elastix in 2022, Fortinet documented the EncystPHP webshell in January 2026, and our May report covered JOMANGY.

    The playbook has held for six years: scan for exposed PBXs, exploit or brute-force a way in, plant a password-gated webshell, and dial out at the victim’s expense. Figure 1 below shows the chain as it stands in the September build, now including the credential upload back to the staging hosts.

    Figure 1: INJ3CTOR3 attack chain, September generation. (Source: 0x1da5 GitHub)
    Figure 1: INJ3CTOR3 attack chain, September generation. (Source: 0x1da5 GitHub)

    What Changed Since Our Last Report

    We compared the April artifacts behind our May report with the 9 September collection from both staging hosts, after decoding every layer.

    Area April September
    Credential Exfiltration None 17 files to /hima_data/index.php on both hosts
    Staging hosts 45[.]95[.]147[.]178 45[.]95[.]147[.]178 and 160[.]119[.]69[.]4
    webshell watermark One value in every copy A different value per build
    Webshell gate hash (JOMANGY and ZenharR) a2f6863413c4192a4abfa360577b9961 8b3a1d970fda0c17a0b785a990fb7b6a
    /x takeover script 367 lines 620 lines, mostly added cleanup: removing rival actors’ implants and SSH keys
    wor.php, people2.txt, _*.php status files Present Absent from the collection

    Unchanged: the decoded webshell panel, the encoding chain (base64 in the shell script, base64 again in PHP, then ROT13), the persistence channels, the backdoor account password hash, and the borrowed timestamp. Behavioral detections built on our May report still apply.

    Credential Exfiltration: The Implant Is No Longer the Product

    The September k.php ends with two new base64-encoded lines, each holding 17 curl commands that upload one configuration file apiece to /hima_data/index.php, one line per staging host (See Figure 2 below). The paths are typed out by hand and cover FreePBX, Issabel, and Elastix layouts. The collector path echoes hima, a backdoor account the takeover script creates. The name goes back further: Check Point’s 2020 INJ3CTOR3 report shows a Telegram post by a user called Hima sharing a tool that scans and cracks SIP ranges, saving its output as HimaResults.

    Figure 2: k.php line 34, decoded into 17 file uploads
    Figure 2: k.php line 34, decoded into 17 file uploads

    Three of the cron beacons fetch and run k.php every minute (the others every two or three minutes), so the upload repeats every minute during the infection. Rotating credentials on a still-infected host hands the new secrets to the operator within minutes.

    What it unlocks Files uploaded Rotate
    SIP trunks and extensions (chan_sip) /etc/asterisk/sip.conf, sip_additional.conf, sip_registrations.conf, sip_general_additional.conf, sip_custom.conf Every trunk secret (with your carrier) and extension secret, changed in the FreePBX GUI, since the *_additional.conf files are regenerated
    SIP trunks and extensions (PJSIP) /etc/asterisk/pjsip.auth.conf, pjsip.endpoint.conf, pjsip.aor.conf, pjsip.identify.conf, pjsip.transports.conf The same secrets; review IP-based identity rules
    Call origination without SIP /etc/asterisk/manager.conf Every AMI user.
    PBX database, AMI, and platform admin /etc/freepbx.conf, /etc/amportal.conf, /etc/asterisk/amportal.conf, /etc/issabel.conf, /etc/elastix.conf The database password (AMPDBPASS), the MySQL root password, and any AMI password stored there
    Outbound mail /etc/postfix/sasl_passwd The SMTP relay account, with your mail provider

    This opens a second route to fraud. Our May report covered calls placed through the webshell, which require the shell to be alive and to land in the victim’s own call records. With a stolen trunk secret, the operator can register to the carrier from any machine and call as the victim, leaving nothing on the host, unless the carrier also restricts the trunk to the victim’s IP addresses. A successful disinfection stops the first route; only rotation stops the second.

    Detection

    • Network: outbound HTTP POSTs from a PBX to any /hima_data/ path or to either staging host. A PBX seldom needs outbound web access beyond vendor updates, so egress allow-listing closes this channel.
    • Carrier: alert on trunk registrations from outside your own IP ranges, and on premium or international destinations, off-hours calling, and unusual concurrency. Set spend caps and destination blocks where your carrier offers them.

    For Law Enforcement Agencies and CERTs

    By design, victims’ credentials were collected on the two staging hosts, which stopped responding in late September 2026. Going offline does not end exposure: hosting providers may still retain server data, and infected PBXs keep trying to upload their credentials every minute to addresses that could be reassigned to someone else.

    Both are reasons for law enforcement and national CERTs, which have the legal standing that researchers lack, to work with the providers on preserving that data and sinkholing the addresses, which would also identify victims for notification. We saw the uploads in code; we did not capture one in transit and hold no victim list.

    Two Staging Hosts, Split by Encoding

    An infected host now talks to both staging hosts, and which one depends on whether the command was written in plain text or base64. The /x takeover script is byte-identical on both.

    Reference Encoding Points to
    k.php line 2 (re-runs /x), eight cron schedules in /x, wr.php’s callback Plain text 160[.]119[.]69[.]4
    Camouflaged cron payloads, login-triggered stager Base64 45[.]95[.]147[.]178
    Credential upload Base64 Both

    In April, all of these pointed to 45[.]95[.]147[.]178. We assess that the operator replaced the address in plain text and never re-encoded the base64 strings; the credential upload, which names both hosts, appears deliberate. This host is distinct from the scanner 160[.]119[.]76[.]250, which is named in our May report.

    Defend: block both hosts in both directions, and decode every base64-encoded string in a crontab or shell profile before deciding which hosts a host talks to. A plain-text review would miss every channel that still reaches 45[.]95[.]147[.]178.

    The Webshell: Same Program, New Identifiers

    Decoded, the September JOMANGY panel is identical to April’s except for the values defenders were told to look for.

    Per-build watermark. Our May report advised hunting for trace_e1ebf9066a951be519a24140711839ea, present in every April copy. The September builds carry trace_bd42a8a0d23ae16c85dede7d2abaec05 (45[.]95[.]147[.]178) and trace_7544725ebaaadac217dfaa7ca8e8fe7e (160[.]119[.]69[.]4), so that hunt now misses current infections.

    One gate for two generations. JOMANGY and ZenharR share a single hardcoded MD5 gate hash, rotated together from a2f6863413c4192a4abfa360577b9961 to 8b3a1d970fda0c17a0b785a990fb7b6a. Our May report listed the April value under ZenharR only.

    A forged administrator session. Behind the gate, the FreePBX button builds an admin session using FreePBX’s own ampuser class and setAdmin(); in our lab, it opened the full console without any password. Therefore, changing the FreePBX admin password affects neither the gate nor this session. (See Figure 3 below)

    Figure 3: The panel's Freepbx and Elastix buttons forge an admin session without a password
    Figure 3: The panel’s Freepbx and Elastix buttons forge an admin session without a password

    Because each of these identifiers changes between builds, the detection approach later in this report focuses on who put a file on disk rather than on what the file contains.

    The .htaccess Door and the Access-Log Gap

    k.php writes a seven-line .htaccess to /var/www/html/admin/views/. It does not hide the webshell; it unblocks it, and it lets requests reach a copy without naming it.

    RewriteEngine On
    # enable symbolic links
    Options +FollowSymLinks
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteRule ^\s+ config.php [L]
    Request path Status What answered
    /dir/zzz 404 Nothing
    /dir/%20zzz, /dir/%09zzz (space, tab, etc) 200 config.php
    /dir/+zzz 404 Nothing

    Simulating an operator and a victim in an isolated environment, we confirmed that a request to a URL containing an encoded space returned a working webshell for the attacker. The access log records only the requested path, never the file that answered, so searching logs for the webshell by its filename can return nothing on a host that is serving it.

    Defend: check every .htaccess across the web root for who put it there; one that no package, FreePBX module, or member of your team accounts for is suspect, whatever it contains. Because the takeover script wipes logs, treat log hunting as secondary: requests with %20, %09, or %0A directly after a slash that return 200 are worth a look where logs survive.

    What the FreePBX Console Won’t Show You

    FreePBX lists the trunks it created from its own database; Asterisk reads whatever is in its configuration files. In our lab, a trunk we wrote directly into /etc/asterisk/pjsip_custom.conf carried a call while the FreePBX Trunks page reported no records (See Figure 4 below). We did not see the campaign plant one, but its root-equivalent accounts and stolen trunk secrets give the operator everything needed to do so.

    Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console
    Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console

    Defend: audit from the Asterisk CLI (pjsip show endpoints, pjsip show registrations, sip show peers, sip show registry) and compare with what the console lists. Review the *_custom.conf files for trunks or contexts that nobody on your team added.

    What Keeps It There

    Before detecting or cleaning, it helps to see the whole apparatus. Everything in Figure 5 is read from /x and k.php: ways the implant stays on the box, and doors allowing the operator to come back, through a system account or a single web request. Each piece can rebuild/repair all others under a minute, which is why removing any one of them on its own fails. (See Figure 5 below)

    Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open
    Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open

    Detecting It Without IOCs

    The operator rotates hashes, watermarks, gate values, and hosts between builds, so asking whether a file is known-bad quickly stops working. The better question is who put the file there: compare what is on disk with what the package manager or a clean install says it should be.

    On the host: triage with beagle.sh

    PBX admins can run beagle.sh, a report-only script that makes no changes to the host, to check a PBX server for signs of compromise. (See Figure 6 below)

    Check What it flags
    Packed shells Several identical, same-size PHP files across unrelated directories
    Locked files chattr +i or +a under the web root or in hidden directories
    Unowned .htaccess An .htaccess no installed package accounts for
    Self-rebuilding cron A cron line that downloads a file and hands it to a shell
    Accounts An extra UID-0 account, or a full-permission FreePBX admin, nobody created
    Blocklist Addresses dropped in and out by iptables outside fail2ban’s chains
    Figure 6: beagle.sh (Source: 0x1da5 GitHub)
    Figure 6: beagle.sh (Source: 0x1da5 GitHub)

    The script separated one infected server from one clean server of the same FreePBX version, a sample of one, so expect some legitimate findings. However, it cannot tell you whether the credentials have already been left: that happens during the first cron run, within a minute of infection, and long before anyone scans. The upload leaves no file behind, and the takeover script wipes what might have recorded it: the web server, Asterisk, cron and audit logs, plus shell and MySQL histories, which makes forensic timelines hard to reconstruct.

    With telemetry

    The most distinctive actions leave little on disk; in our detonation, backdoor accounts were created and deleted 27 seconds apart. These eleven behaviors are detection strategies to build into your own tooling:

    Layer Behavior What it catches
    Host crond spawns a shell that downloads a file and runs it The takeover script on its single run, before persistence and before credentials leave
    Host The web server account spawns a shell The webshell’s command box in use
    Host A cron child rewrites the crontab every minute without reading it first Beacon reinstallation
    Host chattr +i or touch -r on a file in the web root The lock and the borrowed timestamp
    Host Twelve PHP files were written to the web root in the same second The webshell copies, as they are written; fan-out
    Network The PBX contacts staging host roughly every 60 seconds The beacon’s rhythm, whatever the address
    Network Many configuration files read, then outbound POST requests Credentials leaving
    Web A request with leading encoded whitespace returns 200 for a path not on disk The .htaccess door
    Decoy Any read of a decoy config file that the implant reads, but nothing legitimate does Credential collection, with no false positives by design
    Phone Channels originate over AMI or the CLI outside your dial plan A call asking for nothing legitimate
    Phone CDRs with premium destinations, off-hours calling and unusual concurrency The fraud itself

    The last two catch the fraud rather than the machinery, whatever the files are called, and whether you ever find the shell. The host rows need process telemetry that PBX appliances rarely have, which is part of why so many stay infected.

    Why Cleanup Fails, and the Order That Works

    First move Why it fails on its own
    Delete the webshell Cron re-runs k.php within minutes and rewrites all 12 copies, the .htaccess, and the immutable flags.
    Patch FreePBX Sangoma’s advisory for CVE-2025-57819 states the fix prevents new exploitation but does not clean a compromised system.
    Change the admin password The gate and the forged session never use it, and the backdoor accounts bypass the FreePBX login.

    Shadowserver data showed more than 900 compromised FreePBX instances in February 2026; over 700 of them were still compromised in May. Rebuilding from a clean image is the most reliable fix; if you clean in place, work from the system layer up, because it replants everything above it.

    Preserve first

    The takeover script truncates logs, then deletes them, and clears shell and database history, so evidence shrinks with every run:

    1. Cut the host off from the internet, or at least block all outbound traffic except to your SIP carrier. Blocking only the two known staging hosts is not enough if the operator has moved. With no route out, the minute-by-minute downloads fail, and nothing more is uploaded. One local loop survives: a watchdog cron line re-runs the cached copy of k.php at /var/lib/asterisk/bin/zen2 every minute, rebuilding the webshells offline, which is why cron comes first in the cleanup below.
    2. Capture all crontabs and the eight backups listed below, /etc/passwd, /etc/shadow, shell profiles, and the web root with lsattr output and change times.
    3. Export the FreePBX ampusers table, the call records database, and the Asterisk full log, and ask your carrier to preserve CDRs and registration logs.

    Then clean, in this order

    1. Cron and its spares. Clear root’s crontab in one go, so the restore and watchdog lines are removed. Then kill any running zen2, devnull2, or serv processes; killed earlier, the watchdog restarts them within a minute. Remove the k.php beacons (/var/lib/asterisk/bin/zen2, devnull2, zen222, devnull312, devnull212, /tmp/.cache/update, /dev/shm/.systemd/kernel). Unlock (chattr -i, -a) and delete the eight crontab backups: /usr/lib/.systemd/.cache, /usr/share/.fonts/.config, /var/lib/.dbus/.data, /var/tmp/.X11/.Xauthority, /opt/.local/.bashrc, /var/cache/.fontconfig/.cfg, /etc/.ssl/.cert, and /root/.config/.pref.
    2. Login and boot triggers. Remove the base64 stager from /root/.bash_profile, /root/.bashrc, and /etc/rc.local.
    3. Accounts and SSH. Remove every extra UID-0 account and any account whose /etc/shadow hash begins with $1$nRz1Cbtk$ (legitimate service accounts with that hash need new passwords, not deletion). Restore sshd_config, where root login was re-enabled.
    4. Web application. Remove the 12 webshell copies, the .htaccess, the freepbxusers row in ampusers, and /var/www/html/admin/modules/freepbx_ha/license.php.
    5. Credentials. Only now rotate the secrets in the 17 files and across every account on the host.

    Conclusion

    The hard part of the campaign used to be getting the implant off the box, and that has not changed. What has changed is that the box is no longer the whole problem: an organization that rebuilds but does not rotate has removed the operator’s calling platform and handed over its carrier account.

    The code ties this generation to the actor in our May report through the takeover script, backdoor hash, and staging host, and a gate rotated in step across JOMANGY and ZenharR.

    The operator is now rotating exactly the strings defenders were given, so detections built on provenance and behavior will outlast this build, and detections built on its hashes will not. CRIL continues to monitor INJ3CTOR3’s infrastructure.

    Indicators of Compromise

    Hashes and strings rotate between builds; use them to confirm a finding, not as your only detection.

    Value Type Context
    45[.]95[.]147[.]178 IPv4 Staging host since April
    160[.]119[.]69[.]4 IPv4 Second staging host and credential collector, new
    hxxp://45[.]95[.]147[.]178/hima_data/index.php URL Credential upload endpoint
    hxxp://160[.]119[.]69[.]4/hima_data/index.php URL Credential upload endpoint
    c6e64453ea8bc0856333b6f57567c9efd8c440410787cae135d1c4a248c07c0d SHA256 /x takeover script, identical on both hosts
    38edbfc4ac89619d2bdb3f4bb2626deaaf422868d6d7af640f59d7959903f838 SHA256 k.php, 45[.]95[.]147[.]178
    1c14a761620691a43b1a554a9eccd38d21c15d59463945250d4f57b10d20fce9 SHA256 k.php, 160[.]119[.]69[.]4
    b54a8d9e98ff36dfe63b2aea97a2003b670f7311595bb4dd072850fed5900a0b SHA256 wr.php, 45[.]95[.]147[.]178
    aa6dfd7ee90d9aea5af29ae39c14ff70cf8687118abadd7aa4fc98923f01ffd1 SHA256 wr.php, 160[.]119[.]69[.]4
    adeb015fdb37814edc3ed45230f48d2b0e87bb195a5a7e4487c01549b47c744c SHA256 JOMANGY webshell on disk, 45[.]95[.]147[.]178 build
    d345671e688ee807e1bb9b6fc45e6bb0611bbb1331c33888c8030ec2db47e672 SHA256 JOMANGY webshell on disk, 160[.]119[.]69[.]4 build
    trace_bd42a8a0d23ae16c85dede7d2abaec05, trace_7544725ebaaadac217dfaa7ca8e8fe7e String JOMANGY watermarks, one per build
    8b3a1d970fda0c17a0b785a990fb7b6a MD5 Webshell gate hash, JOMANGY and ZenharR
    $1$nRz1Cbtk$ Hash prefix Password hash set on backdoor and service accounts

    MITRE ATT&CK® Techniques

    Mapped from the September /x and k.php to MITRE ATT&CK v20; the last three rows are new in this generation.

    Technique ID Tactic Name Evidence
    T1059.004 Execution Command and Scripting Interpreter: Unix Shell /x and k.php run as bash scripts fetched by cron
    T1105 Command and Control Ingress Tool Transfer wget of /x, k.php and wr.php from the staging hosts
    T1053.003 Persistence Scheduled Task/Job: Cron Minute-level beacons, a restore line and a watchdog
    T1505.003 Persistence Server Software Component: Web Shell JOMANGY and ZenharR, 12 copies across the web root
    T1546.004 Persistence Event Triggered Execution: Unix Shell Configuration Modification Stager added to /root/.bash_profile and /root/.bashrc
    T1037.004 Persistence Boot or Logon Initialization Scripts: RC Scripts Stager added to /etc/rc.local
    T1136.001 Persistence Create Account: Local Account Backdoor accounts, several at UID 0
    T1098 Persistence Account Manipulation Shared password hash set on existing accounts; FreePBX admin row inserted
    T1027 Stealth Obfuscated Files or Information base64, base64 and ROT13 layers around the webshell; base64 cron payloads
    T1564.001 Stealth Hide Artifacts: Hidden Files and Directories Crontab spares in dot-paths such as /var/tmp/.X11/.Xauthority
    T1070.006 Stealth Indicator Removal: Timestomp touch -r copies footer.php’s timestamp onto the webshell
    T1070.003 Stealth Indicator Removal: Clear Command History Shell and MySQL histories cleared
    T1222.002 Defense Impairment File and Directory Permissions Modification: Linux and Mac Permissions chattr +i and +a on webshells and crontab spares
    T1685.006 Defense Impairment Disable or Modify Tools: Clear Linux or Mac System Logs Web server, Asterisk, cron, secure and audit logs truncated, then deleted
    T1686 Defense Impairment Disable or Modify System Firewall iptables rules dropping rival actors’ addresses
    T1496 Impact Resource Hijacking Victim’s PBX and trunks used to place premium-rate calls
    T1552.001 Credential Access Unsecured Credentials: Credentials In Files k.php reads 17 Asterisk, FreePBX, Issabel, Elastix and Postfix configuration files holding secrets
    T1119 Collection Automated Collection The 17 files are collected by hardcoded commands on every k.php run
    T1041 Exfiltration Exfiltration Over C2 Channel Multipart HTTP POST of each file to /hima_data/index.php on both staging hosts

    References

    1. Cyble Research & Intelligence Labs. JOMANGY: INJ3CTOR3’s Self-Healing FreePBX Toll Fraud Campaign, 21 May 2026.
    2. Fortinet FortiGuard Labs. Unveiling the Weaponized Web Shell: encystPHP, 28 January 2026.
    3. Palo Alto Networks Unit 42. ZenharR webshell and CVE-2021-45461 FreePBX exploitation, 2022.
    4. SANS Internet Storm Center. ISC Diary #32892, 13 April 2026.
    5. watchTowr Labs. CVE-2025-57819: FreePBX Endpoint module pre-authentication SQL injection, 2025.
    6. FreePBX Security Advisory. GHSA-vm9p-46mv-5xvw: CVE-2025-64328.
    7. The Hacker News, reporting Shadowserver Foundation data. 900 Sangoma FreePBX instances compromised, February 2026.
    8. beagle.sh: github.com/0x1da5/malware-campaigns

    Source: Cyble Research · 2026-10-28

    From Hijacked PBX to Stolen Trunk: INJ3CTOR3’s Campaign Evolves

    Executive Summary

    In May, Cyble Research & Intelligence Labs (CRIL) documented JOMANGY, a PHP webshell generation deployed by INJ3CTOR3 with self-healing persistence channels and a built-in toll-fraud dialer.

    Back then, the fraud ran through the victim’s own PBX, so removing the implant would have stopped it. Artifacts we collected from the operator’s C2 staging servers during mid-September 2026 show that this is no longer true: the installer now sends credentials off the box on every run, and a second staging host serves it.

    INJ3CTOR3’s FreePBX implant now uploads the victim’s SIP trunk, AMI, database, and mail-relay credentials to the operator, so disinfecting or rebuilding an infected host no longer ends the exposure. Anyone running FreePBX, Issabel, or Elastix who suspects compromise must rotate the secrets in 17 configuration files, and only after the host is clean.

    The infection and persistence code is nearly unchanged; what the operator rotated are the identifiers that were available to defenders since the last time. Each section below pairs a finding with what to do about it.

    Key Takeaways

    • Credentials leave on every run. k.php uploads 17 configuration files to both staging hosts every minute the host stays infected.
    • The fraud no longer needs your PBX. A stolen trunk secret lets the operator register and place calls as you from anywhere.
    • Last report’s identifiers have expired. Each build now carries its own watermark, and the webshell gate hash was rotated.
    • Two staging hosts. Plain-text commands now point to 160[.]119[.]69[.]4, while base64-encoded ones still use 45[.]95[.]147[.]178.
    • Clean-looking logs and consoles prove nothing. Requests through an encoded space reach the shell without being named in the access log, and trunks are written directly to /etc/asterisk; they do not appear in the FreePBX console.

    The Campaign So Far

    INJ3CTOR3 has been abusing Asterisk-based phone systems for toll fraud since at least 2020. Check Point Research named the operation that November, when it exploited CVE-2019-19006 in FreePBX and used a basic webshell to read amportal.conf and sip_additional.conf by hand. Unit 42 reported a related operation against Elastix in 2022, Fortinet documented the EncystPHP webshell in January 2026, and our May report covered JOMANGY.

    The playbook has held for six years: scan for exposed PBXs, exploit or brute-force a way in, plant a password-gated webshell, and dial out at the victim’s expense. Figure 1 below shows the chain as it stands in the September build, now including the credential upload back to the staging hosts.

    Figure 1: INJ3CTOR3 attack chain, September generation. (Source: 0x1da5 GitHub)
    Figure 1: INJ3CTOR3 attack chain, September generation. (Source: 0x1da5 GitHub)

    What Changed Since Our Last Report

    We compared the April artifacts behind our May report with the 9 September collection from both staging hosts, after decoding every layer.

    Area April September
    Credential Exfiltration None 17 files to /hima_data/index.php on both hosts
    Staging hosts 45[.]95[.]147[.]178 45[.]95[.]147[.]178 and 160[.]119[.]69[.]4
    webshell watermark One value in every copy A different value per build
    Webshell gate hash (JOMANGY and ZenharR) a2f6863413c4192a4abfa360577b9961 8b3a1d970fda0c17a0b785a990fb7b6a
    /x takeover script 367 lines 620 lines, mostly added cleanup: removing rival actors’ implants and SSH keys
    wor.php, people2.txt, _*.php status files Present Absent from the collection

    Unchanged: the decoded webshell panel, the encoding chain (base64 in the shell script, base64 again in PHP, then ROT13), the persistence channels, the backdoor account password hash, and the borrowed timestamp. Behavioral detections built on our May report still apply.

    Credential Exfiltration: The Implant Is No Longer the Product

    The September k.php ends with two new base64-encoded lines, each holding 17 curl commands that upload one configuration file apiece to /hima_data/index.php, one line per staging host (See Figure 2 below). The paths are typed out by hand and cover FreePBX, Issabel, and Elastix layouts. The collector path echoes hima, a backdoor account the takeover script creates. The name goes back further: Check Point’s 2020 INJ3CTOR3 report shows a Telegram post by a user called Hima sharing a tool that scans and cracks SIP ranges, saving its output as HimaResults.

    Figure 2: k.php line 34, decoded into 17 file uploads
    Figure 2: k.php line 34, decoded into 17 file uploads

    Three of the cron beacons fetch and run k.php every minute (the others every two or three minutes), so the upload repeats every minute during the infection. Rotating credentials on a still-infected host hands the new secrets to the operator within minutes.

    What it unlocks Files uploaded Rotate
    SIP trunks and extensions (chan_sip) /etc/asterisk/sip.conf, sip_additional.conf, sip_registrations.conf, sip_general_additional.conf, sip_custom.conf Every trunk secret (with your carrier) and extension secret, changed in the FreePBX GUI, since the *_additional.conf files are regenerated
    SIP trunks and extensions (PJSIP) /etc/asterisk/pjsip.auth.conf, pjsip.endpoint.conf, pjsip.aor.conf, pjsip.identify.conf, pjsip.transports.conf The same secrets; review IP-based identity rules
    Call origination without SIP /etc/asterisk/manager.conf Every AMI user.
    PBX database, AMI, and platform admin /etc/freepbx.conf, /etc/amportal.conf, /etc/asterisk/amportal.conf, /etc/issabel.conf, /etc/elastix.conf The database password (AMPDBPASS), the MySQL root password, and any AMI password stored there
    Outbound mail /etc/postfix/sasl_passwd The SMTP relay account, with your mail provider

    This opens a second route to fraud. Our May report covered calls placed through the webshell, which require the shell to be alive and to land in the victim’s own call records. With a stolen trunk secret, the operator can register to the carrier from any machine and call as the victim, leaving nothing on the host, unless the carrier also restricts the trunk to the victim’s IP addresses. A successful disinfection stops the first route; only rotation stops the second.

    Detection

    • Network: outbound HTTP POSTs from a PBX to any /hima_data/ path or to either staging host. A PBX seldom needs outbound web access beyond vendor updates, so egress allow-listing closes this channel.
    • Carrier: alert on trunk registrations from outside your own IP ranges, and on premium or international destinations, off-hours calling, and unusual concurrency. Set spend caps and destination blocks where your carrier offers them.

    For Law Enforcement Agencies and CERTs

    By design, victims’ credentials were collected on the two staging hosts, which stopped responding in late September 2026. Going offline does not end exposure: hosting providers may still retain server data, and infected PBXs keep trying to upload their credentials every minute to addresses that could be reassigned to someone else.

    Both are reasons for law enforcement and national CERTs, which have the legal standing that researchers lack, to work with the providers on preserving that data and sinkholing the addresses, which would also identify victims for notification. We saw the uploads in code; we did not capture one in transit and hold no victim list.

    Two Staging Hosts, Split by Encoding

    An infected host now talks to both staging hosts, and which one depends on whether the command was written in plain text or base64. The /x takeover script is byte-identical on both.

    Reference Encoding Points to
    k.php line 2 (re-runs /x), eight cron schedules in /x, wr.php’s callback Plain text 160[.]119[.]69[.]4
    Camouflaged cron payloads, login-triggered stager Base64 45[.]95[.]147[.]178
    Credential upload Base64 Both

    In April, all of these pointed to 45[.]95[.]147[.]178. We assess that the operator replaced the address in plain text and never re-encoded the base64 strings; the credential upload, which names both hosts, appears deliberate. This host is distinct from the scanner 160[.]119[.]76[.]250, which is named in our May report.

    Defend: block both hosts in both directions, and decode every base64-encoded string in a crontab or shell profile before deciding which hosts a host talks to. A plain-text review would miss every channel that still reaches 45[.]95[.]147[.]178.

    The Webshell: Same Program, New Identifiers

    Decoded, the September JOMANGY panel is identical to April’s except for the values defenders were told to look for.

    Per-build watermark. Our May report advised hunting for trace_e1ebf9066a951be519a24140711839ea, present in every April copy. The September builds carry trace_bd42a8a0d23ae16c85dede7d2abaec05 (45[.]95[.]147[.]178) and trace_7544725ebaaadac217dfaa7ca8e8fe7e (160[.]119[.]69[.]4), so that hunt now misses current infections.

    One gate for two generations. JOMANGY and ZenharR share a single hardcoded MD5 gate hash, rotated together from a2f6863413c4192a4abfa360577b9961 to 8b3a1d970fda0c17a0b785a990fb7b6a. Our May report listed the April value under ZenharR only.

    A forged administrator session. Behind the gate, the FreePBX button builds an admin session using FreePBX’s own ampuser class and setAdmin(); in our lab, it opened the full console without any password. Therefore, changing the FreePBX admin password affects neither the gate nor this session. (See Figure 3 below)

    Figure 3: The panel's Freepbx and Elastix buttons forge an admin session without a password
    Figure 3: The panel’s Freepbx and Elastix buttons forge an admin session without a password

    Because each of these identifiers changes between builds, the detection approach later in this report focuses on who put a file on disk rather than on what the file contains.

    The .htaccess Door and the Access-Log Gap

    k.php writes a seven-line .htaccess to /var/www/html/admin/views/. It does not hide the webshell; it unblocks it, and it lets requests reach a copy without naming it.

    RewriteEngine On
    # enable symbolic links
    Options +FollowSymLinks
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteRule ^\s+ config.php [L]
    Request path Status What answered
    /dir/zzz 404 Nothing
    /dir/%20zzz, /dir/%09zzz (space, tab, etc) 200 config.php
    /dir/+zzz 404 Nothing

    Simulating an operator and a victim in an isolated environment, we confirmed that a request to a URL containing an encoded space returned a working webshell for the attacker. The access log records only the requested path, never the file that answered, so searching logs for the webshell by its filename can return nothing on a host that is serving it.

    Defend: check every .htaccess across the web root for who put it there; one that no package, FreePBX module, or member of your team accounts for is suspect, whatever it contains. Because the takeover script wipes logs, treat log hunting as secondary: requests with %20, %09, or %0A directly after a slash that return 200 are worth a look where logs survive.

    What the FreePBX Console Won’t Show You

    FreePBX lists the trunks it created from its own database; Asterisk reads whatever is in its configuration files. In our lab, a trunk we wrote directly into /etc/asterisk/pjsip_custom.conf carried a call while the FreePBX Trunks page reported no records (See Figure 4 below). We did not see the campaign plant one, but its root-equivalent accounts and stolen trunk secrets give the operator everything needed to do so.

    Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console
    Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console

    Defend: audit from the Asterisk CLI (pjsip show endpoints, pjsip show registrations, sip show peers, sip show registry) and compare with what the console lists. Review the *_custom.conf files for trunks or contexts that nobody on your team added.

    What Keeps It There

    Before detecting or cleaning, it helps to see the whole apparatus. Everything in Figure 5 is read from /x and k.php: ways the implant stays on the box, and doors allowing the operator to come back, through a system account or a single web request. Each piece can rebuild/repair all others under a minute, which is why removing any one of them on its own fails. (See Figure 5 below)

    Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open
    Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open

    Detecting It Without IOCs

    The operator rotates hashes, watermarks, gate values, and hosts between builds, so asking whether a file is known-bad quickly stops working. The better question is who put the file there: compare what is on disk with what the package manager or a clean install says it should be.

    On the host: triage with beagle.sh

    PBX admins can run beagle.sh, a report-only script that makes no changes to the host, to check a PBX server for signs of compromise. (See Figure 6 below)

    Check What it flags
    Packed shells Several identical, same-size PHP files across unrelated directories
    Locked files chattr +i or +a under the web root or in hidden directories
    Unowned .htaccess An .htaccess no installed package accounts for
    Self-rebuilding cron A cron line that downloads a file and hands it to a shell
    Accounts An extra UID-0 account, or a full-permission FreePBX admin, nobody created
    Blocklist Addresses dropped in and out by iptables outside fail2ban’s chains
    Figure 6: beagle.sh (Source: 0x1da5 GitHub)
    Figure 6: beagle.sh (Source: 0x1da5 GitHub)

    The script separated one infected server from one clean server of the same FreePBX version, a sample of one, so expect some legitimate findings. However, it cannot tell you whether the credentials have already been left: that happens during the first cron run, within a minute of infection, and long before anyone scans. The upload leaves no file behind, and the takeover script wipes what might have recorded it: the web server, Asterisk, cron and audit logs, plus shell and MySQL histories, which makes forensic timelines hard to reconstruct.

    With telemetry

    The most distinctive actions leave little on disk; in our detonation, backdoor accounts were created and deleted 27 seconds apart. These eleven behaviors are detection strategies to build into your own tooling:

    Layer Behavior What it catches
    Host crond spawns a shell that downloads a file and runs it The takeover script on its single run, before persistence and before credentials leave
    Host The web server account spawns a shell The webshell’s command box in use
    Host A cron child rewrites the crontab every minute without reading it first Beacon reinstallation
    Host chattr +i or touch -r on a file in the web root The lock and the borrowed timestamp
    Host Twelve PHP files were written to the web root in the same second The webshell copies, as they are written; fan-out
    Network The PBX contacts staging host roughly every 60 seconds The beacon’s rhythm, whatever the address
    Network Many configuration files read, then outbound POST requests Credentials leaving
    Web A request with leading encoded whitespace returns 200 for a path not on disk The .htaccess door
    Decoy Any read of a decoy config file that the implant reads, but nothing legitimate does Credential collection, with no false positives by design
    Phone Channels originate over AMI or the CLI outside your dial plan A call asking for nothing legitimate
    Phone CDRs with premium destinations, off-hours calling and unusual concurrency The fraud itself

    The last two catch the fraud rather than the machinery, whatever the files are called, and whether you ever find the shell. The host rows need process telemetry that PBX appliances rarely have, which is part of why so many stay infected.

    Why Cleanup Fails, and the Order That Works

    First move Why it fails on its own
    Delete the webshell Cron re-runs k.php within minutes and rewrites all 12 copies, the .htaccess, and the immutable flags.
    Patch FreePBX Sangoma’s advisory for CVE-2025-57819 states the fix prevents new exploitation but does not clean a compromised system.
    Change the admin password The gate and the forged session never use it, and the backdoor accounts bypass the FreePBX login.

    Shadowserver data showed more than 900 compromised FreePBX instances in February 2026; over 700 of them were still compromised in May. Rebuilding from a clean image is the most reliable fix; if you clean in place, work from the system layer up, because it replants everything above it.

    Preserve first

    The takeover script truncates logs, then deletes them, and clears shell and database history, so evidence shrinks with every run:

    1. Cut the host off from the internet, or at least block all outbound traffic except to your SIP carrier. Blocking only the two known staging hosts is not enough if the operator has moved. With no route out, the minute-by-minute downloads fail, and nothing more is uploaded. One local loop survives: a watchdog cron line re-runs the cached copy of k.php at /var/lib/asterisk/bin/zen2 every minute, rebuilding the webshells offline, which is why cron comes first in the cleanup below.
    2. Capture all crontabs and the eight backups listed below, /etc/passwd, /etc/shadow, shell profiles, and the web root with lsattr output and change times.
    3. Export the FreePBX ampusers table, the call records database, and the Asterisk full log, and ask your carrier to preserve CDRs and registration logs.

    Then clean, in this order

    1. Cron and its spares. Clear root’s crontab in one go, so the restore and watchdog lines are removed. Then kill any running zen2, devnull2, or serv processes; killed earlier, the watchdog restarts them within a minute. Remove the k.php beacons (/var/lib/asterisk/bin/zen2, devnull2, zen222, devnull312, devnull212, /tmp/.cache/update, /dev/shm/.systemd/kernel). Unlock (chattr -i, -a) and delete the eight crontab backups: /usr/lib/.systemd/.cache, /usr/share/.fonts/.config, /var/lib/.dbus/.data, /var/tmp/.X11/.Xauthority, /opt/.local/.bashrc, /var/cache/.fontconfig/.cfg, /etc/.ssl/.cert, and /root/.config/.pref.
    2. Login and boot triggers. Remove the base64 stager from /root/.bash_profile, /root/.bashrc, and /etc/rc.local.
    3. Accounts and SSH. Remove every extra UID-0 account and any account whose /etc/shadow hash begins with $1$nRz1Cbtk$ (legitimate service accounts with that hash need new passwords, not deletion). Restore sshd_config, where root login was re-enabled.
    4. Web application. Remove the 12 webshell copies, the .htaccess, the freepbxusers row in ampusers, and /var/www/html/admin/modules/freepbx_ha/license.php.
    5. Credentials. Only now rotate the secrets in the 17 files and across every account on the host.

    Conclusion

    The hard part of the campaign used to be getting the implant off the box, and that has not changed. What has changed is that the box is no longer the whole problem: an organization that rebuilds but does not rotate has removed the operator’s calling platform and handed over its carrier account.

    The code ties this generation to the actor in our May report through the takeover script, backdoor hash, and staging host, and a gate rotated in step across JOMANGY and ZenharR.

    The operator is now rotating exactly the strings defenders were given, so detections built on provenance and behavior will outlast this build, and detections built on its hashes will not. CRIL continues to monitor INJ3CTOR3’s infrastructure.

    Indicators of Compromise

    Hashes and strings rotate between builds; use them to confirm a finding, not as your only detection.

    Value Type Context
    45[.]95[.]147[.]178 IPv4 Staging host since April
    160[.]119[.]69[.]4 IPv4 Second staging host and credential collector, new
    hxxp://45[.]95[.]147[.]178/hima_data/index.php URL Credential upload endpoint
    hxxp://160[.]119[.]69[.]4/hima_data/index.php URL Credential upload endpoint
    c6e64453ea8bc0856333b6f57567c9efd8c440410787cae135d1c4a248c07c0d SHA256 /x takeover script, identical on both hosts
    38edbfc4ac89619d2bdb3f4bb2626deaaf422868d6d7af640f59d7959903f838 SHA256 k.php, 45[.]95[.]147[.]178
    1c14a761620691a43b1a554a9eccd38d21c15d59463945250d4f57b10d20fce9 SHA256 k.php, 160[.]119[.]69[.]4
    b54a8d9e98ff36dfe63b2aea97a2003b670f7311595bb4dd072850fed5900a0b SHA256 wr.php, 45[.]95[.]147[.]178
    aa6dfd7ee90d9aea5af29ae39c14ff70cf8687118abadd7aa4fc98923f01ffd1 SHA256 wr.php, 160[.]119[.]69[.]4
    adeb015fdb37814edc3ed45230f48d2b0e87bb195a5a7e4487c01549b47c744c SHA256 JOMANGY webshell on disk, 45[.]95[.]147[.]178 build
    d345671e688ee807e1bb9b6fc45e6bb0611bbb1331c33888c8030ec2db47e672 SHA256 JOMANGY webshell on disk, 160[.]119[.]69[.]4 build
    trace_bd42a8a0d23ae16c85dede7d2abaec05, trace_7544725ebaaadac217dfaa7ca8e8fe7e String JOMANGY watermarks, one per build
    8b3a1d970fda0c17a0b785a990fb7b6a MD5 Webshell gate hash, JOMANGY and ZenharR
    $1$nRz1Cbtk$ Hash prefix Password hash set on backdoor and service accounts

    MITRE ATT&CK® Techniques

    Mapped from the September /x and k.php to MITRE ATT&CK v20; the last three rows are new in this generation.

    Technique ID Tactic Name Evidence
    T1059.004 Execution Command and Scripting Interpreter: Unix Shell /x and k.php run as bash scripts fetched by cron
    T1105 Command and Control Ingress Tool Transfer wget of /x, k.php and wr.php from the staging hosts
    T1053.003 Persistence Scheduled Task/Job: Cron Minute-level beacons, a restore line and a watchdog
    T1505.003 Persistence Server Software Component: Web Shell JOMANGY and ZenharR, 12 copies across the web root
    T1546.004 Persistence Event Triggered Execution: Unix Shell Configuration Modification Stager added to /root/.bash_profile and /root/.bashrc
    T1037.004 Persistence Boot or Logon Initialization Scripts: RC Scripts Stager added to /etc/rc.local
    T1136.001 Persistence Create Account: Local Account Backdoor accounts, several at UID 0
    T1098 Persistence Account Manipulation Shared password hash set on existing accounts; FreePBX admin row inserted
    T1027 Stealth Obfuscated Files or Information base64, base64 and ROT13 layers around the webshell; base64 cron payloads
    T1564.001 Stealth Hide Artifacts: Hidden Files and Directories Crontab spares in dot-paths such as /var/tmp/.X11/.Xauthority
    T1070.006 Stealth Indicator Removal: Timestomp touch -r copies footer.php’s timestamp onto the webshell
    T1070.003 Stealth Indicator Removal: Clear Command History Shell and MySQL histories cleared
    T1222.002 Defense Impairment File and Directory Permissions Modification: Linux and Mac Permissions chattr +i and +a on webshells and crontab spares
    T1685.006 Defense Impairment Disable or Modify Tools: Clear Linux or Mac System Logs Web server, Asterisk, cron, secure and audit logs truncated, then deleted
    T1686 Defense Impairment Disable or Modify System Firewall iptables rules dropping rival actors’ addresses
    T1496 Impact Resource Hijacking Victim’s PBX and trunks used to place premium-rate calls
    T1552.001 Credential Access Unsecured Credentials: Credentials In Files k.php reads 17 Asterisk, FreePBX, Issabel, Elastix and Postfix configuration files holding secrets
    T1119 Collection Automated Collection The 17 files are collected by hardcoded commands on every k.php run
    T1041 Exfiltration Exfiltration Over C2 Channel Multipart HTTP POST of each file to /hima_data/index.php on both staging hosts

    References

    1. Cyble Research & Intelligence Labs. JOMANGY: INJ3CTOR3’s Self-Healing FreePBX Toll Fraud Campaign, 21 May 2026.
    2. Fortinet FortiGuard Labs. Unveiling the Weaponized Web Shell: encystPHP, 28 January 2026.
    3. Palo Alto Networks Unit 42. ZenharR webshell and CVE-2021-45461 FreePBX exploitation, 2022.
    4. SANS Internet Storm Center. ISC Diary #32892, 13 April 2026.
    5. watchTowr Labs. CVE-2025-57819: FreePBX Endpoint module pre-authentication SQL injection, 2025.
    6. FreePBX Security Advisory. GHSA-vm9p-46mv-5xvw: CVE-2025-64328.
    7. The Hacker News, reporting Shadowserver Foundation data. 900 Sangoma FreePBX instances compromised, February 2026.
    8. beagle.sh: github.com/0x1da5/malware-campaigns

    Source: Cyble Research · 2026-10-28

    From Hijacked PBX to Stolen Trunk: INJ3CTOR3’s Campaign Evolves

    Executive Summary

    In May, Cyble Research & Intelligence Labs (CRIL) documented JOMANGY, a PHP webshell generation deployed by INJ3CTOR3 with self-healing persistence channels and a built-in toll-fraud dialer.

    Back then, the fraud ran through the victim’s own PBX, so removing the implant would have stopped it. Artifacts we collected from the operator’s C2 staging servers during mid-September 2026 show that this is no longer true: the installer now sends credentials off the box on every run, and a second staging host serves it.

    INJ3CTOR3’s FreePBX implant now uploads the victim’s SIP trunk, AMI, database, and mail-relay credentials to the operator, so disinfecting or rebuilding an infected host no longer ends the exposure. Anyone running FreePBX, Issabel, or Elastix who suspects compromise must rotate the secrets in 17 configuration files, and only after the host is clean.

    The infection and persistence code is nearly unchanged; what the operator rotated are the identifiers that were available to defenders since the last time. Each section below pairs a finding with what to do about it.

    Key Takeaways

    • Credentials leave on every run. k.php uploads 17 configuration files to both staging hosts every minute the host stays infected.
    • The fraud no longer needs your PBX. A stolen trunk secret lets the operator register and place calls as you from anywhere.
    • Last report’s identifiers have expired. Each build now carries its own watermark, and the webshell gate hash was rotated.
    • Two staging hosts. Plain-text commands now point to 160[.]119[.]69[.]4, while base64-encoded ones still use 45[.]95[.]147[.]178.
    • Clean-looking logs and consoles prove nothing. Requests through an encoded space reach the shell without being named in the access log, and trunks are written directly to /etc/asterisk; they do not appear in the FreePBX console.

    The Campaign So Far

    INJ3CTOR3 has been abusing Asterisk-based phone systems for toll fraud since at least 2020. Check Point Research named the operation that November, when it exploited CVE-2019-19006 in FreePBX and used a basic webshell to read amportal.conf and sip_additional.conf by hand. Unit 42 reported a related operation against Elastix in 2022, Fortinet documented the EncystPHP webshell in January 2026, and our May report covered JOMANGY.

    The playbook has held for six years: scan for exposed PBXs, exploit or brute-force a way in, plant a password-gated webshell, and dial out at the victim’s expense. Figure 1 below shows the chain as it stands in the September build, now including the credential upload back to the staging hosts.

    Figure 1: INJ3CTOR3 attack chain, September generation. (Source: 0x1da5 GitHub)
    Figure 1: INJ3CTOR3 attack chain, September generation. (Source: 0x1da5 GitHub)

    What Changed Since Our Last Report

    We compared the April artifacts behind our May report with the 9 September collection from both staging hosts, after decoding every layer.

    Area April September
    Credential Exfiltration None 17 files to /hima_data/index.php on both hosts
    Staging hosts 45[.]95[.]147[.]178 45[.]95[.]147[.]178 and 160[.]119[.]69[.]4
    webshell watermark One value in every copy A different value per build
    Webshell gate hash (JOMANGY and ZenharR) a2f6863413c4192a4abfa360577b9961 8b3a1d970fda0c17a0b785a990fb7b6a
    /x takeover script 367 lines 620 lines, mostly added cleanup: removing rival actors’ implants and SSH keys
    wor.php, people2.txt, _*.php status files Present Absent from the collection

    Unchanged: the decoded webshell panel, the encoding chain (base64 in the shell script, base64 again in PHP, then ROT13), the persistence channels, the backdoor account password hash, and the borrowed timestamp. Behavioral detections built on our May report still apply.

    Credential Exfiltration: The Implant Is No Longer the Product

    The September k.php ends with two new base64-encoded lines, each holding 17 curl commands that upload one configuration file apiece to /hima_data/index.php, one line per staging host (See Figure 2 below). The paths are typed out by hand and cover FreePBX, Issabel, and Elastix layouts. The collector path echoes hima, a backdoor account the takeover script creates. The name goes back further: Check Point’s 2020 INJ3CTOR3 report shows a Telegram post by a user called Hima sharing a tool that scans and cracks SIP ranges, saving its output as HimaResults.

    Figure 2: k.php line 34, decoded into 17 file uploads
    Figure 2: k.php line 34, decoded into 17 file uploads

    Three of the cron beacons fetch and run k.php every minute (the others every two or three minutes), so the upload repeats every minute during the infection. Rotating credentials on a still-infected host hands the new secrets to the operator within minutes.

    What it unlocks Files uploaded Rotate
    SIP trunks and extensions (chan_sip) /etc/asterisk/sip.conf, sip_additional.conf, sip_registrations.conf, sip_general_additional.conf, sip_custom.conf Every trunk secret (with your carrier) and extension secret, changed in the FreePBX GUI, since the *_additional.conf files are regenerated
    SIP trunks and extensions (PJSIP) /etc/asterisk/pjsip.auth.conf, pjsip.endpoint.conf, pjsip.aor.conf, pjsip.identify.conf, pjsip.transports.conf The same secrets; review IP-based identity rules
    Call origination without SIP /etc/asterisk/manager.conf Every AMI user.
    PBX database, AMI, and platform admin /etc/freepbx.conf, /etc/amportal.conf, /etc/asterisk/amportal.conf, /etc/issabel.conf, /etc/elastix.conf The database password (AMPDBPASS), the MySQL root password, and any AMI password stored there
    Outbound mail /etc/postfix/sasl_passwd The SMTP relay account, with your mail provider

    This opens a second route to fraud. Our May report covered calls placed through the webshell, which require the shell to be alive and to land in the victim’s own call records. With a stolen trunk secret, the operator can register to the carrier from any machine and call as the victim, leaving nothing on the host, unless the carrier also restricts the trunk to the victim’s IP addresses. A successful disinfection stops the first route; only rotation stops the second.

    Detection

    • Network: outbound HTTP POSTs from a PBX to any /hima_data/ path or to either staging host. A PBX seldom needs outbound web access beyond vendor updates, so egress allow-listing closes this channel.
    • Carrier: alert on trunk registrations from outside your own IP ranges, and on premium or international destinations, off-hours calling, and unusual concurrency. Set spend caps and destination blocks where your carrier offers them.

    For Law Enforcement Agencies and CERTs

    By design, victims’ credentials were collected on the two staging hosts, which stopped responding in late September 2026. Going offline does not end exposure: hosting providers may still retain server data, and infected PBXs keep trying to upload their credentials every minute to addresses that could be reassigned to someone else.

    Both are reasons for law enforcement and national CERTs, which have the legal standing that researchers lack, to work with the providers on preserving that data and sinkholing the addresses, which would also identify victims for notification. We saw the uploads in code; we did not capture one in transit and hold no victim list.

    Two Staging Hosts, Split by Encoding

    An infected host now talks to both staging hosts, and which one depends on whether the command was written in plain text or base64. The /x takeover script is byte-identical on both.

    Reference Encoding Points to
    k.php line 2 (re-runs /x), eight cron schedules in /x, wr.php’s callback Plain text 160[.]119[.]69[.]4
    Camouflaged cron payloads, login-triggered stager Base64 45[.]95[.]147[.]178
    Credential upload Base64 Both

    In April, all of these pointed to 45[.]95[.]147[.]178. We assess that the operator replaced the address in plain text and never re-encoded the base64 strings; the credential upload, which names both hosts, appears deliberate. This host is distinct from the scanner 160[.]119[.]76[.]250, which is named in our May report.

    Defend: block both hosts in both directions, and decode every base64-encoded string in a crontab or shell profile before deciding which hosts a host talks to. A plain-text review would miss every channel that still reaches 45[.]95[.]147[.]178.

    The Webshell: Same Program, New Identifiers

    Decoded, the September JOMANGY panel is identical to April’s except for the values defenders were told to look for.

    Per-build watermark. Our May report advised hunting for trace_e1ebf9066a951be519a24140711839ea, present in every April copy. The September builds carry trace_bd42a8a0d23ae16c85dede7d2abaec05 (45[.]95[.]147[.]178) and trace_7544725ebaaadac217dfaa7ca8e8fe7e (160[.]119[.]69[.]4), so that hunt now misses current infections.

    One gate for two generations. JOMANGY and ZenharR share a single hardcoded MD5 gate hash, rotated together from a2f6863413c4192a4abfa360577b9961 to 8b3a1d970fda0c17a0b785a990fb7b6a. Our May report listed the April value under ZenharR only.

    A forged administrator session. Behind the gate, the FreePBX button builds an admin session using FreePBX’s own ampuser class and setAdmin(); in our lab, it opened the full console without any password. Therefore, changing the FreePBX admin password affects neither the gate nor this session. (See Figure 3 below)

    Figure 3: The panel's Freepbx and Elastix buttons forge an admin session without a password
    Figure 3: The panel’s Freepbx and Elastix buttons forge an admin session without a password

    Because each of these identifiers changes between builds, the detection approach later in this report focuses on who put a file on disk rather than on what the file contains.

    The .htaccess Door and the Access-Log Gap

    k.php writes a seven-line .htaccess to /var/www/html/admin/views/. It does not hide the webshell; it unblocks it, and it lets requests reach a copy without naming it.

    RewriteEngine On
    # enable symbolic links
    Options +FollowSymLinks
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-l
    RewriteRule ^\s+ config.php [L]
    Request path Status What answered
    /dir/zzz 404 Nothing
    /dir/%20zzz, /dir/%09zzz (space, tab, etc) 200 config.php
    /dir/+zzz 404 Nothing

    Simulating an operator and a victim in an isolated environment, we confirmed that a request to a URL containing an encoded space returned a working webshell for the attacker. The access log records only the requested path, never the file that answered, so searching logs for the webshell by its filename can return nothing on a host that is serving it.

    Defend: check every .htaccess across the web root for who put it there; one that no package, FreePBX module, or member of your team accounts for is suspect, whatever it contains. Because the takeover script wipes logs, treat log hunting as secondary: requests with %20, %09, or %0A directly after a slash that return 200 are worth a look where logs survive.

    What the FreePBX Console Won’t Show You

    FreePBX lists the trunks it created from its own database; Asterisk reads whatever is in its configuration files. In our lab, a trunk we wrote directly into /etc/asterisk/pjsip_custom.conf carried a call while the FreePBX Trunks page reported no records (See Figure 4 below). We did not see the campaign plant one, but its root-equivalent accounts and stolen trunk secrets give the operator everything needed to do so.

    Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console
    Figure 4: Our lab trunk, known to Asterisk and carrying calls, invisible in the FreePBX console

    Defend: audit from the Asterisk CLI (pjsip show endpoints, pjsip show registrations, sip show peers, sip show registry) and compare with what the console lists. Review the *_custom.conf files for trunks or contexts that nobody on your team added.

    What Keeps It There

    Before detecting or cleaning, it helps to see the whole apparatus. Everything in Figure 5 is read from /x and k.php: ways the implant stays on the box, and doors allowing the operator to come back, through a system account or a single web request. Each piece can rebuild/repair all others under a minute, which is why removing any one of them on its own fails. (See Figure 5 below)

    Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open
    Figure 5: Persistence channels that rebuild each other, and the backdoors they stay open

    Detecting It Without IOCs

    The operator rotates hashes, watermarks, gate values, and hosts between builds, so asking whether a file is known-bad quickly stops working. The better question is who put the file there: compare what is on disk with what the package manager or a clean install says it should be.

    On the host: triage with beagle.sh

    PBX admins can run beagle.sh, a report-only script that makes no changes to the host, to check a PBX server for signs of compromise. (See Figure 6 below)

    Check What it flags
    Packed shells Several identical, same-size PHP files across unrelated directories
    Locked files chattr +i or +a under the web root or in hidden directories
    Unowned .htaccess An .htaccess no installed package accounts for
    Self-rebuilding cron A cron line that downloads a file and hands it to a shell
    Accounts An extra UID-0 account, or a full-permission FreePBX admin, nobody created
    Blocklist Addresses dropped in and out by iptables outside fail2ban’s chains
    Figure 6: beagle.sh (Source: 0x1da5 GitHub)
    Figure 6: beagle.sh (Source: 0x1da5 GitHub)

    The script separated one infected server from one clean server of the same FreePBX version, a sample of one, so expect some legitimate findings. However, it cannot tell you whether the credentials have already been left: that happens during the first cron run, within a minute of infection, and long before anyone scans. The upload leaves no file behind, and the takeover script wipes what might have recorded it: the web server, Asterisk, cron and audit logs, plus shell and MySQL histories, which makes forensic timelines hard to reconstruct.

    With telemetry

    The most distinctive actions leave little on disk; in our detonation, backdoor accounts were created and deleted 27 seconds apart. These eleven behaviors are detection strategies to build into your own tooling:

    Layer Behavior What it catches
    Host crond spawns a shell that downloads a file and runs it The takeover script on its single run, before persistence and before credentials leave
    Host The web server account spawns a shell The webshell’s command box in use
    Host A cron child rewrites the crontab every minute without reading it first Beacon reinstallation
    Host chattr +i or touch -r on a file in the web root The lock and the borrowed timestamp
    Host Twelve PHP files were written to the web root in the same second The webshell copies, as they are written; fan-out
    Network The PBX contacts staging host roughly every 60 seconds The beacon’s rhythm, whatever the address
    Network Many configuration files read, then outbound POST requests Credentials leaving
    Web A request with leading encoded whitespace returns 200 for a path not on disk The .htaccess door
    Decoy Any read of a decoy config file that the implant reads, but nothing legitimate does Credential collection, with no false positives by design
    Phone Channels originate over AMI or the CLI outside your dial plan A call asking for nothing legitimate
    Phone CDRs with premium destinations, off-hours calling and unusual concurrency The fraud itself

    The last two catch the fraud rather than the machinery, whatever the files are called, and whether you ever find the shell. The host rows need process telemetry that PBX appliances rarely have, which is part of why so many stay infected.

    Why Cleanup Fails, and the Order That Works

    First move Why it fails on its own
    Delete the webshell Cron re-runs k.php within minutes and rewrites all 12 copies, the .htaccess, and the immutable flags.
    Patch FreePBX Sangoma’s advisory for CVE-2025-57819 states the fix prevents new exploitation but does not clean a compromised system.
    Change the admin password The gate and the forged session never use it, and the backdoor accounts bypass the FreePBX login.

    Shadowserver data showed more than 900 compromised FreePBX instances in February 2026; over 700 of them were still compromised in May. Rebuilding from a clean image is the most reliable fix; if you clean in place, work from the system layer up, because it replants everything above it.

    Preserve first

    The takeover script truncates logs, then deletes them, and clears shell and database history, so evidence shrinks with every run:

    1. Cut the host off from the internet, or at least block all outbound traffic except to your SIP carrier. Blocking only the two known staging hosts is not enough if the operator has moved. With no route out, the minute-by-minute downloads fail, and nothing more is uploaded. One local loop survives: a watchdog cron line re-runs the cached copy of k.php at /var/lib/asterisk/bin/zen2 every minute, rebuilding the webshells offline, which is why cron comes first in the cleanup below.
    2. Capture all crontabs and the eight backups listed below, /etc/passwd, /etc/shadow, shell profiles, and the web root with lsattr output and change times.
    3. Export the FreePBX ampusers table, the call records database, and the Asterisk full log, and ask your carrier to preserve CDRs and registration logs.

    Then clean, in this order

    1. Cron and its spares. Clear root’s crontab in one go, so the restore and watchdog lines are removed. Then kill any running zen2, devnull2, or serv processes; killed earlier, the watchdog restarts them within a minute. Remove the k.php beacons (/var/lib/asterisk/bin/zen2, devnull2, zen222, devnull312, devnull212, /tmp/.cache/update, /dev/shm/.systemd/kernel). Unlock (chattr -i, -a) and delete the eight crontab backups: /usr/lib/.systemd/.cache, /usr/share/.fonts/.config, /var/lib/.dbus/.data, /var/tmp/.X11/.Xauthority, /opt/.local/.bashrc, /var/cache/.fontconfig/.cfg, /etc/.ssl/.cert, and /root/.config/.pref.
    2. Login and boot triggers. Remove the base64 stager from /root/.bash_profile, /root/.bashrc, and /etc/rc.local.
    3. Accounts and SSH. Remove every extra UID-0 account and any account whose /etc/shadow hash begins with $1$nRz1Cbtk$ (legitimate service accounts with that hash need new passwords, not deletion). Restore sshd_config, where root login was re-enabled.
    4. Web application. Remove the 12 webshell copies, the .htaccess, the freepbxusers row in ampusers, and /var/www/html/admin/modules/freepbx_ha/license.php.
    5. Credentials. Only now rotate the secrets in the 17 files and across every account on the host.

    Conclusion

    The hard part of the campaign used to be getting the implant off the box, and that has not changed. What has changed is that the box is no longer the whole problem: an organization that rebuilds but does not rotate has removed the operator’s calling platform and handed over its carrier account.

    The code ties this generation to the actor in our May report through the takeover script, backdoor hash, and staging host, and a gate rotated in step across JOMANGY and ZenharR.

    The operator is now rotating exactly the strings defenders were given, so detections built on provenance and behavior will outlast this build, and detections built on its hashes will not. CRIL continues to monitor INJ3CTOR3’s infrastructure.

    Indicators of Compromise

    Hashes and strings rotate between builds; use them to confirm a finding, not as your only detection.

    Value Type Context
    45[.]95[.]147[.]178 IPv4 Staging host since April
    160[.]119[.]69[.]4 IPv4 Second staging host and credential collector, new
    hxxp://45[.]95[.]147[.]178/hima_data/index.php URL Credential upload endpoint
    hxxp://160[.]119[.]69[.]4/hima_data/index.php URL Credential upload endpoint
    c6e64453ea8bc0856333b6f57567c9efd8c440410787cae135d1c4a248c07c0d SHA256 /x takeover script, identical on both hosts
    38edbfc4ac89619d2bdb3f4bb2626deaaf422868d6d7af640f59d7959903f838 SHA256 k.php, 45[.]95[.]147[.]178
    1c14a761620691a43b1a554a9eccd38d21c15d59463945250d4f57b10d20fce9 SHA256 k.php, 160[.]119[.]69[.]4
    b54a8d9e98ff36dfe63b2aea97a2003b670f7311595bb4dd072850fed5900a0b SHA256 wr.php, 45[.]95[.]147[.]178
    aa6dfd7ee90d9aea5af29ae39c14ff70cf8687118abadd7aa4fc98923f01ffd1 SHA256 wr.php, 160[.]119[.]69[.]4
    adeb015fdb37814edc3ed45230f48d2b0e87bb195a5a7e4487c01549b47c744c SHA256 JOMANGY webshell on disk, 45[.]95[.]147[.]178 build
    d345671e688ee807e1bb9b6fc45e6bb0611bbb1331c33888c8030ec2db47e672 SHA256 JOMANGY webshell on disk, 160[.]119[.]69[.]4 build
    trace_bd42a8a0d23ae16c85dede7d2abaec05, trace_7544725ebaaadac217dfaa7ca8e8fe7e String JOMANGY watermarks, one per build
    8b3a1d970fda0c17a0b785a990fb7b6a MD5 Webshell gate hash, JOMANGY and ZenharR
    $1$nRz1Cbtk$ Hash prefix Password hash set on backdoor and service accounts

    MITRE ATT&CK® Techniques

    Mapped from the September /x and k.php to MITRE ATT&CK v20; the last three rows are new in this generation.

    Technique ID Tactic Name Evidence
    T1059.004 Execution Command and Scripting Interpreter: Unix Shell /x and k.php run as bash scripts fetched by cron
    T1105 Command and Control Ingress Tool Transfer wget of /x, k.php and wr.php from the staging hosts
    T1053.003 Persistence Scheduled Task/Job: Cron Minute-level beacons, a restore line and a watchdog
    T1505.003 Persistence Server Software Component: Web Shell JOMANGY and ZenharR, 12 copies across the web root
    T1546.004 Persistence Event Triggered Execution: Unix Shell Configuration Modification Stager added to /root/.bash_profile and /root/.bashrc
    T1037.004 Persistence Boot or Logon Initialization Scripts: RC Scripts Stager added to /etc/rc.local
    T1136.001 Persistence Create Account: Local Account Backdoor accounts, several at UID 0
    T1098 Persistence Account Manipulation Shared password hash set on existing accounts; FreePBX admin row inserted
    T1027 Stealth Obfuscated Files or Information base64, base64 and ROT13 layers around the webshell; base64 cron payloads
    T1564.001 Stealth Hide Artifacts: Hidden Files and Directories Crontab spares in dot-paths such as /var/tmp/.X11/.Xauthority
    T1070.006 Stealth Indicator Removal: Timestomp touch -r copies footer.php’s timestamp onto the webshell
    T1070.003 Stealth Indicator Removal: Clear Command History Shell and MySQL histories cleared
    T1222.002 Defense Impairment File and Directory Permissions Modification: Linux and Mac Permissions chattr +i and +a on webshells and crontab spares
    T1685.006 Defense Impairment Disable or Modify Tools: Clear Linux or Mac System Logs Web server, Asterisk, cron, secure and audit logs truncated, then deleted
    T1686 Defense Impairment Disable or Modify System Firewall iptables rules dropping rival actors’ addresses
    T1496 Impact Resource Hijacking Victim’s PBX and trunks used to place premium-rate calls
    T1552.001 Credential Access Unsecured Credentials: Credentials In Files k.php reads 17 Asterisk, FreePBX, Issabel, Elastix and Postfix configuration files holding secrets
    T1119 Collection Automated Collection The 17 files are collected by hardcoded commands on every k.php run
    T1041 Exfiltration Exfiltration Over C2 Channel Multipart HTTP POST of each file to /hima_data/index.php on both staging hosts

    References

    1. Cyble Research & Intelligence Labs. JOMANGY: INJ3CTOR3’s Self-Healing FreePBX Toll Fraud Campaign, 21 May 2026.
    2. Fortinet FortiGuard Labs. Unveiling the Weaponized Web Shell: encystPHP, 28 January 2026.
    3. Palo Alto Networks Unit 42. ZenharR webshell and CVE-2021-45461 FreePBX exploitation, 2022.
    4. SANS Internet Storm Center. ISC Diary #32892, 13 April 2026.
    5. watchTowr Labs. CVE-2025-57819: FreePBX Endpoint module pre-authentication SQL injection, 2025.
    6. FreePBX Security Advisory. GHSA-vm9p-46mv-5xvw: CVE-2025-64328.
    7. The Hacker News, reporting Shadowserver Foundation data. 900 Sangoma FreePBX instances compromised, February 2026.
    8. beagle.sh: github.com/0x1da5/malware-campaigns

    Source: Cyble Research · 2026-10-28

  • EMudhra Intermediate CA Certificates Compromised

    EMudhra Intermediate CA Certificates Compromised

    Eight compromised eMudhra intermediate CA private keys risk unauthorized TLS signing and MitM interception. Read our analysis and containment guide.

    Source: Palo Alto Networks Unit 42 · 2026-10-22

  • Spectator Loader Advertised as FUD Resident Loader With Anti-Analysis and Evasion Features

    Malware Service Report
    Loader
    Defense Evasion
    Anti-Analysis
    Unverified

    Spectator Loader Advertised as FUD Resident Loader With Anti-Analysis and Evasion Features

    ServiceSpectator Loader
    AV products referenced16
    Delivery optionsEXE / MSI / sideload
    ContactTox

    Spectator Loader Advertised as FUD Resident Loader With Anti-Analysis and Evasion Features

    An actor using the handle “Madrex” is advertising a malware service called Spectator Loader. The Russian-language post describes it as a private resident loader built for long-term persistence, resistance to blocking and evasion of modern security products.

    The advertisement claims the service can be delivered through sideloading or installer formats, uses custom obfuscation, anti-sandbox checks and low-level system-call techniques, and is designed to reduce static and behavioral detection. It also advertises remote-management capabilities such as system-information collection, in-memory payload execution, file transfer, process control, registry operations and filesystem management. These are actor claims from the advertisement and have not been independently validated.

    Post details

    ServiceSpectator Loader
    Actor“Madrex”
    Service typePrivate resident malware loader
    Primary marketing claimsPersistence, FUD, anti-analysis, blocking resistance
    Delivery methods advertisedSideloading, EXE, MSI and custom formats
    Security products referenced16 consumer AV products
    Contact methodTox
    Observed date

    What the post advertises

    • Private resident loader
    • Long-term persistence focus
    • FUD / low-detection positioning
    • Sideloading and installer delivery options
    • Custom metamorphic obfuscation
    • Anti-sandbox and anti-analysis checks
    • Claims resistance to static signatures
    • Claims reduced behavioral detection
    • Low-level syscall-based execution claims
    • Traffic imitation / trusted relay claims
    • System-information collection
    • In-memory payload execution
    • File download capability
    • Execution of multiple file/script formats
    • Registry manipulation
    • Process creation and termination
    • Filesystem management
    • Operator support advertised

    The post also claims its protection stack can detect sandboxes, reverse-engineering tools, hypervisors and virtual machines, and that builds are altered to reduce similarity between samples. These statements are summarized as service claims and are not reproduced as implementation guidance.

    Screenshots

    The supplied captures show the Spectator Loader advertisement, including FUD claims, antivirus and anti-analysis positioning, obfuscation and sandbox-evasion claims, network-resilience claims, remote-management features and a Tox contact identifier.

    IOCs & identifiers

    Identifiers directly visible in the supplied material. These support correlation and do not independently verify the advertised capabilities.

    Type Identifier Source
    Actor handle Madrex Screenshots 1–3
    Service name Spectator Loader Screenshots 1–3
    Tox ID 7EB9EF1A8CCCD4E02F87E0908BE745BE0F355D08B29CC1E74831AE80099A070BE4AD7E2E9B24 Screenshot 3

    No malware hash, Session ID, Telegram handle, attacker-controlled domain or attacker-controlled IP address is visible in the supplied screenshots.

    Mapped techniques

    Claimed identifies behavior explicitly advertised by the actor. Inferred identifies an analytical mapping supported by the supplied material. Neither label means the capability has been independently validated.

    • Defense Evasion
      T1027
      Obfuscated Files or Information
      Claimed
      The advertisement explicitly promotes custom obfuscation and build-to-build variation intended to reduce static detection.
    • Defense Evasion
      T1497
      Virtualization/Sandbox Evasion
      Claimed
      The post claims the loader can detect sandboxes, virtual machines, hypervisors and reverse-engineering environments.
    • Command and Control
      T1105
      Ingress Tool Transfer
      Inferred
      The advertised management feature set includes downloading files to the compromised host.

    Potential impact

    If the advertised capabilities are genuine, Spectator Loader could provide operators with a stealth-focused foothold that supports payload delivery, in-memory execution, file transfer, process control, registry modification and filesystem access. Its anti-analysis and evasion claims could also increase the time required for defenders to identify and investigate malicious activity.

    Status Unverified

    Dark Web Informer has not independently verified the loader’s detection-evasion claims, supported delivery methods, anti-sandbox behavior, network resilience or remote-management functionality. The supplied screenshots document the advertisement and visible contact information only.

    Dark Web Informer

    Source: Dark Web Informer · 2026-10-22

  • How APT41 revived the BlackLotus bootkit to attack diplomatic organizations in Central Asia

    How APT41 revived the BlackLotus bootkit to attack diplomatic organizations in Central Asia

    Introduction

    Back in October 2022, Kaspersky GReAT was looking into a peculiar advertisement on a hacking forum. A cybercriminal had been advertising a UEFI bootkit, dubbed BlackLotus, that could bypass Secure Boot, for $5,000. Given the low price for such powerful capabilities, the cybersecurity community initially took this advertisement with a grain of salt. As no BlackLotus samples were found in the wild, no one could at the time verify the claims made in the forum post.

    BlackLotus advertisement

    BlackLotus advertisement

    However, about half a year later, in March 2023, ESET confirmed that the BlackLotus advertisement was genuine. The researchers tracked down samples of this bootkit and confirmed that it can indeed bypass Secure Boot through a vulnerability called Baton Drop (CVE-2022-21894). As this vulnerability was still exploitable in 2023, Microsoft had to release multiple security updates to address it.

    Since the release of these updates, the BlackLotus bootkit has gone quiet — no publicly known attacks have used it. Yet in early 2026, we discovered a malware sample similar to BlackLotus that was used in an APT campaign in Central Asia. In this report, we share our findings, including new payloads and possible attribution of this campaign.

    The return of the infamous bootkit

    In early 2026 we identified a complex APT attack targeting diplomatic agencies in Central Asian countries — namely Tajikistan, Uzbekistan, and Turkmenistan. This attack involved a UEFI bootkit that we dubbed BlackX. Having examined it, we found it to be similar to BlackLotus.

    Attackers have been deploying BlackX after compromising the victim machine networks and obtaining administrator privileges. To install the bootkit, we observed them dropping the following files:

    • inst.exe, an installer executable
    • PVMDIJGKAX2, an RC4-encrypted extensionless file containing files and strings required for the installation

    The installer was launched with the command line C:\ProgramData\Intel\inst.exe PVMDIJGKAX2 Q46F6MDLI3RX2KV1. The last argument here is the RC4 key used for decryption.

    Curiously, the file inst.exe does not contain any malicious strings or embedded blobs. All the files needed to install the malicious payload are inside PVMDIJGKAX2, which makes it harder for incident responders to retrieve the bootkit components.

    The installer package drops a set of files to both system and UEFI partitions, designed to exploit the Baton Drop vulnerability. We noted that the implementation of the exploit is remarkably similar to the one used in the BlackLotus malware. As with BlackLotus, the goal of the exploit is to install custom Machine Owner Keys (MOK), which allows loading arbitrary EFI files on the target machines to manipulate Secure Boot.

    While the vulnerability exploitation chain was implemented very similarly to BlackLotus, we spotted differences between the exploits in BlackLotus and BlackX. That said, the source code of the BlackLotus bootkit has never been published online. This could mean that the attackers behind BlackX either reverse-engineered the BlackLotus bootkit or purchased its source code from cybercriminals. Either way, this is an interesting observation, as we rarely see APT actors borrow ideas or code from cybercrime actors.

    Payload launched by the bootkit

    The UEFI payload delivered during the Baton Drop exploitation has a classic bootkit goal — to inject a malicious driver into the Windows kernel. This driver differs from the one deployed by BlackLotus and is signed with a certificate belonging to an organization named 温江区明宇网络技术服务工作室 (English: Wenjiang District Mingyu Network Technology Service Studio). At the time of writing, this certificate (serial number: 0bcdf5e0da32d68900b8b7638459d072) has been revoked by its issuer.

    The driver aims to tamper with security solutions installed on the machine. For example, it disables process, thread, and registry callbacks related to security solutions. It also tampers with ETW providers so that security solutions cannot access their output. Curiously, some of the tampering procedures are designed to run only if Kaspersky or Avast solutions are installed on the infected machine. However, during dynamic analysis of this driver, we found that these procedures are useless — they fail to interfere with Kaspersky products in any way.

    The driver also protects the bootkit’s files from tampering. It intercepts kernel requests to open these files and returns a handle to calc.exe instead of a malicious file handle.

    User-mode second-stage payloads

    Apart from tampering with security solutions, the driver also deploys a user-mode payload. We observed two such payloads, used for cyberespionage, in the wild. One of them is a RAT that can load further-stage .NET payloads. This RAT uses cloud storage for C2 server communications — we observed its versions using Google Drive, OneDrive, and Yandex.Disk. Having connected to a cloud storage service, this RAT iterates over files available there and interprets them depending on the file suffix. Below is a list of supported suffixes:

    File suffix Description Type
    0X01 A .NET file. The task is to parse it and run the method TEST.Class1.RunCMD(argument_array) from the module Input
    0X02 Result of the call TEST.Class1.RunCMD(argument_array) Output
    0X03 Task to upload a file to the drive Input
    0X04 Uploaded file Output
    0X05 Task to download a file to an infected machine Input
    0X06 File download status Output
    SSSR Contains initial system info Output

    We also observed another payload delivered through the bootkit, which we dubbed OxiDLLRunner. It is a malicious DLL obfuscated with OLLVM. It is loaded by the legitimate file googleupdate.exe (original filename: jcef_helper.exe, MD5: AF8A983B9ADA07EAE1259BF2953ABD40), which is also delivered by the bootkit. The DLL decrypts the contents of the file v8_context_snapshot.bin, which resides in the same folder, and then jumps to the beginning of the decrypted content. The decrypted data starts with shellcode followed by a PE file, which is a Rust payload designed to communicate with the www[.]archivetj[.]com C2 server. During communication, this payload is supposed to receive DLL files exporting a function named create_plugin, which are then executed in separate threads.

    Attribution

    Based on the following facts, we have attributed this attack to the APT41 threat actor with medium confidence:

    • In June 2026, ESET published a blog post on attacks by the FishMonger threat actor, which the community assumes to be related to APT41. This post describes a kernel implant with a PDB path starting with C:\Users\xdd\Desktop. While describing the campaign, the post also suggests the possible use of an unspecified UEFI bootkit component, which might exploit CVE‑2023‑24932. We observed the identifier “xdd” used multiple times in the BlackX bootkit payloads, so we assess that BlackX is the UEFI bootkit referenced in the ESET blog post;
    • The payloads deployed by BlackX are loaded using a legitimate executable abused via DLL sideloading, and an encrypted file — this pattern is common among Chinese-speaking threat actors;
    • The OxiDLLRunner file has been obfuscated with OLLVM, an obfuscator commonly used by Chinese-speaking actors.

    Why did the target organizations get infected?

    During our initial analysis of BlackX, we thought that attackers succeeded in deploying it due to the negligence of the target organizations. Baton Drop, the vulnerability used to deploy BlackX, was disclosed back in 2023 and was patched, so we first thought that the infected machines lacked the relevant updates. However, our investigation proved this wrong — the targeted machines were fully patched.

    Instead, we found out that the problem was with the patch itself. As it turned out, the patch for the Baton Drop vulnerability is designed to revoke the “Windows Production PCA 2011” certificate used to sign vulnerable UEFI components. However, this revocation does not happen automatically upon patch installation — the user has to trigger it manually. This is done with the following steps:

    • A registry flag is set inside HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Secureboot;
    • A scheduled task named Secure-Boot-Update is created.

    This patch is designed to be applied manually — for instance, applying it automatically could break dual-boot systems relying on the “Windows Production PCA 2011” certificate to load. At the same time, this patch deployment practice creates a problem — as it is extremely unusual for a system administrator to take extra steps after installing an update. Usually, when applying patches, system administrators take no further action unless an installation failure occurs. These instructions for activating the patch are buried deep on the Microsoft website, and we assess that they are quite hard for an average IT administrator to notice.

    Curiously, Microsoft’s plan for deploying the Baton Drop patches mentions an “Enforcement Phase” that involves revoking the “Windows Production PCA 2011” certificate automatically, without user interaction. At the time of publishing this post, this stage has not been implemented. On October 19, 2026, this certificate expired, but this does not prevent the vulnerable binaries from loading unless the certificate is blocklisted.

    It is likely that the threat actor behind this campaign took into account that few organizations realized the importance of manually activating the Baton Drop patch. As such, we believe they decided to invest time in understanding how BlackLotus works and creating a copycat of this bootkit.

    Conclusion

    Patch management is important for every organization, as updates from vendors help protect software and hardware against known vulnerabilities. However, sometimes installed patches fail to protect against the flaws they address. The BlackLotus story we described is not the only such example — for instance, in 2025 Microsoft released an update against the ToolShell vulnerability that also had to be applied manually.

    However, modern security solutions are designed to account for such cases when installed patches fail to protect against security flaws for one reason or another. For instance, the Exploit Prevention component available in Kaspersky products prevents exploits from running if the patch is not applied, or if it is a zero-day vulnerability with no available patch. It is thus crucial to equip all machines in an organization with security solutions and constantly monitor the alerts they raise.

    Source: Securelist (Kaspersky GReAT) · 2026-10-22

  • Smashing Security podcast #489: How a brand new crypto wallet came with a spy inside

    Imagine buying a brand new hardware wallet for your cryptocurrency with the shrink-wrap still on… what could possibly be hiding inside? We break out a Geiger counter and a cat to find out.

    Meanwhile, malicious ads are targeting journalists with zero-click attacks.

    Plus, Origin’s Spencer Thompson reveals what AI agents are really getting up to on your employees’ laptops when nobody’s looking.

    All this and more in episode 489 of the “Smashing Security” podcast with cybersecurity expert and keynote speaker Graham Cluley, and special guest Lianne Potter.

    Source: Graham Cluley · 2026-10-21

  • “Next Exploit Opportunities”: How a Threat Actor Used AI to Help Plan and Execute Multiple Types of Cybercrime Activities

    “Next Exploit Opportunities”: How a Threat Actor Used AI to Help Plan and Execute Multiple Types of Cybercrime Activities

    An investigation into a threat actor bypassing AI safety controls to coordinate credential theft, VoIP fraud planning, and database exfiltration.

    Source: Palo Alto Networks Unit 42 · 2026-10-21

  • Police arrest Qilin ransomware suspect on holiday, as links made to Synnovis hack that contributed to patient’s death

    A 28-year-old Russian man has been arrested by German police, suspected of being a key member of the Qilin ransomware gang. Detectives have linked the man to the attack against blood-testing firm Synnovis, that disrupted London hospitals, and resulted in the death of a patient.

    Read more in my article on the Hot for Security blog.

    Source: Graham Cluley · 2026-10-20

  • Krybit ransomware: what you need to know

    Krybit is a fast-growing ransomware gang that was hacked by a rival, hit back, and is still extorting victims. Find out how it works, who it has targeted, and what organisations can do to protect themselves.

    Read more in my article on the Fortra blog.

    Source: Graham Cluley · 2026-10-16