# 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.
