PrestaShop
Perl backticks/qx// sinks in Apache mod_perl handlers (reachability and exploitation)
Real-world pattern: Perl code builds a shell command string and executes it via backticks (or qx//). In a mod_perl AccessHandler, attacker-controlled request components like $r->uri() can flow into that string. If any branch concatenates raw input and then evaluates it with a shell, you get pre-auth RCE.
Risky Perl execution primitives (spawn a shell when given a single string):
- Backticks / qx//: my $out = cmd ...;
- system with a single string: system("/bin/sh -c '...'") implicitly
- open with a pipe: open my $fh, "cmd |" or "| cmd"
- IPC::Open3 with a single string
Minimal vulnerable shape observed in the wild:
sub getCASURL {
...
my $exec_cmd = "...";
if ($type eq 'login') {
$exec_cmd .= $uri; # $uri from $r->uri() → attacker-controlled
my $out = `$exec_cmd`; # backticks = shell
}
}
Exploitation workflow 1) Inspect httpd.conf for PerlModule/MOD_PERL handler scopes to find a resolvable path processed by the handler. 2) Send an unauthenticated request so the login redirect path is taken (type == "login"). 3) Place shell metacharacters in the request-URI path so $r->uri() carries your payload into the command string.
Example HTTP PoC (path injection via ';')
GET /ui/health;id HTTP/1.1
Host: target
Connection: close
backticks, $(...), and encoded newlines (%0A) depending on quoting.
- If earlier patches quote other args but not the URI in one branch, payloads appended at the end of the string often work: ;id# or &&/usr/bin/id#
Hardening (Perl) - Do not build shell strings. Prefer argument-vector execution: system('/usr/bin/curl', '--silent', '--', $safe_url) — no shell. - If a shell is unavoidable, escape strictly and consistently across all branches; treat $r->uri() as hostile. Consider URI::Escape for paths/queries and strong allowlists. - Avoid backticks/qx// for command execution; capture output via open3/list form if truly needed without invoking a shell. - In mod_perl handlers, keep auth/redirect code paths free of command execution or ensure identical sanitization across branches to avoid “fixed everywhere but one branch” regressions.
Vulnerability hunting - Patch-diff modules that assemble shell commands; look for inconsistent quoting between branches (e.g., if ($type eq 'login') left unescaped). - Grep for backticks, qx//, open\s(|||, and system\s(\s*" to find string-based shells. Build a call graph from sink to request entry ($r) to verify pre-auth reachability.
Real-world case: Dell UnityVSA pre-auth RCE (CVE-2025-36604) - Pre-auth command injection via backticks in AccessTool.pm:getCASURL when type == "login" concatenated raw $uri ($r->uri()). - Reachable through MOD_SEC_EMC::AccessHandler → make_return_address($r) → getCASLoginURL(..., type="login") → getCASURL(..., $uri, 'login'). - Practical nuance: use a resolvable path covered by the handler; otherwise the module won’t execute and the sink won’t be hit.