示例#1
0
async def main_loop(args):
    ##setting up logging
    logger = Logger('Operator')
    asyncio.ensure_future(logger.run())

    mgr = MultiplexorOperator(args.connection_string, logger)
    await mgr.connect()

    ## sending commands
    if args.command == 'server':
        if args.cmd == 'list':
            reply = await mgr.list_agents()

    elif args.command == 'agent':
        if args.cmd == 'info':
            reply = await mgr.info_agent(args.agentid)

        elif args.cmd == 'list':
            reply = await mgr.list_agent_plugins(args.agentid)

    elif args.command == 'plugin':
        if args.cmd == 'info':
            reply = await mgr.info_plugin(args.agentid, args.pluginid)

    elif args.command == 'create':
        if args.type == 'socks5':
            reply = await mgr.start_socks5(args.agentid, args.listen_ip,
                                           args.listen_port, args.remote)

        elif args.type == 'sspi':
            reply = await mgr.start_socks5(args.agentid, args.listen_ip,
                                           args.listen_port, args.remote)

    await mgr.terminate()
示例#2
0
async def startup(operator_listen_ip, operator_listen_port, listen_ip, listen_port, agent_sslctx = None, operator_sslctx = None, transport_type = 'websockets'):
	try:
		logger = Logger('multiplexor_server')

		ophandler = OperatorHandler(operator_listen_ip, operator_listen_port, logger.logQ, ssl_ctx=operator_sslctx)
		if transport_type == 'websockets':
			transport = WebsocketsTransportServer(listen_ip, listen_port, logger.logQ, ssl_ctx=agent_sslctx)

		elif transport_type == 'http11':
			transport = HTTP11TransportServer(listen_ip, listen_port, logger.logQ, ssl_ctx=agent_sslctx)
		
		else:
			raise Exception('Unknown transport type! %s' % transport_type)
		
		mpserver = MultiplexorServer(logger)
		mpserver.add_transport(transport)
		mpserver.add_ophandler(ophandler)

		print(__banner__)
		print('[+] Running config:')
		print('[+] Agent service listening on    : %s:%s (%s)' % (listen_ip, listen_port, transport_type))
		print('[+] Operator service listening on : %s:%s' % (operator_listen_ip, operator_listen_port))
		print('[+] Starting server...')
		await mpserver.run()
		return True, None
	except Exception as e:
		return False, e
示例#3
0
 def __init__(self, listen_ip, listen_port, logging_queue, ssl_ctx=None):
     self.listen_ip = listen_ip
     self.listen_port = listen_port
     self.ssl_ctx = ssl_ctx
     self.logger = Logger('WebsocketsTransportServer', logQ=logging_queue)
     self.agent_dispatch_queue = None  #will be defined by the server!
     self.server = None
示例#4
0
	def __init__(self, listen_ip, listen_port, logging_queue, ssl_ctx = None):
		self.listen_ip = listen_ip
		self.listen_port = listen_port
		self.ssl_ctx = ssl_ctx
		self.logger = Logger('HTTP11TransportServer', logQ = logging_queue)
		self.agent_dispatch_queue = None #will be defined by the server!
		self.server = None
		self.agent_temp = {} #agent's own made-up ids -> transport
示例#5
0
    def __init__(self, listen_ip, listen_port, logQ, ssl_ctx=None):
        self.listen_ip = listen_ip
        self.listen_port = listen_port
        self.sslctx = ssl_ctx
        self.transport_terminated_evt = asyncio.Event()

        self.operator_dispatch_queue = None
        self.logger = Logger('multiplexor.operatorhandler', logQ=logQ)
示例#6
0
 def __init__(self, websocket, operator_id, logQ):
     self.logger = Logger('Operator %s' % operator_id, logQ=logQ)
     self.websocket = websocket
     self.operator_id = operator_id
     self.multiplexor_cmd_in = asyncio.Queue()
     self.multiplexor_cmd_out = asyncio.Queue()
     self.transport_closed = asyncio.Event()
     self.incoming_task = None
     self.outgoing_task = None
示例#7
0
    def __init__(self,
                 server_url,
                 logQ,
                 ssl_ctx=None,
                 reconnect_interval=5,
                 reconnect_tries=None):
        self.logger = Logger("Connector", logQ)
        self.server_url = server_url
        self.ssl_ctx = ssl_ctx
        self.reconnect_interval = reconnect_interval
        self.reconnect_tries = reconnect_tries

        self.cmd_out_q = asyncio.Queue()
        self.cmd_in_q = asyncio.Queue()
        self.server_connected = asyncio.Event(
        )  #this variable is used to signal status towards the modules
        self.in_task = None
        self.out_task = None
        self.current_ws = None
