Skip to content

php2shell v1.14.0: chain D, measured — and confined

Latest

Choose a tag to compare

@JoshRob297 JoshRob297 released this 10 Nov 04:42
a0c7ef8

A negative result, published because a matrix that only lists successes is not a matrix.

One of the chains circulating for these CVEs says the request shutdown reads a stale EG(objects_store) left by a request that died mid-startup, and the next request on the same worker consumes it. We measured that step and it does not behave that way.

What was measured. php:8.4.26-apache, mod_php, one worker, breakpoint at php_request_shutdown (main/main.c:1891), three requests on that worker: a warmup GET (200), a chunked 70 MB body that dies at startup (500), a GET after the OOM (200). At the breakpoint, all three are identical: same store pointer, top=1, size=1024, flh=-1, current_execute_data nil, same vm_stack bounds. No crash, and the worker kept serving.

Where it stops, which is the important part. We measured the store header and its first bucket entries, not the whole 1024-entry array, and all three observations were made with the store empty at shutdown. A request that reaches shutdown holding live objects is another state, and this says nothing about it.

What survives. The bucket-array variant: segfo confirms the object_buckets use-after-free with a crash and marks RCE unproven; cookie-bakery publishes a full chain through zend_objects_store_del and a free_obj pivot, with ASLR off. A working ASLR-off chain and an identical-header result are not in conflict — they are about different memory. The patch that resets object_buckets is consistent with that variant, not with a stale header.

Changed in our own matrix. The Chain D row goes from UNSUPPORTED to something narrower: unsupported as a stale-store claim, with the bucket variant explicitly open.

Both languages, plus the transcript in raw/chain-d-eg-shutdown.txt.