Check Point Research has disclosed an active campaign, tracked since mid-2025, in which a Chinese-speaking cybercrime cluster dubbed Gambling Goblin is compromising web servers operated by Brazilian government agencies and educational institutions and installing malicious Apache modules — native .so binaries loaded directly into the httpd process — to silently divert visitors to attacker-controlled pages promoting online gambling and sports betting.
This is not a defacement. It is not a web shell dropped in /var/www/html. It is a persistent, in-process backdoor living inside the web server itself, which makes it significantly harder to detect with conventional file-integrity monitoring tuned to web content directories. The attackers monetize the trust and search-engine authority of .gov.br and .edu.br domains — domains that carry enormous SEO weight — by conditionally redirecting or rewriting traffic toward betting infrastructure. From the attacker's perspective, compromising a Brazilian federal portal is the equivalent of buying premium advertising real estate for free.
If you operate Apache anywhere in your environment — and statistically, you do — the defensive lesson generalizes well beyond Brazil: your web server process and its module load path are a persistence surface most organizations never audit. This post walks through how the technique works, how to hunt for it, and how to lock down Apache so a rogue module can't be loaded in the first place.
Technical Analysis
Threat actor and targeting
- Actor: Gambling Goblin (Check Point Research attribution), a Chinese-speaking cybercrime cluster motivated by gambling/betting affiliate revenue.
- Active since: at least mid-2025, per Check Point's tracking.
- Victimology: Brazilian government (
.gov.br) and educational (.edu.br) institutions running Apache on Linux. - Objective: traffic diversion to attacker-controlled gambling and sports betting pages — classic SEO poisoning / black-hat affiliate monetization, not espionage.
No CVE is associated with this campaign. The initial access vector is not a single software flaw — it is compromised administrative access to the server (stolen credentials, previously established webshells, or exploitation of whatever vulnerable stack the institution runs in front of Apache). The novelty is the persistence and traffic-hijacking mechanism, not the entry point.
How a malicious Apache module works — attack chain
- Initial access: attacker obtains root (or a user that can write to Apache's module directory and configuration, e.g. via
sudomisconfiguration) on the target server. - Module staging: a malicious shared object — conventionally named to blend in, e.g.
mod_security.so,mod_cache_hk.so,mod_pagespeed.soor similar look-alike names — is dropped into/usr/lib/apache2/modules/(Debian/Ubuntu),/etc/httpd/modules/or/usr/lib64/httpd/modules/(RHEL/CentOS/Rocky), or an arbitrary path referenced by config. - Persistence: a
LoadModuledirective is appended toapache2.conf,httpd.conf, or a file insidemods-enabled//conf.modules.d/. On the nextapachectl graceful/ reload — which attackers often trigger themselves to avoid waiting — the module is mapped into thehttpdprocess address space. - Traffic manipulation in-process: because the module runs inside Apache's request-processing hooks (
ap_hook_translate_name,ap_hook_handler, output filters), it can:- inspect the
User-AgentandRefererheaders and only redirect visitors arriving from search engines (so administrators browsing the site directly see nothing wrong); - issue 301/302 redirects or inject JavaScript/iframes pointing to gambling landing pages;
- serve cloaked content to crawlers (Googlebot) to poison search rankings for betting keywords;
- act as a full backdoor, proxying commands or fetching updated payloads over the same port 80/443 traffic that looks completely legitimate at the network layer.
- inspect the
- Evasion: because the malicious code executes within the legitimate
apache2/httpdprocess, EDR tooling sees no suspicious child process. Because redirection is conditional (referrer/user-agent/IP-geography based), casual inspection and uptime monitors see a healthy site. Because no web-root files change, file-integrity monitoring scoped to/var/wwwsees nothing.
Why this evades typical controls
| Control | Why it misses the technique |
|---|---|
Web-root FIM (/var/www) | Module lives in system library paths, not the docroot |
| Process-based EDR | Code runs inside trusted httpd; no new process spawned |
| Network IDS | Redirects ride inside normal HTTPS responses to real visitors |
| Uptime/external monitoring | Conditional cloaking shows clean pages to probes |
| Signature AV | Custom-compiled .so with no public signature |
Exploitation status
Confirmed active exploitation in the wild since at least mid-2025, against production government and education infrastructure. This is not theoretical. There is no CISA KEV entry because no CVE exists — the vulnerability is operational (weak server hygiene enabling root-level compromise), and the module is the payload.
Detection & Response
The highest-fidelity detection points are: (1) unauthorized LoadModule directives and module files not owned by the package manager, (2) apache2/httpd making unexpected outbound connections or reading unexpected files, and (3) conditional redirect behavior observable in access logs (redirects to gambling TLDs/domains, or 302s only for search-engine referrers).
Sigma Rules
---
title: Apache HTTP Server Spawning Shell or Unusual Child Process
id: 3f9c1a72-4b8e-4d2a-9c15-7e6f0a1b2c3d
status: experimental
description: Detects the Apache worker process spawning shells or interpreters, consistent with a malicious Apache module executing attacker commands in-process. Legitimate Apache workers should almost never exec shells on servers without CGI/PHP-FPM exec patterns.
references:
- https://thehackernews.com/2026/09/malicious-apache-modules-hijack.html
- https://attack.mitre.org/techniques/T1505/004/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.persistence
- attack.t1505.004
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith:
- '/apache2'
- '/httpd'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/zsh'
- '/python'
- '/python3'
- '/perl'
- '/curl'
- '/wget'
- '/nc'
- '/ncat'
condition: selection_parent and selection_child
falsepositives:
- Legacy CGI applications executing system commands
- mod_php applications calling exec()/shell_exec()
level: high
---
title: Suspicious Shared Object Written to Apache Module Directory
id: 8b2d4e61-1c3f-4a58-b7d9-2e4a6c8f0d1e
status: experimental
description: Detects file creation of shared objects in Apache module directories by processes other than the system package manager. Malicious Apache modules are staged as .so files in /etc/httpd/modules, /usr/lib64/httpd/modules, or /usr/lib/apache2/modules.
references:
- https://thehackernews.com/2026/09/malicious-apache-modules-hijack.html
- https://attack.mitre.org/techniques/T1505/004/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.persistence
- attack.t1505.004
logsource:
category: file_event
product: linux
detection:
selection_path:
TargetFilename|contains:
- '/etc/httpd/modules/'
- '/usr/lib64/httpd/modules/'
- '/usr/lib/apache2/modules/'
- '/usr/lib/httpd/modules/'
selection_ext:
TargetFilename|endswith: '.so'
filter_package_managers:
Image|endswith:
- '/dpkg'
- '/apt'
- '/apt-get'
- '/rpm'
- '/yum'
- '/dnf'
- '/unattended-upgrade'
condition: selection_path and selection_ext and not filter_package_managers
falsepositives:
- Administrators manually compiling and installing third-party Apache modules (e.g., mod_pagespeed builds)
level: high
---
title: LoadModule Directive Added to Apache Configuration
id: 5c7a9f13-6d24-4e8b-a3c7-9f1b2d4e6a80
status: experimental
description: Detects modification of Apache configuration files where LoadModule directives are defined, by editors or scripts outside expected configuration-management tooling. Gambling Goblin-style persistence requires registering the rogue module in httpd.conf, apache2.conf, conf.modules.d, or mods-enabled.
references:
- https://thehackernews.com/2026/09/malicious-apache-modules-hijack.html
- https://attack.mitre.org/techniques/T1554/
author: Security Arsenal
date: 2026/04/06
tags:
- attack.persistence
- attack.t1554
logsource:
category: file_event
product: linux
detection:
selection:
TargetFilename|contains:
- '/etc/apache2/apache2.conf'
- '/etc/apache2/mods-enabled/'
- '/etc/httpd/conf/httpd.conf'
- '/etc/httpd/conf.modules.d/'
- '/etc/apache2/conf-enabled/'
filter_mgmt:
Image|endswith:
- '/dpkg'
- '/apt'
- '/rpm'
- '/dnf'
- '/yum'
- '/ansible-playbook'
- '/ansible'
- '/puppet'
- '/chef-client'
condition: selection and not filter_mgmt
falsepositives:
- Administrators editing Apache config via vi/nano (tune with authorized admin accounts or a change-window allowlist)
level: medium
KQL — Microsoft Sentinel (Linux Syslog/CEF ingestion)
This hunt assumes your Linux web servers forward auditd/Sysmon-for-Linux or syslog process events into Sentinel. It looks for Apache spawning unexpected children, and for writes to module directories surfaced via auditd SYSCALL/PATH records forwarded through Syslog.
// Hunt: Apache worker spawning shells/interpreters or downloads (malicious module behavior)
let lookback = 14d;
Syslog
| where TimeGenerated > ago(lookback)
| where ProcessName in~ ("apache2", "httpd")
or SyslogMessage has_any ("apache2", "httpd")
| where SyslogMessage has_any ("/bin/sh", "/bin/bash", "python", "perl", "curl", "wget", "nc ")
| project TimeGenerated, Computer, ProcessName, SyslogMessage, HostIP
| order by TimeGenerated desc;
// Hunt: auditd records showing writes to Apache module/config paths by non-package tools
Syslog
| where TimeGenerated > ago(lookback)
| where SyslogMessage has_any ("/etc/httpd/modules", "/usr/lib64/httpd/modules", "/usr/lib/apache2/modules", "conf.modules.d", "mods-enabled")
| where SyslogMessage has_any ("open", "creat", "rename", "write") or ProcessName in~ ("cp", "scp", "rsync", "curl", "wget", "vi", "nano")
| where SyslogMessage !has_any ("dpkg", "apt", "rpm", "dnf", "yum")
| project TimeGenerated, Computer, ProcessName, SyslogMessage
| order by TimeGenerated desc;
// Hunt: HTTP redirects to gambling-themed external domains in proxy/WAF logs (CommonSecurityLog via CEF)
CommonSecurityLog
| where TimeGenerated > ago(lookback)
| where DeviceVendor in~ ("Apache", "Squid", "Zscaler", "Palo Alto Networks") or AdditionalExtensions has "Referer"
| where DestinationHostName has_any ("bet", "casino", "slot", "gambl", "aposta", "jogos") // includes Portuguese 'aposta' (bet)
and RequestMethod == "GET"
| summarize Hits = count(), SrcHosts = dcount(SourceHostName) by DestinationHostName, RequestURL, bin(TimeGenerated, 1h)
| order by Hits desc;
Velociraptor VQL
-- Hunt for rogue Apache modules: enumerate .so files in module dirs,
-- flag those NOT owned by the package manager, plus unexpected LoadModule lines.
-- Deploy as a client artifact across Linux web servers (via Linux.Sys or custom collection).
LET module_dirs = ("/etc/httpd/modules/", "/usr/lib64/httpd/modules/", "/usr/lib/apache2/modules/", "/usr/lib/httpd/modules/")
LET rogue_modules = SELECT FullPath, Mtime, Size,
shell(argv=["bash", "-c", format(format="rpm -qf %s 2>/dev/null || dpkg -S %s 2>/dev/null || echo NOT_PACKAGE_OWNED", args=FullPath, args=FullPath)]).Stdout AS PackageOwner
FROM glob(globs=module_dirs + "*.so")
WHERE PackageOwner =~ "NOT_PACKAGE_OWNED"
OR Mtime > now() - 90 * 24 * 3600 -- recently modified modules
LET suspicious_loadmodule = SELECT FullPath, Line,
parse_records_with_regex(regex="^LoadModule\\s+(?P<Module>\\S+)\\s+(?P<Path>\\S+)", buffer=Line).Path AS ModulePath
FROM parse_lines(filename=glob(globs=(
"/etc/apache2/apache2.conf",
"/etc/apache2/mods-enabled/*.load",
"/etc/httpd/conf/httpd.conf",
"/etc/httpd/conf.modules.d/*.conf")))
WHERE Line =~ "^LoadModule"
AND NOT Line =~ "mod_(access_compat|alias|auth|autoindex|cgi|deflate|dir|env|expires|filter|headers|http2|log_config|mime|negotiation|proxy|reqtimeout|rewrite|setenvif|socache|ssl|status|unixd|version|mpm_prefork|php)"
SELECT * FROM rogue_modules
UNION ALL
SELECT FullPath, NULL AS Mtime, NULL AS Size, suspicious_loadmodule.Line AS PackageOwner, NULL AS Line, NULL AS ModulePath
FROM suspicious_loadmodule
(Adapt the final UNION shape to your deployment — the core hunts are the two LET queries: unowned/recent .so files, and non-standard LoadModule directives.)
Remediation & Audit Script (Bash)
Run on every Apache host. It inventories loaded modules, verifies package ownership of every .so, and diffs LoadModule directives against a known-good baseline.
#!/bin/bash
# Gambling Goblin-style rogue Apache module audit
# Run as root. Safe: read-only checks, no changes made.
echo "=== [1] Modules currently loaded in Apache ==="
apachectl -M 2>/dev/null | sort | tee /tmp/loaded_modules.txt
echo; echo "=== [2] Verify every .so in module dirs is owned by the package manager ==="
MODDIRS="/usr/lib64/httpd/modules /usr/lib/apache2/modules /etc/httpd/modules"
for d in $MODDIRS; do
[ -d "$d" ] || continue
for so in "$d"/*.so; do
[ -e "$so" ] || continue
if command -v rpm >/dev/null 2>&1; then
owner=$(rpm -qf "$so" 2>/dev/null)
else
owner=$(dpkg -S "$so" 2>/dev/null)
fi
if [ -z "$owner" ] || echo "$owner" | grep -qi "no path\|not owned"; then
echo "SUSPICIOUS (not package-owned): $so"
sha256sum "$so"
stat -c ' mtime: %y | uid: %U' "$so"
fi
done
done
echo; echo "=== [3] All LoadModule directives (diff against your CM baseline) ==="
grep -rEi '^\s*LoadModule' /etc/apache2 /etc/httpd 2>/dev/null
echo; echo "=== [4] Recently modified files in Apache config/module paths (last 30 days) ==="
find /etc/apache2 /etc/httpd /usr/lib64/httpd/modules /usr/lib/apache2/modules \
-type f -mtime -30 2>/dev/null -exec ls -la {} \;
echo; echo "=== [5] Apache processes with open outbound sockets ==="
for pid in $(pgrep -x apache2; pgrep -x httpd); do
ss -tanp 2>/dev/null | grep "pid=$pid" | grep -v ':80 \|:443 '
done | sort -u
echo; echo "=== [6] Search access logs for redirect responses to gambling terms (pt/en) ==="
grep -rEi ' 30[1278] ' /var/log/apache2/ /var/log/httpd/ 2>/dev/null | \
grep -Ei 'bet|casino|slot|aposta|jogos|gambl' | tail -50
echo; echo "Done. Investigate any SUSPICIOUS .so, unknown LoadModule, or gambling redirects immediately."
Remediation
If a rogue module is confirmed on a host, treat it as a full root-level compromise — the attacker had the privileges needed to write module files and edit Apache config. Do not just delete the .so.
- Isolate and image first. Take the server off the load balancer/network, capture memory and a disk image before remediation. The module binary is the key forensic artifact — preserve it and its
LoadModuleline, timestamps, and any config edits (stat,aide/tripwireoutput, auditd logs). - Identify initial access. The module is persistence, not entry. Review auth logs (
/var/log/auth.log,secure,lastlog), webshells in the docroot, cron jobs, and any internet-facing CMS/app stack in front of Apache. Without closing the entry point, the module returns. - Rebuild, don't clean. The authoritative remediation for a root-compromised web server is re-image from known-good media and redeploy config from configuration management. Rotate all credentials that ever touched the host (SSH keys, sudo users, app/service accounts, API keys, TLS private keys).
- Establish a module baseline. There is no vendor patch for this — the fix is operational. Maintain a signed allowlist of legitimate
LoadModuledirectives and module.sohashes in your CM tool (Ansible/Puppet). Alert on any deviation. Verify every module file is owned by a system package (rpm -qf/dpkg -S). - Harden Apache's module surface:
- Mount
/etc/httpd/modules//usr/lib*/apache2/moduleswith least-privilege ownership (root-only write) and considerchattr +ior immutable infrastructure for module directories. - Disable unused modules aggressively (
a2dismod) — a smaller module set means a smaller cloaking surface and an easier allowlist. - Run
apachectl -Moutput andmod_ratelimit/mod_security-style checks into your SIEM on a schedule; diff against baseline. - Deploy file-integrity monitoring (AIDE, Tripwire, Wazuh FIM) explicitly covering Apache config and module paths — not just the web root.
- Set
ServerTokens Prod/ minimal disclosure, keep Apache current via your distro channel, and restrict who can triggergraceful/reloads.
- Mount
- Detect the cloaking behavior externally. Periodically crawl your own sites with Googlebot/Bingbot user-agents and search-engine referrers from off-network vantage points, and alert on any 3xx to external domains or injected scripts. Monitor certificate-transparency and DNS for look-alike betting domains referencing your hostnames.
- Reference: Check Point Research's Gambling Goblin write-up via the source article: https://thehackernews.com/2026/09/malicious-apache-modules-hijack.html. MITRE mapping: T1505.004 (Server Software Component: IIS/Apache Modules), T1554 (Compromise Host Software Binary), T1027 (conditional execution/cloaking).
The strategic takeaway for CISOs: this campaign monetizes exactly the domains governments assume are trusted by default. Web server integrity — process, modules, and configuration — belongs in your critical-asset monitoring scope alongside endpoints and identity.
Related Resources
Security Arsenal Managed SOC Services AlertMonitor Platform Book a SOC Assessment soc-mdr Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.