2026-02-25 21:16:36 -05:00
|
|
|
use crate::evidence::Confidence;
|
|
|
|
|
use crate::patterns::{Pattern, PatternCategory, PatternTier, Severity};
|
2025-06-17 01:17:48 +02:00
|
|
|
|
2026-02-25 21:16:36 -05:00
|
|
|
/// PHP AST patterns.
|
|
|
|
|
///
|
|
|
|
|
/// Taint rules cover `system`/`exec`/`passthru`/`shell_exec` (command
|
|
|
|
|
/// injection), `echo`/`print` (XSS sinks), and `mysqli_query`/`pg_query`
|
|
|
|
|
/// (SQL sinks). AST patterns here focus on **eval**, **deserialization**,
|
|
|
|
|
/// **deprecated dangerous functions**, **include with variable**, and
|
|
|
|
|
/// **SQL concatenation** (Tier B).
|
2025-06-17 01:17:48 +02:00
|
|
|
pub const PATTERNS: &[Pattern] = &[
|
2026-02-25 21:16:36 -05:00
|
|
|
// ── Tier A: Code execution ─────────────────────────────────────────
|
2025-06-24 20:27:06 +02:00
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "php.code_exec.eval",
|
|
|
|
|
description: "eval() — dynamic code execution",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#eq? @n "eval"))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeExec,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "php.code_exec.create_function",
|
|
|
|
|
description: "create_function() — deprecated eval-like constructor",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#eq? @n "create_function"))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeExec,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "php.code_exec.preg_replace_e",
|
|
|
|
|
description: "preg_replace with /e modifier — code execution via regex",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#eq? @n "preg_replace")
|
|
|
|
|
arguments: (arguments
|
|
|
|
|
(argument
|
|
|
|
|
(string) @pat (#match? @pat "/[^/]*/[a-zA-Z]*e"))))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::High,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeExec,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
|
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "php.code_exec.assert_string",
|
|
|
|
|
description: "assert() with string argument — evaluates PHP code",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#eq? @n "assert")
|
|
|
|
|
arguments: (arguments
|
|
|
|
|
(argument (string) @code)))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::High,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CodeExec,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
2026-02-25 21:16:36 -05:00
|
|
|
// ── Tier A: Command execution ──────────────────────────────────────
|
2025-06-24 20:27:06 +02:00
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "php.cmdi.system",
|
|
|
|
|
description: "system/shell_exec/exec/passthru — shell command execution",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#match? @n "^(system|shell_exec|exec|passthru|proc_open|popen)$"))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::High,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::CommandExec,
|
|
|
|
|
confidence: Confidence::High,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
2026-02-25 21:16:36 -05:00
|
|
|
// ── Tier A: Deserialization ────────────────────────────────────────
|
2025-06-24 20:27:06 +02:00
|
|
|
Pattern {
|
2026-02-25 21:16:36 -05:00
|
|
|
id: "php.deser.unserialize",
|
|
|
|
|
description: "unserialize() — PHP object injection",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#eq? @n "unserialize"))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::High,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::Deserialization,
|
|
|
|
|
confidence: Confidence::High,
|
|
|
|
|
},
|
|
|
|
|
// ── Tier B: SQL injection (concatenation heuristic) ────────────────
|
|
|
|
|
Pattern {
|
|
|
|
|
id: "php.sqli.query_concat",
|
|
|
|
|
description: "mysql_query/mysqli_query with concatenated SQL string",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#match? @n "^(mysql_query|mysqli_query)$")
|
|
|
|
|
arguments: (arguments
|
|
|
|
|
(argument (binary_expression) @concat)))
|
|
|
|
|
@vuln"#,
|
2025-06-24 20:27:06 +02:00
|
|
|
severity: Severity::Medium,
|
2026-02-25 21:16:36 -05:00
|
|
|
tier: PatternTier::B,
|
|
|
|
|
category: PatternCategory::SqlInjection,
|
|
|
|
|
confidence: Confidence::Medium,
|
|
|
|
|
},
|
|
|
|
|
// ── Tier B: Path traversal (include with variable) ─────────────────
|
|
|
|
|
Pattern {
|
|
|
|
|
id: "php.path.include_variable",
|
|
|
|
|
description: "include/require with variable path — file inclusion vulnerability",
|
|
|
|
|
query: r#"(include_expression (variable_name)) @vuln"#,
|
|
|
|
|
severity: Severity::High,
|
|
|
|
|
tier: PatternTier::B,
|
|
|
|
|
category: PatternCategory::PathTraversal,
|
|
|
|
|
confidence: Confidence::Medium,
|
|
|
|
|
},
|
|
|
|
|
// ── Tier A: Crypto ─────────────────────────────────────────────────
|
|
|
|
|
Pattern {
|
|
|
|
|
id: "php.crypto.md5",
|
|
|
|
|
description: "md5() — weak hash function",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#eq? @n "md5"))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::Low,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::Crypto,
|
|
|
|
|
confidence: Confidence::Medium,
|
|
|
|
|
},
|
|
|
|
|
Pattern {
|
|
|
|
|
id: "php.crypto.sha1",
|
|
|
|
|
description: "sha1() — weak hash function",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#eq? @n "sha1"))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::Low,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::Crypto,
|
|
|
|
|
confidence: Confidence::Medium,
|
|
|
|
|
},
|
|
|
|
|
Pattern {
|
|
|
|
|
id: "php.crypto.rand",
|
|
|
|
|
description: "rand()/mt_rand() — not cryptographically secure",
|
|
|
|
|
query: r#"(function_call_expression
|
|
|
|
|
function: (name) @n (#match? @n "^(rand|mt_rand)$"))
|
|
|
|
|
@vuln"#,
|
|
|
|
|
severity: Severity::Low,
|
|
|
|
|
tier: PatternTier::A,
|
|
|
|
|
category: PatternCategory::Crypto,
|
|
|
|
|
confidence: Confidence::Medium,
|
2025-06-24 20:27:06 +02:00
|
|
|
},
|
2025-06-17 01:17:48 +02:00
|
|
|
];
|