# PHP2Shell, and a Site Stuck on PHP 5.6

Source: https://gofranz.com/blog/php2shell-and-a-site-stuck-on-php-5-6/

On October 21 the PHP project [published fixes](https://www.php.net/archive/2026.php) for two bugs, CVE-2026-109618 and CVE-2026-109619, rated 9.2 out of 10. Together they let anyone on the internet run code on a PHP web server by sending it a crafted request. The details had leaked a day earlier, and exploit attempts showed up in honeypots before the patch was out. Apache with `mod_php` is the worst case: the attack runs before the application gets to execute a single line. Fixed releases exist for PHP 8.2 and up. Everything older gets nothing.

I run a site for the Malaysian-German Society. It's ExpressionEngine 2.9.2, a CMS release from 2014, on PHP 5.6, on Apache with `mod_php`. The day before I'd applied the two workarounds from the [advisory](https://github.com/php/php-src/security/advisories/GHSA-w8hw-w9fx-j79w): no memory limit inside PHP, upload progress off. The advisory itself says those reduce the exposure and don't close it. [CISA's advice](https://www.cisa.gov/news-events/alerts/2026/10/21/critical-vulnerabilities-php-require-immediate-patching) for anything on PHP 8.1 or older that can't be patched is to take it offline.

On my day off, I decided to take another look:

### The options

ExpressionEngine 2 was a commercial product. The last 2.x release got PHP 7.0 support in 2016; 2.9.2 predates even that. So the choices were:

1. **Upgrade to ExpressionEngine 7.** It's open source now and runs on PHP 8.5. The catch is the 17 add-ons: a couple are discontinued, two keep their content in their own tables, and every template that touches them changes.
2. **Replace the CMS with a static site.** Someone still edits events and news in the control panel, so no.
3. **Patch the CMS myself for PHP 8.4.** A fork of a 2014 code base, maintained by me.

I'd have told you the third one was the worst idea until I looked into it... A PHPCompatibility scan over the whole tree came back with 157 errors in 31 files: 60 PHP 4 style constructors, 41 `each()` loops, 140 curly-brace string offsets that `phpcbf` fixes on its own, and the removed `mysql` extension, which CodeIgniter 2 already has a `mysqli` driver for. Nothing too crazy.

### How it went

The mechanical part was one script. The rest was iteration: 
1. boot the site on `php:8.4-apache`
2. load a page
3. read the error
4. fix it
5. reload

ExpressionEngine turns a fatal error into a blank page with a 200 status and nothing in the log, so I added a shutdown hook that logs the last error.

The runtime breakage was about twenty items, and a few were real bugs that PHP 5 had hidden for a decade. A `+` where `.` was meant, which PHP 5 evaluated as zero and PHP 8 refuses. A regex `[^\w-.]` that the newer regex engine rejects, so a column name came back empty and the comments page died on a SQL error. `count()` on a string, which used to return 1. And 74 methods in add-ons whose signatures don't match the class they extend, which PHP 8 won't load at all; a small script found all of them in one pass.

### Result

130 files, about 390 lines changed. The site has been on PHP 8.4.27 since the afternoon of the 23rd. I compared 29 pages before and after the switch: identical status codes, sizes within a few hundred bytes.

The ExpressionEngine 7 question is still open. It's just no longer urgent.
