Aws/php2shell Hunt
Head-hunt exposure and indicators of compromise for the PHP2Shell remote code execution vulnerabilities CVE-2026-109618 and CVE-2026-109619 across AWS, using only the signals AWS already collects — no SSH, no in-guest access.
Unlike @swamp/cve/php-rce-2026-10 (which scans and patches hosts directly over SSH/Docker), this model is strictly read-only AWS-side telemetry. It observes:
- Amazon Inspector v2 findings for the two CVEs (vulnerable PHP inventory)
- GuardDuty findings since 2026-10-17 correlated to the published IOC IPs and to RCE/backdoor-shaped finding types
- CloudWatch Logs Insights over VPC flow logs (IOC IP contact) and over WAF/ALB/application logs (the PHP_SESSION_UPLOAD_PROGRESS upload marker)
- Security Hub (opportunistic): one aggregated query when a central aggregator is present; the hunt still works fully without it
Scope spans a single account, a named set of accounts, or every active account in an AWS Organization resolved from a delegated-administrator account. Each method fans out across a configurable region list internally.
The output is deliberately honest about what it could NOT inspect. A clean
result is no_signal only for lanes that actually ran; any lane that could
not run is recorded in lanesSkipped with a reason, and an account with no
runnable lane is inconclusive, never no_signal.
Authentication
Uses the default AWS credential chain, or the profile global argument
(fromIni / SSO token cache). Point at the delegated-admin account for
organization scope.
Required IAM Permissions
inspector2:ListFindingsguardduty:ListDetectors,guardduty:ListFindings,guardduty:GetFindingslogs:StartQuery,logs:GetQueryResultssecurityhub:GetFindings(optional lane)organizations:ListAccounts(organization scope only)
Coverage caveats
- Amazon Inspector only sees SSM-managed EC2, scanned ECR images, and Lambda. Absence of an Inspector hit is NOT proof of safety for unmanaged hosts.
- The logs lane needs explicit
logGroupNames; flow/WAF/ALB groups cannot be auto-discovered and S3-delivered logs are out of reach of Logs Insights.
Usage
# Single account, default US regions
AWS_PROFILE="my-account/ReadOnlyPlus" \
swamp behavior create @webframp/aws/php2shell-hunt hunt
# Emit the indicator set as queryable data
swamp behavior run hunt show_iocs
# Full hunt, single account, with flow + WAF log groups
swamp behavior run hunt hunt \
--input 'logGroupNames=["/vpc/flowlogs","/aws/waf/php-app"]'
# Org-wide from the delegated-admin account
swamp behavior create @webframp/aws/php2shell-hunt org-hunt \
--global-arg scope=organization \
--global-arg 'regions=["us-east-1","us-east-2","us-west-2"]'
swamp behavior run org-hunt huntMethods
- show_iocs - Emit the PHP2Shell indicator set as data (no AWS calls)
- scan_inspector - Inspector v2 findings for the CVEs across regions
- scan_guardduty - GuardDuty findings correlated to IOC IPs / RCE types
- scan_logs - Logs Insights: IOC IP contact + upload marker
- scan_securityhub - Opportunistic aggregated Security Hub lane
- hunt - Run all lanes, correlate, write a per-account exposure verdict
2026.10.22.1
Added: Initial release. Head-hunts PHP2Shell exposure (CVE-2026-109618, CVE-2026-109619) across AWS using read-only service telemetry — no SSH or in-guest access.
show_iocsemits the indicator set (CVEs, six IOC IPs, thePHP_SESSION_UPLOAD_PROGRESSupload marker, the 2026-10-17 earliest-known exploitation date, fixed PHP versions) as queryable data.discover_log_groupsenumerates and ranks CloudWatch log groups across the configured regions by likely relevance (flow / WAF / ALB / app), so an agent can present candidates and a user can chooselogGroupNamesfor the logs lane. Runs no queries.scan_inspectorqueries Amazon Inspector v2 for the two CVEs across regions.scan_guarddutycorrelates GuardDuty findings since 2026-10-17 against the IOC IPs and RCE/backdoor-shaped finding types.scan_logsruns CloudWatch Logs Insights over supplied log groups for IOC IP contact (flow logs) and the upload marker (WAF/ALB/app logs).scan_securityhubopportunistically queries an aggregated Security Hub; skips cleanly when none is present.huntruns every lane across the configured scope and regions, correlates them, and writes a per-account exposure verdict (confirmed_exposure/active_targeting/possible_probe/no_signal/inconclusive). A lane that could not run is recorded inlanesSkipped; an account with no runnable lane isinconclusive, neverno_signal.
Optional jev enrichment: when the jevBehavior global argument names a
pre-created @swamp/typesafe-ai (jev) behavior whose apiKey resolves from a
vault, hunt asks jev — through runModel — to calibrate the fuzzy GuardDuty
RCE-hint and log upload-marker signals, and thresholds the possible_probe
verdict on jev's judgement rather than a substring match. CVE matches stay
binary and are never sent to jev. With no jevBehavior the hunt is unchanged. A
jev failure is recorded (jevEnriched: false + jevSkipReason) and falls back
to the heuristic — it never silently yields a clean verdict.
Resources
- Has README or module doc2/2earned
- README has a code example1/1earned
- README is substantive1/1earned
- Most symbols documented1/1earned
- No slow types (deprecated)1/1earned
- Dependencies pass trust audit2/2earned
- Has description1/1earned
- Platform support declared (or universal)2/2earned
- License2/2earned
- Verified public repository2/2earned