#!/usr/bin/env bash
# find-php-on-aws.sh: read-only sweep for places PHP runs in one AWS account.
#
# Companion to https://www.factualminds.com/blog/php2shell-aws-waf-8kb-gap-2026/
# Written 2026-10-27 for PHP2Shell (CVE-2026-109618, CVE-2026-109619).
#
# Every call below is a Describe/List/Get. Nothing is created, changed, or deleted.
# Needs AWS CLI v2 and credentials with read access to EC2, SSM, Elastic Beanstalk,
# Lambda, Lightsail, and Inspector. A missing permission or an unsupported Region
# prints a SKIP line and the sweep moves on.
#
# Usage:
#   ./find-php-on-aws.sh                 # all enabled Regions
#   REGIONS="us-east-1 eu-west-1" ./find-php-on-aws.sh
#
# What it cannot see: PHP inside container images that Inspector does not scan,
# hosts without the SSM agent, and anything outside this account.

set -uo pipefail

REGIONS="${REGIONS:-$(aws ec2 describe-regions --query 'Regions[].RegionName' --output text)}"

run() {
  # run <label> <aws args...>; prints output, or SKIP when the call fails
  local label="$1"; shift
  local out
  if out=$(aws "$@" --output text 2>&1); then
    [ -n "$out" ] && [ "$out" != "None" ] && printf '%s\n' "$out" | sed "s/^/  [$label] /"
  else
    printf '  [%s] SKIP: %s\n' "$label" "$(printf '%s' "$out" | head -1)"
  fi
}

for region in $REGIONS; do
  echo "== $region"

  # 1. EC2 and on-prem hosts that report SSM Inventory with a php* package
  run ssm-inventory ssm get-inventory --region "$region" \
    --filters 'Key=AWS:Application.Name,Values=php,Type=BeginWith' \
    --query 'Entities[].[Id, join(`,`, Data."AWS:Application".Content[?starts_with(Name, `php`)].join(`=`, [Name, Version || `?`]))]'

  # 2. Elastic Beanstalk environments on a PHP platform
  run beanstalk elasticbeanstalk describe-environments --region "$region" \
    --query "Environments[?contains(SolutionStackName || '', 'PHP')].[EnvironmentName, SolutionStackName, Status]"

  # 3. Lambda functions that could bundle PHP (custom runtime or container image)
  run lambda lambda list-functions --region "$region" \
    --query "Functions[?PackageType=='Image' || starts_with(Runtime || '', 'provided')].[FunctionName, Runtime || PackageType]"

  # 4. Lightsail instances; PHP blueprints include WordPress, LAMP, Drupal, Joomla, Magento
  run lightsail lightsail get-instances --region "$region" \
    --query "instances[?contains(blueprintId, 'wordpress') || contains(blueprintId, 'lamp') || contains(blueprintId, 'drupal') || contains(blueprintId, 'joomla') || contains(blueprintId, 'magento')].[name, blueprintId, publicIpAddress]"

  # 5. Inspector findings for either CVE (empty if Inspector is off or has no rule yet)
  for cve in CVE-2026-109618 CVE-2026-109619; do
    run "inspector:$cve" inspector2 list-findings --region "$region" \
      --filter-criteria "{\"vulnerabilityId\":[{\"comparison\":\"EQUALS\",\"value\":\"$cve\"}]}" \
      --query 'findings[].[resources[0].id, severity, status]'
  done
done

cat <<'EOF'

Next: on each host found above, run `php -v` and `php -i | grep session.upload_progress.enabled`.
Fixed versions: 8.5.12, 8.4.27, 8.3.36, 8.2.35. PHP 8.1 and older get no regular upstream fix.
An empty Inspector result does not mean you are clean. Check sections 1 to 4 by hand.
EOF
