# REPRO-2026-00307: vBulletin runtime template runMaths pre-auth RCE ## Summary Status: published Severity: critical CVSS: Unknown CWE: Unknown Type: security Confidence: high ## Identifiers REPRO ID: REPRO-2026-00307 CVE: CVE-2026-61511 ## Package Name: Unknown Ecosystem: Unknown Affected: Unknown Fixed: Unknown ## Root Cause # Root Cause Analysis Report ## Summary CVE-2026-61511 is a pre-authentication remote code execution vulnerability in vBulletin's template runtime. The public `ajax/render/pagenav` route merges unauthenticated POST data into template variables. The stock `pagenav` template assigns `pagenav[pagenumber]` to `pagenav.currentpage` and embeds it in a `{vb:math}` expression. `vB5_Template_Runtime::runMaths()` removes characters with a deny-style regular expression but retains digits, parentheses, concatenation, bitwise XOR, and invocation syntax, then passes the result to PHP `eval()`. A phpfuck-style expression can therefore synthesize `system` and an attacker-selected command using only permitted characters. This run reproduced arbitrary command execution through the real HTTP route without a session. ## Impact - **Affected component:** vBulletin 5/6 presentation-layer template engine, specifically `includes/vb5/template/runtime.php`, the `pagenav` template, and the public AJAX renderer. - **Affected versions:** The published CVE record identifies vBulletin 5.0.0 through 5.7.5 and 6.0.0 through 6.2.1. The exact current-run target was vBulletin 5.1.5. - **Tested runtime:** vBulletin 5.1.5 source and original database from digest-pinned image manifest `cck1/vbulletin:v2` (`sha256:df5a9fa87186c49101db79577a0401c07f1239bf79dd1e5d066328147f6727f8`), served by Apache 2.4.25 with PHP 7.0.32. The PHP runtime came from the digest-pinned `wordpress:4.9.8-php7.0-apache` image manifest (`sha256:60cbd13178ed7f629098b1b7a0104ce038d55729f89784739e1bc2eca372f64a`); only its Apache/PHP runtime was used, not WordPress code. - **Risk:** Critical. An unauthenticated network attacker can run commands as the web-service account. Consequences include application/database disclosure, site modification, persistence, credential theft, and potential host compromise depending on service privileges. - **Repository scope note:** The ticket-mandated `https://github.com/quangbahoa/vbulletin` repository was inspected at commit `6126d15ed2a4023e9efa672c387f98c3e9905d4c`, but it contains vBulletin 3.8.11 and has no `runMaths`, `{vb:math}`, or `ajax/render` implementation. It is outside the CVE's affected 5.x/6.x code family and could not be the runtime target. ## Impact Parity - **Disclosed/claimed maximum impact:** Unauthenticated remote arbitrary PHP/code execution. - **Reproduced impact:** Unauthenticated attacker-selected OS command execution via `system()` through `POST /` with `routestring=ajax/render/pagenav` and `pagenav[pagenumber]`. - **Parity:** `full` - **Not demonstrated:** No privilege escalation beyond the web-service account, persistence, outbound connectivity, or destructive post-exploitation was attempted. ## Root Cause The public light application recognizes any route beginning with `ajax/render` and dispatches it without an authentication gate. `vB5_Frontend_Controller_Ajax::actionRender()` combines `$_GET`, `$_POST`, and supplied data, then renders the caller-selected server template. In the stock `pagenav` template, a request-provided `pagenav[pagenumber]` value becomes `pagenav.currentpage`; that value is then inserted into math expressions such as: ```text {vb:math {vb:var pagenav.currentpage} - 1} ``` `vB5_Template_Runtime::runMaths()` attempts to make `eval()` safe with this filter: ```php $str = preg_replace('#([^+\-*=/\(\)\d\^<>&|\.]*)#', '', $str); $status = @eval("\$str = $str;"); ``` The filter is not a safe arithmetic parser. The retained character set supports numeric literals, string concatenation, XOR-based string construction, parenthesized expression invocation, and function calls on PHP 7+. The exploit synthesizes the string `CHR`, uses it to build `system` and the command byte-by-byte, then invokes the resulting function name. The request is processed more than once in the template, which explains the duplicate response marker; one successful invocation is already sufficient for RCE. The vulnerable source excerpts captured from the exact tested package are: - `bundle/logs/repro/vb515-runmaths-source.txt` - `bundle/logs/repro/vb515-pagenav-source.txt` The vendor fix is available as vBulletin 6.2.2 and as Patch Level 1 packages for 6.2.1, 6.2.0, and 6.1.6. The patches are license-gated at `https://members.vbulletin.com/patches.php`; no public source commit was found. Vendor references: - https://forum.vbulletin.com/forum/vbulletin-announcements/vbulletin-announcements_aa/4509358-security-patch-released-for-vbulletin-6-2-1-6-2-0-and-6-1-6 - https://forum.vbulletin.com/forum/vbulletin-announcements/vbulletin-announcements_aa/4509404-vbulletin-6-2-2-is-available ## Reproduction Steps 1. Run `bash -n bundle/repro/reproduction_steps.sh` to validate shell syntax. 2. Start an isolated affected vBulletin instance with a compatible PHP 7+ runtime, then invoke: ```bash TARGET_URL=http://127.0.0.1:18081/ bash bundle/repro/reproduction_steps.sh ``` 3. The script: - verifies service reachability; - generates a fresh nonce and a phpfuck/XOR payload using only characters accepted by the vulnerable filter; - sends a benign numeric request through the same unauthenticated endpoint and verifies that it does not contain the nonce; - sends the malicious `pagenav[pagenumber]` request; - requires the exact fresh response marker before exiting successfully; - writes `bundle/repro/runtime_manifest.json` and request, response, payload, identity, and proof logs. 4. Expected success evidence is exit code 0 and: ```text CONFIRMED: unauthenticated pagenav input executed an attacker-selected command through runMaths(). ``` The script exits 1 when the endpoint is reached but command execution is absent and exits 2 for a service/setup blocker. ## Evidence Primary current-run positive evidence (two consecutive self-contained runs): - `bundle/logs/repro/durable-positive-3-proof.log` and `bundle/logs/repro/durable-positive-4-proof.log` - `response_marker=true` - `target_file_marker=true` - `benign_control_reached_math=true` - `benign_control_clean=true` - `authentication_material_sent=false` - `CONFIRMED: unauthenticated pagenav input executed an attacker-selected command through runMaths().` - `bundle/logs/repro/durable-positive-3-exploit-request.trace` and `bundle/logs/repro/durable-positive-4-exploit-request.trace` — byte-level HTTP traces of unauthenticated exploit requests. - `bundle/logs/repro/durable-positive-3-exploit-response.txt` and `bundle/logs/repro/durable-positive-4-exploit-response.txt` — each contains its independent fresh marker: ```text __PRUVA_BEGIN__PRUVA_RUNMATHS_durable_positive_3__PRUVA_END__ __PRUVA_BEGIN__PRUVA_RUNMATHS_durable_positive_4__PRUVA_END__ ``` - `bundle/logs/repro/durable-positive-3-marker.txt` and `bundle/logs/repro/durable-positive-4-marker.txt` — independent target-local files written by the command. - `bundle/logs/repro/durable-positive-3-baseline-response.txt` and `bundle/logs/repro/durable-positive-4-baseline-response.txt` — benign arithmetic controls through the same route, rendering page values 1 and 3 and no nonce. - `bundle/logs/repro/durable-positive-3-health.txt` and `bundle/logs/repro/durable-positive-4-health.txt` — reachable vBulletin service and PHP 7.0.32 headers. - `bundle/repro/runtime_manifest.json` — structured current-run endpoint and proof-artifact manifest. Compatibility negative control: - `bundle/logs/repro/manual-positive-1-exploit-response.txt` and `bundle/logs/repro/php55-negative-control.txt` show that the same product route under PHP 5.5.9 returned `Invalid math expression`; PHP 5.5 lacks the PHP 7 uniform-variable syntax used by the public payload. This constrains exploitability of this payload but does not negate the confirmed affected configuration. Source and provenance evidence: - `bundle/logs/repro/vb515-runmaths-source.txt` - `bundle/logs/repro/vb515-pagenav-source.txt` - `bundle/logs/repro/CVE-2026-61511-cve-record.json` - `bundle/logs/repro/KIS-2026-13.html` - `bundle/logs/repro/ssd-post-10702.json` Novelty classification is `duplicate`: KIS-2026-13, SSD Secure Disclosure, the CVE record, and the public PoC disclose this exact pagenav-to-runMaths route and payload mechanism. ## Recommendations / Next Steps - Upgrade to vBulletin 6.2.2 or later, or apply the official Patch Level 1 package for a supported 6.2.1, 6.2.0, or 6.1.6 installation immediately. - Replace `eval()` with a small, explicitly bounded arithmetic parser. A character filter is not an adequate substitute for grammar validation. - Do not merge arbitrary unauthenticated request arrays into server-template data. Use route-specific schemas and scalar type/length limits. - Restrict public template rendering to an explicit allowlist and audit every allowed template for request-to-executable-context flows. - Add regression tests that submit the published payload and nearby character-set variants to every public math-bearing template; assert no command marker, no function call, and a safe validation error. - Review logs for large `pagenav[pagenumber]` values and requests selecting `ajax/render/pagenav`. - Treat disabling dangerous PHP functions only as defense in depth, not the primary fix. ## Additional Notes - **Idempotency:** The proof uses a unique nonce and marker path per run. Repeating it does not depend on a previous marker and the benign control always runs first. The final self-contained script completed twice consecutively with exit code 0 (`durable-positive-3` and `durable-positive-4`), producing distinct markers. - **PHP limitation:** The public phpfuck payload relies on PHP 7's uniform variable syntax. The exact vBulletin 5.1.5 instance under PHP 5.5 reached the sink but returned an invalid-expression control result. PHP 7.0.32 produced command execution. - **Comparator limitation:** The vendor's fixed package is license-gated and was not available in this environment. The PHP 5.5 parser control and benign same-route control were both reached, but they are not substitutes for testing vBulletin 6.2.2. Variant analysis should test the official fixed release if licensed bytes become available. - The local command was deliberately limited to a unique `/tmp` marker plus a matching response marker; no external network target or third-party vBulletin site was touched. ## Reproduction Details Reproduced: 2026-07-27T17:08:24.902Z Duration: 8351 seconds Tool calls: 826 Turns: Unknown Handoffs: 3 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00307 pruva-verify CVE-2026-61511 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00307&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00307/artifacts/bundle/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-61511 ## Artifacts - bundle/repro/rca_report.md (analysis, 10373 bytes) - bundle/repro/reproduction_steps.sh (reproduction_script, 21959 bytes) - bundle/coding/proposed_fix.diff (patch, 13567 bytes) - bundle/logs/coding/coding-live-3-variant-benign.json (other, 942 bytes) - bundle/logs/coding/coding-live-3-variant-attack.json (other, 39369 bytes) - bundle/repro/validation_verdict.json (other, 807 bytes) - bundle/logs/coding/coding-live-3-http.log (log, 153 bytes) - bundle/logs/coding/coding-live-3-source-identity.txt (other, 467 bytes) - bundle/logs/coding/coding-live-3-parent-benign.json (other, 466 bytes) - bundle/logs/coding/coding-live-3-parent-attack.json (other, 526 bytes) - bundle/logs/repro/php70-positive-1-proof.log (log, 193 bytes) - bundle/logs/repro/php70-positive-1-marker.txt (other, 31 bytes) - bundle/logs/repro/php70-positive-1-exploit-response.txt (other, 15650 bytes) - bundle/repro/runtime_manifest.json (other, 1687 bytes) - bundle/logs/repro/vb515-runmaths-source.txt (other, 2205 bytes) - bundle/logs/repro/vb515-pagenav-source.txt (other, 2702 bytes) - bundle/repro/discovery_manifest.json (other, 2649 bytes) - bundle/logs/repro/durable-positive-4-exploit-response.txt (other, 15654 bytes) - bundle/logs/repro/durable-positive-4-source-identity.txt (other, 911 bytes) - bundle/logs/repro/durable-positive-4-health.txt (other, 423 bytes) - bundle/logs/repro/durable-positive-4-baseline-request.trace (other, 1917 bytes) - bundle/logs/repro/durable-positive-4-payload.txt (other, 83145 bytes) - bundle/logs/repro/durable-positive-4-mysql.log (log, 283 bytes) - bundle/logs/repro/durable-positive-4-apache-stdout.log (log, 237 bytes) - bundle/logs/repro/durable-positive-4-apache-error.log (log, 505 bytes) - bundle/logs/repro/durable-positive-4-apache-access.log (log, 264 bytes) - bundle/coding/verify_fix.sh (other, 12017 bytes) - bundle/coding/summary_report.md (documentation, 6034 bytes) - bundle/logs/coding/coding-live-3-proof.log (log, 410 bytes) - bundle/logs/coding/coding-live-3-observation.json (other, 278 bytes) - bundle/logs/coding/coding-live-3-unit.log (log, 1419 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00307 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00307/artifacts/bundle/repro/reproduction_steps.sh - Web: https://pruva.dev/reproductions/REPRO-2026-00307 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev