#!/bin/bash # php-worker-ini-check.sh DOCROOT BASEURL [HOSTHEADER] [--upload] # # Shows five PHP settings as the web worker that serves DOCROOT sees them: # memory_limit, post_max_size, upload_max_filesize, session.upload_progress.enabled # and fatal_error_backtraces (PHP 8.5 only), each with its ini access level. # # It writes one randomly named PHP file into DOCROOT, requests it once through # your web server, and deletes it when the script exits. Run it only on a server # you administer, as a user that can write to DOCROOT. Afterwards, check that no # iniprobe_*.php file is left in DOCROOT. # # --upload sends a small multipart POST using PHPSESSID and the default upload # progress field. It checks a flat sess_ path under literal session.save_path. # A not_created result is inconclusive: custom names, fields, storage handlers, # structured save paths, strict mode or a failed upload can hide an active feature. # A missing upload_progress_ key is also inconclusive (cleanup or custom prefix). # The upload may leave a small synthetic session file for normal store cleanup. # The random probe name is not access control, curl has no time limit, and cleanup # is best effort. Interrupt a stalled check and verify the probe was removed. # # From CyberNative AI LLC: https://cybernative.ai/guides/php2shell-interim-mitigations-check-web-workers/ set -u DOC=${1:?usage: php-worker-ini-check.sh DOCROOT BASEURL [HOSTHEADER] [--upload]} URL=${2:?base url, e.g. http://127.0.0.1}; HOSTH=${3:-}; MODE=${4:-} [ "$HOSTH" = "--upload" ] && { MODE=--upload; HOSTH=; } [ -d "$DOC" ] && [ -w "$DOC" ] || { echo "cannot write to $DOC" >&2; exit 1; } N=iniprobe_$(head -c6 /dev/urandom | od -An -tx1 | tr -d ' \n').php P="$DOC/$N"; trap 'rm -f "$P"' EXIT cat > "$P" <<'PHP' "$F" curl -fsS "${H[@]}" -b "PHPSESSID=$SID" -F "PHP_SESSION_UPLOAD_PROGRESS=inicheck" -F "f=@$F" "$URL/$N?sess=$SID"; R=$?; rm -f "$F"; exit $R else curl -fsS "${H[@]}" "$URL/$N" fi