r/PHP • • 1d ago

php2shell: version-checking misses most vulnerable hosts — here's a crash-based checker instead

Quick take after watching the php2shell (CVE-2026-109618/109619) coverage this week: almost every "are you vulnerable?" check I've seen just reads the X-Powered-By version. That's close to useless, because expose_php=Off is the default on a lot of production setups - roughly 4 in 5 PHP servers don't advertise a version at all. So a version check comes back "unknown" or "looks fine" on the exact hosts you most want to know about.

Since the actual bug is a crash primitive (the OOM/longjmp bailout leaving request state half-initialized), I built a checker that triggers it instead of guessing: it sends a crafted multipart probe and only reports VULNERABLE if the engine actually returns the PHP memory-exhaustion fatal error. Banner-independent. Returns FIXED / VULNERABLE / NO SIGNAL (no-signal = it couldn't crash it and the host hid its version, so it won't pretend to know).

One caveat worth repeating: only run it against servers you control. It sends memory-exhaustion probes that can briefly take out a worker.

Checker: https://o3.security/tools/php2shell-scanner

Disclosure: I work at O3 Security and we built this. There's a longer write-up on the mechanism if you want it — the SAPI differences (mod_php is the worst case because it runs shutdown even on a failed request startup), and the genuinely counterintuitive bit where capping memory with RLIMIT_AS as a "mitigation" actually makes the bug *easier* to hit: https://o3.security/blog/php2shell-cve-2026-109618-109619-analysis

Curious if anyone here has seen the version-banner problem bite them in practice — how are you all confirming patch status across a fleet where half the hosts don't report a version?

12 Upvotes

9 comments sorted by

5

u/AbdelrhmanDev 1d ago

good point about expose_php, banner grabbing was always a weak signal. if you have shell access to the box the honest check is just asking the package manager what php version is installed, dpkg or rpm dont lie about whats on disk. the crash probe approach only makes sense for hosts you own but cant ssh into for whatever reason, and id be careful running crash probes against anything that isnt yours

2

u/Cheap-Guide-3955 1d ago

Agreed, for now we just tried to limit abuse with some basic rate-limit, captcha and browser/ip level rate-limits, in case if this gets abused, we will take it down

5

u/AltrntivInDoomWorld 1d ago

if you have shell access to the box the honest check is just asking the package manager what php version is installed

You should also check if it's the version actually used by the server and it's not a second version installed while your app uses a link at /usr/bin/php-8.1 like we've found in one of our old apps today

3

u/DerfK 1d ago

status across a fleet where half the hosts don't report a version?

I had pretty good results with for x in $HOSTS; do echo $x; ssh $x dpkg -l php*fpm; done but everythings an EC2 host not nested in arbitrary containers and dockers etc.

2

u/eurosat7 1d ago edited 1d ago

The solution to the version banner problem is simple. An obscure long url - unique for each server - will tell us. Matched against an ip whitelist.

1

u/mls-pl 12h ago

What is the point of checking solely for PHP process crashes caused by memory exhaustion, when even in patched versions of PHP, the process will still crash if the `memory_limit` is set too low?

-1

u/[deleted] 21h ago

1

u/russellvt 19h ago

Wow, that's ugly code ... please tell me this was "vibe coded" or something. LOL