Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# via mem
# disable_functions bypass - via memory primitives

{{#include ../../../../banners/hacktricks-training.md}}

From [http://blog.safebuff.com/2016/05/06/disable-functions-bypass/](http://blog.safebuff.com/2016/05/06/disable-functions-bypass/)
Classic Linux `disable_functions` bypasses can recover runtime addresses from `/proc/self/exe`, `/proc/self/maps`, and `/proc/self/mem`, then overwrite a PLT/GOT slot so a later innocent PHP filesystem call jumps into native `system()`. The older PoC below rewrites `open@plt` and then triggers `readfile('/usr/bin/id')`, which lands in `system('/usr/bin/id')` instead.<sup>[1]</sup>

```php
<?php
Expand Down Expand Up @@ -131,7 +131,29 @@ if(fwrite($mem, packlli($system_addr))) {
echo "[-] Write failed. Exiting\n";
```

{{#include ../../../../banners/hacktricks-training.md}}
## Modern variant: engine-memory bug to native code

A stronger pattern is to first turn constrained PHP execution into an arbitrary-read primitive inside the PHP process itself. In the wp2root chain this is done with a legacy `Serializable` recursion UAF: inner and outer `unserialize()` operations share one reference table, a property-table resize frees buckets still referenced by the outer parser, and sprayed strings turn those stale references into attacker-controlled fake `zval` data. Reinterpreting the forged `zval` as a string yields arbitrary process-memory reads. For application-level gadget chains, see [PHP - Deserialization + Autoload Classes](../../../../pentesting-web/deserialization/php-deserialization-+-autoload-classes.md).<sup>[2][3]</sup>

Once arbitrary read exists, `disable_functions` stops being a boundary: the PHP-visible `system()` name may be gone, but the native handler is still resident in the worker and can be recovered from live memory and called directly. This is useful after any bug that grants PHP code execution, not only WordPress.<sup>[2][3]</sup>

## Self-resolving ROP from live PHP

Instead of relying on fixed offsets, leak any code pointer inside the loaded PHP image, walk backwards to the ELF base, parse the in-memory image, and resolve gadgets/functions dynamically. In the published chain, fake HashTable or array-destruction metadata is used as the control-transfer point: when PHP frees the forged array, cleanup pivots the stack to attacker data, runs a ROP chain, marks a payload buffer executable, and jumps into a PIC launcher. This adapts to ASLR and differing PHP builds. For generic ROP mechanics, see [ROP & JOP](../../../../binary-exploitation/rop-return-oriented-programing/README.md).<sup>[2][3]</sup>

## Fileless helper handoff

A practical post-exploitation follow-on is to keep the native payload fileless: `memfd_create("php-helper", 0)` -> `dup2(fd, 197)` -> write helper ELF -> `execveat(197, "", argv, NULL, AT_EMPTY_PATH)`. Leaving the memfd without close-on-exec preserves fd `197` across later `execve` transitions, so both the unprivileged launcher and any later privileged stub can re-enter the same in-memory helper without writing an executable to disk.<sup>[2][3]</sup>

## Root follow-on and hunting

After native execution, any local privilege escalation can be chained in. One public path keeps the helper in the memfd and uses [Copy Fail](../../../../linux-hardening/main-system-information/kernel-lpe-cves/copy-fail-af_alg-splice-page-cache-overwrite-cve-2026-31431.md) to replace the page-cached image of `/usr/bin/su`; executing `su` then runs attacker code as root while the on-disk binary remains unchanged. Useful detection points are web/PHP workers opening `/proc/self/mem`, `memfd_create`, `dup2` pinning a high FD such as `197`, `execveat(..., AT_EMPTY_PATH)`, and unexpected execution of setuid binaries from a web worker context.<sup>[2][3]</sup>



## References

- [1] [Safebuff: disable_functions bypass](http://blog.safebuff.com/2016/05/06/disable-functions-bypass/)
- [2] [Calif: The WordPress Chain Massacre: From Constrained PHP Execution to Linux Root](https://blog.calif.io/p/the-wordpress-chain-massacre)
- [3] [Calif wp2root full-chain write-up](https://github.com/califio/publications/blob/main/MADBugs/wp2root/writeups/FULL_CHAIN_WRITEUP.md)
{{#include ../../../../banners/hacktricks-training.md}}