示例#8
0
	def __init__(self, logQ, transport, packetizer):
		self.logger = Logger('MultiplexorAgent', logQ)
		self.agent_id = None
		self.teminated_evt = asyncio.Event()
		self.transport = transport
		self.packetizer = packetizer
		
		self.plugin_ctr = 0
		self.plugins = {}
		self.plugin_taks = {}
		self.plugin_operator = {} #plugin_id -> operator
		
		self.status = AgentStatus.CONNECTED
		
		self.info = None

		self.packetizer_task = None
		self.packetizer_send_task = None
		self.packetizer_recv_task = None
示例#9
0
 async def start_logger(self):
     if self.logger is None:
         self.logger = Logger('MP Operator', sink=self.logging_sink)
         self.logger_task = asyncio.create_task(self.logger.run())
示例#10
0
class MultiplexorOperator:
    """
	This object represents an operator, who controls the multiplexor server.
	It can manage all aspects of the server, list agents, plugins etc and create plugins on the agent

	Use this for managing the server, either via command line or programaticcally using the APIs this object exposes.
	"""
    def __init__(self,
                 connection_string,
                 logger=None,
                 reconnect_tries=None,
                 logging_sink=None,
                 show_remote_logs=False):
        self.connection_string = connection_string
        self.connector = None
        self.logger = logger
        self.show_remote_logs = show_remote_logs
        self.logging_sink = logging_sink
        self.cmd_id_ctr = 0
        self.reply_buffer = {}  # cmd_id -> reply
        self.reply_buffer_evt = {}  #cmd_id -> event
        self.plugin_created_evt = {}  #agent_id -> {plugin_id -> started_event}
        self.fs_plugin_id = None

        self.connector_task = None
        self.incoming_task = None
        self.disconnected_evt = None
        self.reconnect_tries = reconnect_tries
        self.logger_task = None

    async def start_logger(self):
        if self.logger is None:
            self.logger = Logger('MP Operator', sink=self.logging_sink)
            self.logger_task = asyncio.create_task(self.logger.run())

    @mpexception
    async def handle_incoming(self):
        while True:
            try:
                reply = await self.connector.cmd_in_q.get()
                # enable line below for command debug
                #print('handle_incoming %s' % reply.to_dict())
                if reply.cmdtype in [
                        OperatorCmdType.START_PLUGIN,
                        OperatorCmdType.PLUGIN_STARTED_EVT,
                        OperatorCmdType.PLUGIN_STOPPED_EVT,
                        OperatorCmdType.LOG_EVT,
                        OperatorCmdType.PLUGIN_DATA_EVT,
                        OperatorCmdType.AGENT_CONNECTED_EVT,
                        OperatorCmdType.AGENT_DISCONNECTED_EVT
                ]:
                    if reply.cmdtype == OperatorCmdType.LOG_EVT:
                        if self.show_remote_logs is True:
                            await self.logger.log(reply.level, reply.msg)
                        try:
                            asyncio.create_task(self.on_log(reply))
                        except Exception as e:
                            await self.logger.exception()
                    elif reply.cmdtype == OperatorCmdType.PLUGIN_STARTED_EVT:
                        self.plugin_created_evt[reply.agent_id][
                            reply.plugin_id].set()
                        try:
                            asyncio.create_task(
                                self.on_plugin_start(reply.agent_id,
                                                     reply.plugin_id))
                        except Exception as e:
                            await self.logger.exception()
                    elif reply.cmdtype == OperatorCmdType.PLUGIN_STOPPED_EVT:
                        try:
                            asyncio.create_task(
                                self.on_plugin_stop(reply.agent_id,
                                                    reply.plugin_id))
                        except Exception as e:
                            await self.logger.exception()
                    elif reply.cmdtype == OperatorCmdType.AGENT_CONNECTED_EVT:
                        try:
                            asyncio.create_task(
                                self.on_agent_connect(reply.agent_id,
                                                      reply.agentinfo))
                        except Exception as e:
                            await self.logger.exception()
                    elif reply.cmdtype == OperatorCmdType.AGENT_DISCONNECTED_EVT:
                        try:
                            asyncio.create_task(
                                self.on_agent_disconnect(reply.agent_id))
                        except Exception as e:
                            await self.logger.exception()
                    continue
                else:
                    if hasattr(reply, 'cmd_id'):
                        if reply.cmd_id is not None:
                            self.reply_buffer[reply.cmd_id] = reply
                            self.reply_buffer_evt[reply.cmd_id].set()
                        else:
                            await self.logger.error(
                                'Got reply from server with empty command id!')
                    else:
                        await self.logger.error(
                            'Got reply from server without command id!')
            except Exception as e:
                #at this point something bad happened, so we are cleaning up
                #sending out the exception to all cmd ids and notifying them
                #print(str(e))
                if not isinstance(e, asyncio.CancelledError):
                    await self.logger.exception()
                for reply_id in self.reply_buffer:
                    self.reply_buffer[reply_id] = e
                for reply_id in self.reply_buffer_evt:
                    self.reply_buffer_evt[reply_id].set()
                break
        self.disconnected_evt.set()

    @mpexception
    async def recv_reply(self, cmd_id):
        #
        # Checking if cmd id is already in the buffer, if not we wait for the incoming event
        # then we take out the reply from the buffer, and delete the buffer entry and also the notification entry
        #
        #print('recv_reply called with cmd_id of %s' % cmd_id)
        if cmd_id not in self.reply_buffer:
            await self.reply_buffer_evt[cmd_id].wait()
        reply = self.reply_buffer[cmd_id]
        del self.reply_buffer[cmd_id]
        del self.reply_buffer_evt[cmd_id]
        return reply

    @mpexception
    async def send_cmd(self, cmd):
        ## assigns a command id to the command then sends the command
        ## returns the command id to the caller, which then can wait for the reply
        ##
        cmd.cmd_id = self.cmd_id_ctr
        self.reply_buffer_evt[cmd.cmd_id] = asyncio.Event()
        self.cmd_id_ctr += 1
        # enable line below for outgoing command debug
        #print('send_cmd: %s' % cmd)
        await self.connector.cmd_out_q.put(cmd)
        #print('send_cmd called and returned %s' % cmd.cmd_id)
        return cmd.cmd_id

    @mpexception
    async def connect(self):
        self.disconnected_evt = asyncio.Event()
        await self.start_logger()

        self.connector = MultiplexorOperatorConnector(
            self.connection_string,
            self.logger.logQ,
            ssl_ctx=None,
            reconnect_interval=5,
            reconnect_tries=self.reconnect_tries)
        self.connector_task = asyncio.create_task(self.connector.run())
        try:
            await asyncio.wait_for(
                self.connector.server_connected.wait(), timeout=1
            )  #waiting until connector managed to connect to the multiplexor server
        except asyncio.TimeoutError:
            asyncio.create_task(
                self.on_server_error('Server failed to connect!'))
            await self.terminate()
            raise Exception('Server failed to connect!')

        asyncio.create_task(self.on_server_connected(self.connection_string))
        self.incoming_task = asyncio.create_task(self.handle_incoming())

    @mpexception
    async def listen(self):
        await self.start_logger()

        if self.connection_string.find(':') != -1:
            listen_ip, listen_port = self.connection_string.split(':')
        else:
            listen_ip = '127.0.0.1'
            listen_port = int(self.connection_string)
        self.connector = MultiplexorOperatorListener(listen_ip,
                                                     listen_port,
                                                     self.logger.logQ,
                                                     ssl_ctx=None,
                                                     reconnect_interval=5)
        self.connector_task = asyncio.create_task(self.connector.run())
        self.incoming_task = asyncio.create_task(self.handle_incoming())

    async def terminate(self):
        await self.logger.debug('terminate called!')
        if self.incoming_task:
            self.incoming_task.cancel()
        if self.connector:
            await self.connector.terminate()
        if self.connector_task:
            self.connector_task.cancel()

        if self.logger_task:
            self.logger_task.cancel()
        self.connector_task = None

        self.connector = None
        self.cmd_id_ctr = 0
        self.reply_buffer = {}  # cmd_id -> reply
        self.reply_buffer_evt = {}  #cmd_id -> event
        return

    @mpexception
    async def list_agents(self):
        cmd = OperatorListAgentsCmd()
        cmd_id = await self.send_cmd(cmd)
        reply = await self.recv_reply(cmd_id)

        return reply.agents

    @mpexception
    async def start_socks5(self,
                           agent_id,
                           listen_ip='127.0.0.1',
                           listen_port=0,
                           remote=False):
        if remote == False:
            if agent_id not in self.plugin_created_evt:
                self.plugin_created_evt[agent_id] = {}
            cmd = OperatorStartPlugin()
            cmd.agent_id = agent_id
            cmd.plugin_type = PluginType.SOCKS5.value
            cmd.operator_token = str(uuid.uuid4())
            cmd.server = Socks5PluginServerStartupSettings(
                listen_ip=listen_ip,
                listen_port=listen_port,
                auth_type=None,
                remote=False)
            cmd_id = await self.send_cmd(cmd)
            reply = await self.recv_reply(cmd_id)

            if reply.cmdtype == OperatorCmdType.EXCEPTION:
                raise MultiplexorRemoteException(reply.exc_data)
            self.plugin_created_evt[reply.agent_id][
                reply.plugin_id] = asyncio.Event()
            await self.plugin_created_evt[reply.agent_id][
                reply.plugin_id].wait()  #waiting for the plugin creation event
            del self.plugin_created_evt[reply.agent_id][reply.plugin_id]

            reply = await self.info_plugin(agent_id, reply.plugin_id)
            return reply

        else:
            #this passes all controls over to the local sock5server object
            #exits the function when socks5 server is terminated
            so = MultiplexorSocks5Operator(self.logger.logQ, self.connector,
                                           agent_id)
            await so.run()
            return

    @mpexception
    async def start_sspi(self,
                         agent_id,
                         listen_ip='127.0.0.1',
                         listen_port=0,
                         remote=False):
        if remote == False:
            if agent_id not in self.plugin_created_evt:
                self.plugin_created_evt[agent_id] = {}
            cmd = OperatorStartPlugin()
            cmd.agent_id = agent_id
            cmd.plugin_type = PluginType.SSPI.value
            cmd.server = Socks5PluginServerStartupSettings(
                listen_ip=listen_ip,
                listen_port=listen_port,
                auth_type=None,
                remote=False)
            cmd_id = await self.send_cmd(cmd)
            reply = await self.recv_reply(cmd_id)
            if reply.cmdtype == OperatorCmdType.EXCEPTION:
                raise MultiplexorRemoteException(reply.exc_data)

            self.plugin_created_evt[reply.agent_id][
                reply.plugin_id] = asyncio.Event()
            await self.plugin_created_evt[reply.agent_id][
                reply.plugin_id].wait()  #waiting for the plugin creation event
            del self.plugin_created_evt[reply.agent_id][reply.plugin_id]

            reply = await self.info_plugin(agent_id, reply.plugin_id)
            return reply

        else:
            #this passes all controls over to the local sock5server object
            #exits the function when socks5 server is terminated
            so = MultiplexorSSPIOperator(self.logger.logQ, self.connector,
                                         agent_id)
            await so.run()
            return

    async def info_agent(self, agent_id):
        cmd = OperatorGetAgentInfoCmd(agent_id=agent_id)
        cmd_id = await self.send_cmd(cmd)
        reply = await self.recv_reply(cmd_id)
        if reply.cmdtype == OperatorCmdType.EXCEPTION:
            raise MultiplexorRemoteException(reply.exc_data)
        return reply.agentinfo

    async def list_agent_plugins(self, agent_id):
        cmd = OperatorListPluginsCmd(agent_id=agent_id)
        cmd_id = await self.send_cmd(cmd)
        reply = await self.recv_reply(cmd_id)
        if reply.cmdtype == OperatorCmdType.EXCEPTION:
            raise MultiplexorRemoteException(reply.exc_data)
        return reply.plugins

    async def info_plugin(self, agent_id, plugin_id):
        cmd = OperatorGetPluginInfoCmd(agent_id=agent_id, plugin_id=plugin_id)
        cmd_id = await self.send_cmd(cmd)
        reply = await self.recv_reply(cmd_id)
        if reply.cmdtype == OperatorCmdType.EXCEPTION:
            raise MultiplexorRemoteException(reply.exc_data)
        return reply.plugininfo

    async def run(self):
        await self.connect()
        try:
            asyncio.create_task(self.on_run())
        except Exception as e:
            await self.logger.exception()
        await self.disconnected_evt.wait()

    async def on_agent_connect(self, agent_id, agentinfo):
        pass

    async def on_agent_disconnect(self, agent_id):
        pass

    async def on_plugin_start(self, agent_id, plugin_id):
        pass

    async def on_plugin_stop(self, agent_id, plugin_id):
        pass

    async def on_log(self, log):
        pass

    async def on_server_connected(self, connection_string):
        pass

    async def on_server_error(self, reason):
        pass

    async def on_run(self):
        pass