1--TEST-- 2Bug #80111: PHP SplDoublyLinkedList::offsetUnset UAF Sandbox Escape 3--FILE-- 4<?php 5 6function i2s(&$s, $p, $i, $x=8) 7{ 8 for($j=0;$j<$x;$j++) 9 { 10 $s[$p+$j] = chr($i & 0xff); 11 $i >>= 8; 12 } 13} 14 15class Trigger 16{ 17 function __destruct() 18 { 19 global $s, $b; 20 # Add a reference afterwards 21 //$v = new SplDoublyLinkedList(); 22 //$v->setIteratorMode(SplDoublyLinkedList::IT_MODE_DELETE); 23 # Remove element #2 from the list: this has no effect on 24 # intern->traverse_pointer, since it is removed from the list already 25 # The element, along with the zval, is freed 26 unset($s[0]); 27 28 $a = str_shuffle(str_repeat('A', 40-24-1)); 29 # Build a fake zval (long, value: 12345678) 30 i2s($a, 0x00, 12345678); # ptr 31 i2s($a, 0x08, 4, 7); # type: long 32 33 var_dump($s->current()); 34 $s->next(); 35 # The value is our fake zval 36 var_dump($s->current()); 37 print_r('DONE'."\n"); 38 } 39} 40 41# Create a 3-item dllist 42$s = new SplDoublyLinkedList(); 43 44# This is the UAF trigger 45$s->push(new Trigger()); 46 47#$b = &$a; 48$s->push(3); 49 50# Points intern->traverse_pointer to our object element 51$s->rewind(); 52#$s->next(); 53 54# calls SplDoublyLinkedList::offsetUnset, which will remove the element from the 55# dllist, and then destruct the object, before clearing traverse_pointer 56unset($s[0]); 57 58?> 59--EXPECT-- 60NULL 61NULL 62DONE 63