Joomla iCagenda & Balbooa Forms — Unauthenticated File-Upload RCE
Executive Summary
Two Joomla extensions carry unauthenticated arbitrary-file-upload flaws being exploited as zero-days. CVE-2026-48939 (CVSS 10.0) in the iCagenda events extension lets an attacker upload arbitrary files — including PHP — through the public "Submit an Event" form's attachment feature; automated scanners identifying as icagenda-batch/1.0 retrieve the resulting shells from images/icagenda/frontend/attachments/. CVE-2026-56291 (CVSS 10.0) in Balbooa Forms allows unauthenticated file upload with no login and no type validation, placing PHP files in images/baforms/uploads/ for remote code execution. CISA added both to the KEV catalog on 2026-07-10.
Both bugs collapse the attack chain: an unauthenticated web request drops a PHP webshell into a browsable directory; a follow-up request executes it with the web-server's privileges. From there the actor runs OS commands, pulls second-stage tooling, adds Joomla super-users, and pivots. Because the initial upload is an HTTP request the endpoint sensor never sees the payload — but the moment the webshell executes a command, the web-server process spawns a child shell, and that is the highest-fidelity Falcon signal in this pack.
Affected: iCagenda 4.x ≤ 4.0.7 and 3.x 3.2.1–3.9.15 (fixed 4.0.8 / 3.9.15); Balbooa Forms ≤ 2.4.0 (fixed 2.4.1). No public atomic IOCs (attacker IPs, shell hashes) were released beyond the scanner user-agent and the two upload paths, so the atomic IOC blocks ship as placeholders.
Defender priority: On any Joomla host running these extensions, hunt web-server processes (httpd/apache2/php-fpm/nginx/w3wp) spawning shells or LOLBins (Q1) and newly written .php files under the two upload directories (Q2) — those two catch the webshell before the actor establishes deeper persistence. Patch, then sweep the upload dirs for planted shells and audit for rogue super-user accounts.
Source Review & Web Hunter Notes
| Tier | Source | Key Finding | Carry Fwd |
|---|---|---|---|
| 1 | CISA KEV catalog (added 2026-07-10) | CVE-2026-48939 (iCagenda) & CVE-2026-56291 (Balbooa Forms) added as exploited | yes |
| 2 | The Hacker News (2026-07-13) | Both flaws exploited as zero-days; iCagenda zero-day since 2026-06-15; Balbooa discovered 2026-07-08 after active compromise | yes |
| 2 | THN / vendor advisory detail | Scanner UA icagenda-batch/1.0; shells under images/icagenda/frontend/attachments/ and images/baforms/uploads/ | yes |
| 2 | iCagenda / Balbooa vendor patch notes | Fixed: iCagenda 4.0.8 & 3.9.15; Balbooa Forms 2.4.1 | yes |
Intel gap: Beyond the scanner user-agent and the two upload paths, no attacker IPs or webshell hashes were published. Detection is behavior-led (web-server process lineage + upload-dir writes); enrich atomic IOCs from your own web logs and quarantined shells.
Hunt Brief & Attack Chain
Attack chain
| # | Step | Telemetry | Hunt Angle |
|---|---|---|---|
| 1 | Unauth POST uploads a PHP file (iCagenda Submit-an-Event / Balbooa upload) | Web-server access logs (off-endpoint payload) | Native hunt §7 — POST to upload endpoints, icagenda-batch/1.0 UA |
| 2 | PHP webshell written to a browsable upload dir | TargetFileName file-write | Q2 — .php/.phtml written under images/icagenda|baforms |
| 3 | Attacker requests shell → PHP executes a command | ProcessRollup2 | Q1 — web-server process spawns shell/LOLBin |
| 4 | Reconnaissance via webshell | ProcessRollup2 | Q3 — recon children of web-server process |
| 5 | Ingress tool transfer | ProcessRollup2 | Q4 — curl/wget/certutil children of web server |
| 6 | Reverse shell / tunneling | ProcessRollup2 | Q5 — nc/socat/bash-i/python-socket from web server |
| 7 | Persistence: cron / task / new Joomla super-user | ProcessRollup2, DB/native | Q6 — cron/systemd/schtasks child; §7 super-user audit |
| 8 | C2 / exfil from the web host | NetworkConnectIP4 | Q7 — outbound from php/httpd process |
Hypotheses (fidelity-ordered)
- H1 (high): A web-server process spawns an interactive shell or LOLBin — a webshell executing commands.
- H2 (high): A .php/.phtml file is written under the iCagenda or Balbooa upload directory.
- H3 (medium): Recon utilities run with a web-server parent.
- H4 (medium): A downloader runs with a web-server parent (second-stage pull).
- H5 (high): A reverse-shell/tunnel binary or one-liner runs from the web-server process.
- H6 (medium): A web-server child creates cron/systemd/scheduled-task persistence.
- H7 (low): The web-server process makes an outbound connection to a rare external host.
Consolidated IOC Table
| Type | Value | Confidence | Action | Context |
|---|---|---|---|---|
| CVE | CVE-2026-48939 | high | patch | iCagenda unauth arbitrary file upload, CVSS 10.0 |
| CVE | CVE-2026-56291 | high | patch | Balbooa Forms unauth file upload, CVSS 10.0 |
| user-agent | icagenda-batch/1.0 | high | hunt | Automated exploit/retrieval scanner UA |
| path | images/icagenda/frontend/attachments/ | high | hunt | iCagenda shell drop directory |
| path | images/baforms/uploads/ | high | hunt | Balbooa Forms shell drop directory |
| fixed version | iCagenda 4.0.8 / 3.9.15 · Balbooa 2.4.1 | high | enrich | Anything below is vulnerable |
| ip / hash | REPLACE_WITH_WEBLOG_IOC | medium | detect | Populate from web logs / quarantined shell |
Affected Surface & Telemetry Matrix
| Surface | Required Telemetry | Priority | Gap Risk |
|---|---|---|---|
| Joomla web servers with iCagenda / Balbooa Forms | ProcessRollup2 (process lineage) | Critical | Low — if Falcon on the web host |
| Web-root file writes | TargetFileName file-write events | Critical | Medium — needs file-write visibility on the host |
| Web-server egress | NetworkConnectIP4 | High | Low |
| HTTP upload requests | Web-server access logs / WAF | High | High — off-endpoint; needs log pipeline |
ATT&CK Mapping
| Tactic | Technique | Observed Behavior | Query / Control |
|---|---|---|---|
| Initial Access | T1190 Exploit Public-Facing Application | Unauth file upload on Joomla extension | Patch · §7 |
| Persistence | T1505.003 Web Shell | PHP shell in upload directory | Q2 |
| Execution | T1059 Command & Scripting Interpreter | Web-server process spawns shell | Q1 |
| Discovery | T1083 / T1087 / T1082 | Recon children of web server | Q3 |
| Command & Control | T1105 Ingress Tool Transfer | Downloader children of web server | Q4 |
| Command & Control | T1071 / T1571 | Reverse shell / outbound from web host | Q5 · Q7 |
| Persistence | T1053.003 Cron · T1136 Create Account | Cron/task persistence; rogue Joomla super-user | Q6 · §7 |
Native Audit-Log Hunts (non-CQL)
- Web access logs: search for the
icagenda-batch/1.0user-agent and for POST requests to the iCagenda Submit-an-Event and Balbooa Forms upload endpoints, especially from single scanning IPs hitting many hosts. - Upload-directory sweep: list non-document files (especially
.php,.phtml,.phar) underimages/icagenda/frontend/attachments/andimages/baforms/uploads/; any script there is suspect. - Recently-modified PHP: enumerate
.phpfiles across the webroot modified after 2026-06-15 (iCagenda zero-day start) and correlate with deploy history. - Joomla super-user audit: review the Joomla
#__users/ user-group tables for unexpected Super Users or accounts created during the exposure window. - Extension version audit: confirm iCagenda ≥ 4.0.8 / 3.9.15 and Balbooa Forms ≥ 2.4.1 on every Joomla site.
CrowdStrike LogScale CQL Hunt Queries
These assume Falcon is deployed on the Joomla web server (Linux or Windows/IIS). Start with Q1 and Q2 — highest fidelity for webshell activity.
Looks for: httpd/apache2/php-fpm/nginx/w3wp spawning an interactive shell or recon/download LOLBin — the webshell running commands. Highest-fidelity signal in the pack. FP: some PHP apps legitimately shell out (imagemagick, backups) — baseline per host and exclude known helper commands.
// HUNT: web-server process spawning a shell/LOLBin (webshell execution) // MITRE: T1059, T1505.003 | CONF: high FP: low COST: low | REQUIRES: ProcessRollup2 // FALSE POSITIVES: PHP apps invoking convert/backup helpers // TUNING: exclude known helper FileName per host baseline #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^(httpd|apache2|php-fpm[0-9.]*|php|nginx|w3wp|caddy|litespeed)(\.exe)?$/i | FileName=/^(sh|bash|dash|zsh|cmd|powershell|pwsh|whoami|id|uname|python[0-9.]*|perl|curl|wget|nc|ncat|socat)(\.exe)?$/i | table([ComputerName, aid, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Looks for: a script file (.php/.phtml/.phar) written under the iCagenda or Balbooa upload paths — the webshell being planted. FP: legitimate extension updates can write files to images subfolders — a script extension in an uploads/attachments folder is not legitimate. Requires file-write telemetry on the host.
// HUNT: PHP webshell written to iCagenda/Balbooa upload directory // MITRE: T1505.003 | CONF: high FP: med COST: low | REQUIRES: file-write telemetry (TargetFileName) // FALSE POSITIVES: extension update writing to images/ — but never a script in uploads/attachments // TUNING: keep only .php/.phtml/.phar extensions; scope to the two known dirs #event_simpleName=/PeFileWritten|NewExecutableWritten|FileCreateInfo/ | TargetFileName=/(icagenda.{0,40}attachments|baforms.{0,20}uploads).{0,60}\.(php|phtml|phar|php5|php7)/i | table([ComputerName, aid, UserName, TargetFileName, ContextBaseFileName], limit=200)
Looks for: host/user/network discovery utilities whose parent is a web-server process — hands-on-keyboard recon through the shell. FP: monitoring agents occasionally spawn these — exclude known monitoring parents/accounts.
// HUNT: discovery utilities parented by a web-server process // MITRE: T1083, T1087, T1082, T1016 | CONF: med FP: med COST: low | REQUIRES: ProcessRollup2 // FALSE POSITIVES: monitoring/inventory agents // TUNING: exclude monitoring service accounts and known agent parents #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^(httpd|apache2|php-fpm[0-9.]*|php|nginx|w3wp|litespeed)(\.exe)?$/i | FileName=/^(whoami|id|uname|hostname|net1?|systeminfo|ipconfig|ifconfig|arp|cat|ls|dir)(\.exe)?$/i | table([ComputerName, aid, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Looks for: curl/wget/certutil/python fetching a second stage, parented by the web server. FP: some apps fetch remote resources — require an external URL and correlate with Q1/Q2.
// HUNT: ingress tool transfer parented by a web-server process // MITRE: T1105 | CONF: high FP: med COST: low | REQUIRES: ProcessRollup2 // FALSE POSITIVES: apps legitimately fetching remote assets // TUNING: require external URL in CommandLine; exclude package-manager parents #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^(httpd|apache2|php-fpm[0-9.]*|php|nginx|w3wp|litespeed)(\.exe)?$/i | CommandLine=/(curl\s.{0,40}http|wget\s.{0,40}http|certutil.{0,30}urlcache|Invoke-WebRequest|DownloadString)/i | table([ComputerName, aid, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Looks for: reverse-shell one-liners and tunnel binaries (nc/ncat/socat, bash -i, python socket, ngrok/chisel) run on the web host — attacker upgrading the webshell to interactive access.
// HUNT: reverse shell / tunneling from the web host // MITRE: T1059, T1572, T1071 | CONF: high FP: low COST: low | REQUIRES: ProcessRollup2 // FALSE POSITIVES: sanctioned admin tunnels — confirm operator + change record #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | CommandLine=/(bash\s+-i|sh\s+-i|nc\s.{0,20}-e|ncat\s.{0,20}-e|socat\s.{0,30}exec|python[0-9.]*\s.{0,60}socket|ngrok|chisel|frpc)/i | table([ComputerName, aid, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Looks for: crontab/systemctl/schtasks/at run by a web-server process — persistence installed via the webshell. FP: deployment tooling can install cron/services — exclude known deploy accounts and RMM parents.
// HUNT: cron/task persistence installed via a web-server process // MITRE: T1053.003, T1053.005, T1543 | CONF: med FP: med COST: low | REQUIRES: ProcessRollup2 // FALSE POSITIVES: CI/CD or config-management deployment // TUNING: exclude deployment/config-management accounts and parents #event_simpleName=/ProcessRollup2|SyntheticProcessRollup2/ | ParentBaseFileName=/^(httpd|apache2|php-fpm[0-9.]*|php|nginx|w3wp|litespeed)(\.exe)?$/i | FileName=/^(crontab|systemctl|schtasks|at|systemd-run)(\.exe)?$/i | table([ComputerName, aid, UserName, FileName, ParentBaseFileName, CommandLine], limit=200)
Looks for: the web-server process itself connecting outbound — reverse-shell egress or C2. FP: web apps make legitimate outbound API/update calls — treat as a pivot, rank by rare destination, never alert alone.
// HUNT: outbound connection sourced from a web-server process // MITRE: T1071, T1571 | CONF: med FP: high COST: med | REQUIRES: NetworkConnectIP4 // FALSE POSITIVES: legitimate outbound API/update calls // TUNING: allowlist known API/update destinations; focus on rare RemoteAddressIP4 #event_simpleName=/NetworkConnectIP4/ | ConnectionDirection="0" | ContextBaseFileName=/^(httpd|apache2|php-fpm[0-9.]*|php|nginx|w3wp|litespeed)(\.exe)?$/i | groupBy([RemoteAddressIP4, RemotePort, ContextBaseFileName], function=count(field=ComputerName, as=hosts, distinct=true)) | table([RemoteAddressIP4, RemotePort, ContextBaseFileName, hosts], limit=200)
CrowdStrike Custom IOA Recommendations
| IOA Name | Pattern | Exclusions | Deployment |
|---|---|---|---|
| Web server spawns interactive shell | Parent httpd/apache2/php-fpm/nginx/w3wp → child sh/bash/cmd/powershell | Per-host known helper commands | Promote Q1 — Detect on web tier, Prevent after baseline |
| Reverse shell from web host | CommandLine matches bash -i / nc -e / socat exec / python socket | Sanctioned admin tunnels | Promote Q5 — high fidelity |
| PHP in upload directory | Script write under icagenda attachments / baforms uploads | None — always suspicious | Promote Q2 where file-write telemetry exists |
Q3, Q4, Q6, Q7 stay investigate-only hunt/scheduled searches pending per-environment tuning.
Machine-Readable IOC Appendix
Only the scanner UA and upload paths are vendor-published; atomic network/hash IOCs ship as placeholders to fill from your web logs and quarantined shells.
type,value,action,severity,expiration,description,tags ipv4,REPLACE_WITH_SCANNER_IP,detect,high,2026-10-15,Joomla upload exploit source,campaign:Joomla-Upload-RCE sha256,REPLACE_WITH_WEBSHELL_SHA256,prevent,critical,2027-01-15,Joomla PHP webshell,campaign:Joomla-Upload-RCE domain,REPLACE_WITH_C2,detect,high,2026-10-15,Joomla webshell C2,campaign:Joomla-Upload-RCE
- Web-server process spawns shell/LOLBin (Q1) - .php/.phtml written under icagenda attachments or baforms uploads (Q2) - Recon/downloader children of httpd/php-fpm (Q3/Q4) - Reverse-shell one-liner from web host (Q5) - UA icagenda-batch/1.0 in web access logs (native §7)
CVE-2026-48939 iCagenda unauth file upload CVSS 10.0 CVE-2026-56291 Balbooa Forms unauth file upload CVSS 10.0 user-agent: icagenda-batch/1.0 paths: images/icagenda/frontend/attachments/ , images/baforms/uploads/ Fixed: iCagenda 4.0.8 & 3.9.15 ; Balbooa Forms 2.4.1
[ ] Inventory Joomla sites; confirm iCagenda >= 4.0.8/3.9.15, Balbooa >= 2.4.1 [ ] Sweep images/icagenda/frontend/attachments/ + images/baforms/uploads/ for scripts [ ] Find .php modified after 2026-06-15 across webroot [ ] Audit Joomla Super Users for rogue accounts [ ] Disable PHP execution in upload directories [ ] Rotate Joomla secret, admin + DB credentials
Detection Validation Gates
| Gate | Check | Pass Criteria |
|---|---|---|
| Telemetry ready | ProcessRollup2 + file-write + NetworkConnectIP4 reporting from web hosts | All returning in last 24h |
| Benign baseline | Run Q1 over 7 days pre-incident | Legit web-server child commands catalogued & excluded |
| Positive test | In a lab, drop a benign PHP that runs id; request it | Q1 and Q2 fire |
| File-write visibility | Confirm the host emits file-write events for script files | Q2 usable; else rely on §7 sweep |
| Promotion | Q1, Q2, Q5 tuned FP-clean for 1 week | Promote to Custom IOA per §9 |
Hardening — Tiered & Deployable
- Patch the extensions: iCagenda 4.0.8 / 3.9.15, Balbooa Forms 2.4.1. M1051 Update Software (vendor patch notes).
- Sweep & remove planted shells from the two upload directories; audit for rogue Joomla Super Users. M1018 User Account Management.
- Disable PHP execution in upload directories (web-server config) so a dropped shell cannot run. M1038 Execution Prevention.
- Store uploads outside the webroot or on a non-executable mount; enforce server-side content-type + extension allowlists. M1038
- Deploy a WAF rule blocking script uploads / requests to the vulnerable endpoints (virtual patch). M1050 Exploit Protection.
- Least-privilege web-server user + file-integrity monitoring on the webroot. M1026 Privileged Account Management.
- MFA on Joomla admin; alert on new Super User creation. M1032 Multi-factor Authentication.
- Joomla extension inventory + patch SLA; subscribe to VEL (Vulnerable Extensions List). M1051
- Segment public web servers into a restricted DMZ with tight egress filtering. M1030 Network Segmentation.
- Ensure Falcon on all internet-facing web servers and centralize web logs to the SIEM. M1047 Audit.
Deployable Playbooks
1 · Deny PHP execution in Joomla upload dirs (Apache)
# Drop into an .htaccess in each upload directory (or a <Directory> block)
<FilesMatch "\.(php|phtml|phar|php[0-9])$">
Require all denied
</FilesMatch>
php_admin_flag engine off
2 · Deny PHP execution in upload dirs (nginx)
# In the server block, above the generic PHP location
location ~* /images/(icagenda|baforms)/.*\.(php|phtml|phar)$ {
deny all;
return 403;
}
3 · auditd rule — watch the upload directories for writes (Linux)
# Alert on any file write into the two exploited upload paths -w /var/www/images/icagenda/frontend/attachments/ -p wa -k joomla_upload -w /var/www/images/baforms/uploads/ -p wa -k joomla_upload
4 · Post-hardening CQL spot-check
# Re-run Q1 after disabling PHP execution — a re-requested shell should no # longer spawn a child process. Any hit = the control is not effective; escalate.
Containment Runbook
| Phase | Actions | Owner | Evidence |
|---|---|---|---|
| Isolate | Network-contain the web host if Q1/Q2/Q5 fired; take the site to maintenance mode; block the scanner IP at the WAF | SOC / Web | Falcon containment log, WAF block, Q1/Q2 hits |
| Eradicate | Remove planted shells; patch iCagenda/Balbooa; delete rogue Super Users; rotate Joomla secret, admin, and DB credentials; remove cron/task persistence found by Q6 | Web / IR | Quarantined shell hashes, patch record, account-deletion log |
| Recover | Restore from a known-clean backup if integrity is uncertain; re-enable with PHP execution disabled in upload dirs + WAF virtual patch; monitor Q1/Q2 for 30 days | Web / SOC | Backup validation, 30-day monitoring dashboard |
Detection Coverage Map
| Technique | Behavior | CQL | IOA | Coverage |
|---|---|---|---|---|
| T1190 Exploit Public-Facing App | Unauth upload HTTP request | — | — | GAP — off-endpoint; §7 web logs + patch |
| T1505.003 Web Shell (write) | PHP dropped in upload dir | Q2 | Yes | Partial — needs file-write telemetry |
| T1059 Execution | Web server spawns shell | Q1 | Yes | Good |
| T1083/T1087/T1082 Discovery | Recon via webshell | Q3 | — | Partial |
| T1105 Ingress tool transfer | Downloader child | Q4 | — | Partial |
| T1059/T1572 Reverse shell | nc/socat/bash-i/python | Q5 | Yes | Good |
| T1053.003/T1136 Persistence | Cron/task; rogue super-user | Q6 | — | Partial — account creation via §7 |
| T1071/T1571 C2 | Outbound from web process | Q7 | — | Weak — high FP, pivot only |
Validation: the upload request itself is off-endpoint (cover via web logs / WAF, §7). Falcon coverage is strongest at execution — Q1 and Q5 are the reliable catches; Q2 depends on the host emitting script file-write events, so pair it with the §7 upload-dir sweep.
Hunt Summary Ticket
TITLE: Joomla iCagenda & Balbooa Forms Unauth File-Upload RCE
(CVE-2026-48939 + CVE-2026-56291)
SEVERITY: Critical — two CVSS 10.0 zero-days, CISA KEV 2026-07-10
SCOPE: Joomla web servers running iCagenda or Balbooa Forms
HYPOTHESIS: Unauth upload drops a PHP webshell in a browsable dir; a follow-up
request executes commands as the web-server user.
QUERIES: Q1 shell spawn · Q2 upload-dir php write · Q3 recon · Q4 download ·
Q5 reverse shell · Q6 cron/task · Q7 egress
DO FIRST: Patch extensions -> sweep upload dirs -> run Q1 and Q2 -> audit
Joomla Super Users
FINDINGS: <fill after run>
GAPS: Upload HTTP request off-endpoint; atomic IPs/hashes not published
ACTIONS: Patch, disable PHP in upload dirs, WAF virtual patch, rotate creds
OWNER: HuntPack
VERSION: v0.2 · 2026-07-15
Changelog
table() calls now carry an explicit row limit: the default is 200 and truncation is silent, so a capped result was indistinguishable from a complete one. Atomic-IOC sweeps (filters over 5+ hashes or C2 IPs) use limit=max so a wide infection is never silently under-scoped; behavioural hunts use limit=200, where exceeding the cap indicates the query needs tuning. Where present, event names that do not exist in the Falcon data model were corrected (e.g. ServiceInstalled is a Sysmon concept, not a Falcon event; ElfFileWritten is ELFFileWritten) — such queries could never return a row. No detection logic, fields, or IOCs changed.References
| Tier | Source | Used For | Access Date |
|---|---|---|---|
| 1 | CISA KEV catalog | KEV addition 2026-07-10 for both CVEs | 2026-07-15 |
| 2 | The Hacker News (2026-07-13) | CVE details, affected versions, scanner UA, upload paths, timeline | 2026-07-15 |
| 2 | Joomla Extensions Directory / vendor advisories | Fixed versions (iCagenda 4.0.8/3.9.15, Balbooa 2.4.1) | 2026-07-15 |
| 3 | MITRE ATT&CK | Technique + mitigation mapping | 2026-07-15 |