/*
 * Defensive telemetry originally published before the 2026 PHP emergency release.
 * Post-release advisories confirm broader OOM and stale-state paths that these
 * rules do not comprehensively detect.
 *
 * Scope:
 * - Scan UNPACKED files and retained, decrypted HTTP request bodies.
 * - These rules are alerts/hunts, not a compensating control for a PHP-core flaw.
 * - Do not scan live session files in place if the scanner can lock or alter them.
 */

import "hash"

rule PHPUP_Staged_Bundle_Exact_Hash
{
    meta:
        author = "Cody Kretsinger"
        date = "2026-10-20"
        confidence = "high"
        purpose = "Detect the exact staged archive identified in public reporting"
        limitation = "Hash only; renamed or modified variants will not match"
    condition:
        filesize > 30MB and filesize < 50MB and
        hash.sha256(0, filesize) == "0c254d547cac650bfbcb2275e30c2083737520a51a0511646f1fbb7ed60a0d63"
}

rule PHPUP_Staged_Tooling_Unpacked
{
    meta:
        author = "Cody Kretsinger"
        date = "2026-10-20"
        confidence = "medium"
        purpose = "Hunt unpacked staged-tooling files or documentation"
        limitation = "Compressed tarballs must be unpacked before string scanning"
    strings:
        $file1 = "php_up_framework.py" ascii wide
        $file2 = "poc0_109618.py" ascii wide
        $file3 = "poc1_109619.py" ascii wide
        $file4 = "poc_trigger.py" ascii wide
        $mark1 = "DELTAS_LSphp" ascii wide nocase
        $mark2 = "PHPUP_FILES" ascii wide
        $mark3 = "php_session_rfc1867_callback" ascii wide
    condition:
        filesize < 10MB and (2 of ($file*) or (1 of ($file*) and 1 of ($mark*)))
}

rule PHPUP_Session_Progress_Record
{
    meta:
        author = "Cody Kretsinger"
        date = "2026-10-20"
        confidence = "informational"
        purpose = "Locate persisted upload-progress records for incident scoping"
        limitation = "Matches normal use of the feature; supports common PHP serializers only"
    strings:
        $php_session = /upload_progress_[^|]{0,256}\|a:[0-9]{1,10}:\{/ ascii
        $php_serialize = /s:[0-9]{1,10}:"upload_progress_[^"]{0,256}";a:[0-9]{1,10}:\{/ ascii
        $field1 = "bytes_processed" ascii
        $field2 = "content_length" ascii
        $field3 = "start_time" ascii
        $field4 = "files" ascii
    condition:
        filesize < 4MB and (any of ($php_*) and 2 of ($field*))
}

rule PHPUP_Session_Progress_Potential_PostCompromise
{
    meta:
        author = "Cody Kretsinger"
        date = "2026-10-20"
        confidence = "medium"
        purpose = "Triage session artifacts that contain progress data and command-payload strings"
        limitation = "May be an attempted or staged payload; a match does not prove execution or compromise"
    strings:
        $progress = "upload_progress_" ascii
        $cmd1 = "system(" ascii nocase
        $cmd2 = "shell_exec" ascii nocase
        $cmd3 = "proc_open" ascii nocase
        $cmd4 = "passthru" ascii nocase
        $cmd5 = "/bin/sh" ascii
        $cmd6 = "/dev/tcp/" ascii
        $cmd7 = /(curl|wget)\s+-?[a-zA-Z]*\s*https?:\/\// ascii
    condition:
        filesize < 4MB and $progress and 1 of ($cmd*)
}

rule PHPUP_Multipart_Progress_Small_File_Hunt
{
    meta:
        author = "Cody Kretsinger"
        date = "2026-10-20"
        confidence = "low"
        purpose = "Prioritize retained multipart requests that exercised upload progress with a very small file part"
        limitation = "Use for hunt/correlation only; legitimate upload-progress forms can match"
    strings:
        $disposition = "Content-Disposition: form-data" ascii nocase
        $progress = "name=\"PHP_SESSION_UPLOAD_PROGRESS\"" ascii nocase
        $file_part = "filename=" ascii nocase
    condition:
        filesize < 4096 and all of them
}

rule PHPUP_Multipart_Progress_Any
{
    meta:
        author = "Cody Kretsinger"
        date = "2026-10-20"
        confidence = "informational"
        purpose = "Baseline all retained use of PHP upload progress"
        limitation = "Never use alone as a block or high-severity alert"
    strings:
        $progress = "PHP_SESSION_UPLOAD_PROGRESS" ascii nocase
    condition:
        $progress
}
