PHP2Shell exploit illustrated
While there is a lot of discussion surrounding this exploit, I am yet to see an article dumbing it down enough to make it understandable for techies. Virtually every YouTuber is talking about its ramifications rather than what the exploit is on a high level. I'll provide a brief high-level overview of the exploits, and at the end I will link to more articles covering this in more depth than is provided here.
Illustration


Flow
The general flow of triggering these exploits was this:
Upload a file in PHP: These can be triggered even if the target page has no dedicated upload feature; PHP starts accepting uploads before loading the page itself.
We can then use the first exploit and make another separate error a hotbed for the second exploit.
a) The first exploit utilizes a feature of the handler of OOM(out of memory) exceptions on upload of multipart file.You need to upload a file that triggers the 128M memory limit per request of PHP requests. To trigger an OOM error, the exploit that's used is opening multiple upload requests with empty uploads. The fields are named as xyz['a']['b']['c'] which results in PHP allocating nested arrays like FILE['xyz']['a']['b']['c']. This helps the upload stay below the 8MB max POST request size of PHP while still overflowing max memory allowed to be used per request. When a overflow occurs PHP moves on without cleaning up this memory location. PHP asks for a memory of similar size as our upload chunk and it gets alloted this freed but not overwritten memory location. PHP finds a object exists there still and tries to delete it (using something called a destructor). This supposed deconstructor contains our nefarious function we prepared ahead of time.
b) As for the second exploit there was a bug in PHP that can leave the pointers of upload workers pointing to memory that's been freed when a fatal error occurs and these can be used in another request. To trigger this with our multi-file uploads though, we need to first wait for > 1sec for PHP to actually update its upload progress pointers(too fast uploads doesn't update them). Then while the upload is resumed and the data is again put in memory, the older memory location have pointers pointing to locations that have no data in them left. Exactly what we wanted
Now to finish up with the second exploit, create another upload, this time spamming similarly sized upload headers as the empty memory location (it's called heap spraying), hoping some specially crafted struct stays there.
The exploit relies on how, later, PHP goes on to reuse the variables in the worker and happens to chance upon this data that doesn't look like it is a data object. This confuses the heck out of PHP, and due to this type confusion, it ends up reading it as a trusted object. The struct that the attacker placed can contain a function pointer which can point to a custom function, thus resulting in a remote code execution exploit.
Disclaimers:
- This summary was written by me to simplify a complex C-level memory exploit; I don't have deep experience with PHP internals or exploit development. Read the source articles below for the exact low-level mechanics.
- Some details were simplified to make the article concise.
- Neither PHP nor the original exploiters have actually released a sourcecode for these exploits; some of this is based on speculation.
Further reading:
- Much of the source for this article: Akamai – Understanding PHP2Shell
- In-depth article: Calif – A Tale of Two PHP Remote Vulnerabilities
- Official Advisory & Mitigations: PHP2Shell Official Overview