(Reliable)? php2shell exploitability
Yesterday everyone was running around like crazy (me included :) because of the php2shell vulnerability.
However, after looking closely at some published PoC's - and there is an unbelievable amount of AI generated - erm, slop - it looks like building a universal, reliable, one click exploit is quite difficult (unless I'm missing something, so please do let me know).
The PoC's that have been released so far have several pre-requirements and are almost cheating.
First, in order to have a clean initial state, the one PoC that makes sense sends a POST HTTP request with a number of small fields (3000 bytes each, 1001 of them), for bulk allocation pressure, prepare PHPSESSID and PHP_SESSION_UPLOAD_PROGRESS and then append a big field of 12 MB.
This guarantees that emalloc fails, since the PoC require that memory limit is set to 8 MB.
This is the first issue; in real world setups memory_limit is usually 128 MB, making this a bit more demanding.
An even bigger issue is that real world setups will have multiple workers - the demo uses a single-worker prefork configuration which guarantees that the next phase lands with this worker. In real world this is not guaranteed and an attacker would have to consume all workers and release one (and catch that one). Not sure how difficult this is.
The next phase now (phase 1) leaks the Zend MM chunk base, which is a piece of heap, from which the 2 MB-aligned Zend MM chunk base is extracted.
This is needed for calculation of HashTable.
Then phase 2 leaks the libphp.so base address.
This is needed to defeat ASLR, but it's not the only component required. Specifically, once Apache starts, it will pick a randomized base address for libphp.so. However, offsets of other functions/pointers in libphp.so will be static.
So phase 2 will leak one specific code pointer: zval_ptr_dtor, which has a static offset from libphp.so base address. In other words, by knowing this offset, we can calculate the base address of libphp.so and defeat ASLR.
The problem here is that this depends on many factors - how libphp.so was compiled, what's the exact PHP version, distro etc).
This is where shown PoC's are "cheating" they read offsets of zval_ptr_dtor (and zif_system) from libphp.so on the server.
In real world an attacker would have to know this. I presume someone could compile list of all possible options for commonly used distro combinations.
Now in phase 3 (and I haven't thoroughly checked this one), the exploit will change pDestructor to zif_system, and this will result in execution of code. There is one limit here; the size of command can be up to 14 bytes.
As we can see, there's a lot of prerequisites here that make a reliable exploit difficult.
I'm pretty sure that smart researchers that found the vulnerability know (much) more, but clearly it's not as simple as perhaps initially thought.
The general recommendation to put session.upload_progress.enabled = 0 should help, especially since there apparently is a way to bypass even the (currently) available fix so do put this until the next update.

Comments