for(let i=0;i<0x4000;i++){ foo(true); } new ArrayBuffer(0x7f00000);
for(int i=0;i<N;i++) msgsnd(qid[i],&msg,size,0);
POST /upload.php HTTP/1.1 Host: victim.tld Content-Length: 8192 data=%00%02%be%ef...
An encrypted copy of every freelist next, re-checked on each allocation.
Safe-unlink fd/bk checks on the doubly-linked chunk list.
Allocator hooks in zend_mm_heap made read-only at runtime.
Request data ($_GET/$_POST) moved to a separate heap zone.
How PHP allocates, and why that lets us shape the heap at all, remotely.
Spray attacker-defined raw memory the interpreter will later trust.
Put a chosen object at any offset next to the victim, in one request.
Turning the weakest possible bug, one constrained byte, into a strong primitive.
A separate allocation the overflow reaches. arData points to the split: index array on the left half, buckets on the right.
The value pointer is sprayed as a string, encoding-restricted. We control only its low bytes.
So ++/-- lands near a chosen spot, not anywhere.
Steer the constrained value at the type_flags of another zval in a sprayed array.
++/-- on a type tag → make any zval refcounted → decrement anywhere.
Zend-Oriented Programming, the interpreter's own structures become the gadget set.
flip a type tag, PHP prints the pointer
++/-- as an oracle to defeat ASLR
a destructor pointer you control
Everything so far needs a heap layout, built in one shot, with no raw bytes allowed.
One real CVE, one constrained byte, fully remote, from HTTP request to shell.
glibc iconv OOB via a normal PHP app. In practice: one byte, value pinned to 0x48–0x4D.
All four defenses on. No recon request.
The victim app is a few lines. The exploit is a heap program encoded entirely in one JSON body.
Real CVEs, all defenses on, measured for reliability, not a one-off crash.
Metadata falls, but by then the write is already strong, and the ASLR probe exposes writable structs anyway.
verdict: limitedPer-type dedicated heaps disrupt remote page-level shaping, the assumption our whole path rests on.
verdict: strongFixed-size gaps do little here. A randomized variant injects real page-level entropy.
only if randomizedReorders slots in a freelist, but page-level spraying still walks past it.
verdict: partialCheck the index stays within num_used. Kills Index Forgery at the source.
Validate the target is an aligned zend_refcounted on the PHP heap. Kills arbitrary ++/--.
Good freelist hardening. Attackers are forced off the allocator.
Built-in objects and decoder-driven layout.
PHP's hardening moved the bar. We showed where it still needs to go, and shipped two fixes toward it.