Пример #1
0
    def bot_worker_loop(self):
        """ The bot worker thread


        """
        # send initial connection message
        mariposa_cnc = MariposaBot.cnc
        mariposa_port = MariposaBot.bot_port
        sleep(2 * 60)
        msg = MariposaProtocol.generate_initial_connect_message(
            MariposaBot.seq_num)
        NetUtility.send_message_ipv4_udp(mariposa_cnc,
                                         MariposaProtocol.MARIPOSA_PORT1, msg)
        MariposaBot.seq_num += 1
        self.logger.info("send connection request")
        # print "send connection request"
        while self.active:
            if self.state == ConnectionState.ALIVENESS_PHASE:
                # send signal
                msg = MariposaProtocol.generate_aliveness_announcement(
                    MariposaBot.seq_num)
                NetUtility.send_message_ipv4_udp(MariposaBot.connected_to,
                                                 mariposa_port, msg)
                MariposaBot.seq_num += 1
                self.logger.info("send aliveness signal")
                # print "send aliveness signal"
            sleep(4 * 60)
Пример #2
0
    def execute_orders_impl(self):
        """ Execute the stored orders.


        """
        if HelloBot.orders.target != '':
            o = HelloBot.orders
            NetUtility.send_message_ipv4_udp(o.target, o.target_port, o.message)
Пример #3
0
    def place_order_impl(self, unpacked_data):
        """ Send command to c&c server.
            Refer to print commands for details.

        :type unpacked_data: dict
        :param unpacked_data: a dict with the command
        """
        target = unpacked_data['cnc_target_host']
        target_port = unpacked_data['cnc_target_port']
        command = unpacked_data['command']
        additional_params = unpacked_data['args']
        current_seq_num = MariposaBotMaster.seq_num
        if command == "enable_google":
            msg = MariposaProtocol.generate_enable_google_message(
                current_seq_num)
        elif command == "disable_google":
            msg = MariposaProtocol.generate_disable_google_message(
                current_seq_num)
        elif command == "enable_msn":
            msg = MariposaProtocol.generate_enable_messenger_message(
                current_seq_num)
        elif command == "disable_msn":
            msg = MariposaProtocol.generate_disable_messenger_message(
                current_seq_num)
        elif command == "enable_usb":
            msg = MariposaProtocol.generate_enable_usb_spreader_message(
                current_seq_num)
        elif command == "disable_usb":
            msg = MariposaProtocol.generate_disable_usb_spreader_message(
                current_seq_num)
        elif command == "silence":
            msg = MariposaProtocol.generate_silence_channel_message(
                current_seq_num, additional_params)
        elif command == "send_ip_list":
            msg = MariposaProtocol.generate_channel_ip_list_message(
                current_seq_num)
        elif command == "update":
            msg = MariposaProtocol.generate_update_malware_message(
                current_seq_num)
        elif command == "download":
            msg = MariposaProtocol.generate_download_and_exec_message(
                current_seq_num)
        elif command == "download2":
            msg = MariposaProtocol.generate_new_alternative_download_and_exec_message(
                current_seq_num)
        elif command == "remove":
            msg = MariposaProtocol.generate_remove_bot_message(current_seq_num)
        else:
            return
        NetUtility.send_message_ipv4_udp(target, target_port, msg)
        MariposaBotMaster.seq_num += 1
Пример #4
0
    def server_acceptor_listener(self):
        """ This thread listens for incoming connections and passes them to the server_acceptor_handler method.


        """
        self.server_listener_socket = NetUtility.create_ipv4_tcp_socket(
            self.server_port, self.server_bind_address)
        while self.server_working:
            try:
                readable, writable, exceptional = select.select(
                    [self.server_listener_socket], [], [], 1)
                for c in readable:
                    s, ad = c.accept()
                    self.server_acceptor_handler(s, ad)
            # except select.error as e:
            #     self.server_logger.logger.debug("Select Error: %s", e)
            #     break
            except socket.error as e:
                self.server_logger.logger.debug("Socket Error on select: %s",
                                                e)
                # print "Socket Error: ", e.message
                break
            except RuntimeError as e:
                self.server_logger.logger.debug("Runtime Error on select: %s",
                                                e)
                # print "Runtime Error: ", e.message
                break
        self.server_logger.logger.debug("Left the acceptor-listener-loop!")
Пример #5
0
    def client_open_connection(self,
                               host,
                               port,
                               timeout=None,
                               operation_timeout=None):
        """ Opens a socket to a TCP-server.
            Will block till connection is established.


        :type port: int
        :type host: str
        :type timeout: float | None
        :type operation_timeout: float | None
        :param host: the host to connect to
        :param port: the port to connect to
        :param timeout: time to wait for till connection is established
        :param operation_timeout: time to wait for all other socket operations
        :raise RuntimeError: is raised if you attempt to open a new connection without closing an old one
        :raise socket.timeout: is raised if an connection could not be established in time
        """
        if self.client_socket_is_open is False:
            while True:
                try:
                    self.client_socket = NetUtility.open_ipv4_tcp_connection(
                        host, port, timeout, operation_timeout)
                    break
                except socket.timeout:  # handle timeouts separate
                    raise socket.timeout(
                        "Failed to establish connection in specified time!")
                except socket.error:
                    pass
            self.client_socket_is_open = True
        else:
            raise RuntimeError("socket needs to be closed first")
Пример #6
0
    def place_order_impl(self, unpacked_data):
        """ Stores a command on a server.

        :type unpacked_data: dict
        :param unpacked_data: a dict containing the orders data
        """
        try:
            receiving_host = unpacked_data['cnc_target']
            receiving_port = unpacked_data['cnc_target_port']
            command = unpacked_data['command']
            target = unpacked_data['bot_target']
            msg = unpacked_data['msg']
            cmd_string = 'place ' + command + ' ' + target + ' ' + msg
            NetUtility.send_message_ipv4_udp(receiving_host, receiving_port, cmd_string)
        except socket.error:
            pass
Пример #7
0
    def pull_orders_impl(self, src_host, src_port):
        """ Request new orders.

        :param src_host: C&C-server hosting orders
        :param src_port: servers port
        """
        try:
            if src_host is not None:
                NetUtility.send_message_ipv4_udp(src_host, src_port, 'pull')
            else:
                server, port = self.server_list.get_peer(0)
                NetUtility.send_message_ipv4_udp(server, port, 'pull')
        except KeyError:
            pass
        except socket.error:
            pass
Пример #8
0
    def server_acceptor_listener(self):
        """ This thread listens for incoming connections and passes them to the server_acceptor_handler method.


        """
        self.server_listener_socket = NetUtility.create_ipv4_udp_socket(
            self.server_port, self.server_bind_address)
        while self.server_working:
            try:
                readable, writable, exceptional = select.select(
                    [self.server_listener_socket], [], [])
                for c in readable:
                    s, ad = c.accept()
                    self.server_acceptor_handler(s, ad)
            except socket.error as e:
                print "Socket Error: ", e.message
            except RuntimeError as e:
                print "Runtime Error: ", e.message
Пример #9
0
    def agent_start(self,
                    monitor_ip='192.168.100.1',
                    monitor_port=10555,
                    bind_ip='127.0.0.1',
                    bind_port=10556,
                    request_payload_on_start=True,
                    payload_name='group'):
        """ Starts the agent.

        :type payload_name: str
        :type request_payload_on_start: bool
        :type bind_port: int
        :type bind_ip: str
        :type monitor_port: int
        :type monitor_ip: str
        :param request_payload_on_start: whether we want to bootstrap a payload on start
        :param payload_name: the name of the payload we want to bootstrap
        :param monitor_ip: ip/host where the monitor is running
        :param monitor_port: the port of the monitor
        :param bind_ip: the address we want the agent to bind to
        :param bind_port: the port we want the agent to bind to
        """
        self.active = True
        self.stopped = False
        self.payload_name = payload_name
        self.logger.info("waiting for connection to monitor...")
        # print "waiting for connection to monitor..."
        self.client_open_connection(monitor_ip, monitor_port)
        self.client_thread = threading.Thread(
            None, self.agent_client_command_processor_thread)
        self.client_thread.start()
        self.logger.info("established connection to monitor")
        # print "established connection to monitor"
        self.server_start_listener(bind_port, bind_ip)
        self.logger.info("started agent listener")
        # print "started agent listener"
        if request_payload_on_start:
            self.logger.info("beginning bootstrapping process...")
            # print "beginning bootstrapping process..."
            m = messagegenerator.generate_payload_request(0, payload_name)
            self.client_socket.send(
                NetUtility.length_prefix_message(m.SerializeToString()))
Пример #10
0
    def processor_thread(self, delegate):
        """ This thread will listen to incoming announcements from the delegates associated agent.


        :type delegate: hystck.core.agentconnectorbase.AgentConnectorBaseDelegate
        :param delegate: the delegate to work with
        :raise RuntimeError:
        """
        while self.active:
            try:
                # receive a message
                msg = NetUtility.receive_prefixed_message(delegate.agent_socket)
                m = genericmessage_pb2.GenericMessage()
                m.ParseFromString(msg)
                self.logger.debug("[%s] got message> %s", delegate.ip_address, str(m))
                # print "[", delegate.ip_address, "] got message>\n", str(m)
                # check what type of message was received
                # todo implement a function mapper
                # check if it's a announcement and set the delegates state
                if m.message_type == messagetypes_pb2.ANNOUNCE:
                    if m.HasExtension(announcemessage_pb2.status_info):
                        if m.Extensions[announcemessage_pb2.status_info].state == announcemessage_pb2.ONLINE_ENABLED:
                            delegate.state = agentconnectorbase.BotStates.enabled
                            delegate.instance_of = m.Extensions[announcemessage_pb2.status_info].instance_of
                            self.logger.info("%s changed state to enabled", delegate.ip_address)
                            # print delegate.ip_address, ' changed state to enabled'
                        elif m.Extensions[announcemessage_pb2.status_info].state == announcemessage_pb2.ONLINE_DISABLED:
                            delegate.state = agentconnectorbase.BotStates.disabled
                            delegate.instance_of = m.Extensions[announcemessage_pb2.status_info].instance_of
                            self.logger.info("%s changed state to disabled", delegate.ip_address)
                            # print delegate.ip_address, ' changed state to disabled'
                        elif announcemessage_pb2.GRACEFUL_SHUTDOWN == \
                                m.Extensions[announcemessage_pb2.status_info].state:
                            delegate.state = agentconnectorbase.BotStates.offline
                            delegate.instance_of = m.Extensions[announcemessage_pb2.status_info].instance_of
                            self.logger.info("%s changed state to offline", delegate.ip_address)
                            # print delegate.ip_address, ' changed state to offline'
                        elif m.Extensions[announcemessage_pb2.status_info].state == announcemessage_pb2.CRASHED:
                            delegate.state = agentconnectorbase.BotStates.crashed
                            delegate.instance_of = m.Extensions[announcemessage_pb2.status_info].instance_of
                            self.logger.info("%s changed state to crashed", delegate.ip_address)
                            # print delegate.ip_address, ' changed state to crashed'
                        else:
                            raise RuntimeError('unhandled announce message type')
                    else:
                        raise RuntimeError('missing extension field')
                # check if it's a payload request and try to send the requested payload to agent
                elif m.message_type == messagetypes_pb2.PAYLOAD_REQUEST:
                    if m.HasExtension(payloadmessage_pb2.payload_req):
                        gid = self.bot_registry.items[delegate.ip_address].gid
                        p = self.payload_registry.request_payload(
                            m.Extensions[payloadmessage_pb2.payload_req].payload_name, gid)
                        if p is None:
                            self.logger.warning("%s requested unregistered payload", delegate.ip_address)
                            # print "requested unregistered payload"
                            m = messagegenerator.generate_payload_message_embedded(0, str())
                            delegate.agent_socket.send(NetUtility.length_prefix_message(m.SerializeToString()))
                        elif isinstance(p, Payload):
                            if p.is_embedded:
                                m = messagegenerator.generate_payload_message_embedded(0, p.embedded_data)
                                delegate.agent_socket.send(NetUtility.length_prefix_message(m.SerializeToString()))
                            else:
                                pass
                        else:
                            pass
                # check if it's an answer and update the last received message info
                elif m.message_type == messagetypes_pb2.ANSWER:
                    if m.HasExtension(answermessage_pb2.answer_info):
                        cmd = m.Extensions[answermessage_pb2.answer_info].request
                        state = m.Extensions[answermessage_pb2.answer_info].ok
                        info = m.Extensions[answermessage_pb2.answer_info].answer
                        delegate.last_answer.update(cmd, state, info)
                # bot requested the globals
                elif m.message_type == messagetypes_pb2.GLOBALS_REQUEST:
                    m = messagegenerator.generate_globals_answer_message(0, self.globals)
                    delegate.agent_socket.send(NetUtility.length_prefix_message(m.SerializeToString()))
                else:
                    self.logger.warning("%s: Unhandled message type", delegate.ip_address)
                    # print "Unhandled message type"
            except socket.error as e:
                # excepts most likely if the socket connection is broken
                self.logger.error("Socket Error: ", e)
                # print "Socket Error: ", str(e)
                delegate.agent_socket.close()
                break
            except RuntimeError as e:
                # excepts most likely if an agent wants to close it's connection gracefully
                self.logger.warning("%s: %s", delegate.ip_address, e)
                # print e.message
                if e.message == 'unexpected connection close':
                    try:
                        delegate.agent_socket.shutdown(socket.SHUT_RDWR)
                    except socket.error:
                        pass
                    finally:
                        delegate.agent_socket.close()
                        self.logger.info("%s: socket has been closed by demand", delegate.ip_address)
                        # print 'socket has been closed by demand'
                        delegate.state = agentconnectorbase.BotStates.offline
                        self.logger.info("%s changed state to offline", delegate.ip_address)
                        # print delegate.ip_address, ' changed state to offline'
                        break
                else:
                    self.logger.error("RuntimeError: %s", e)
                    delegate.agent_socket.close()
                    break
            # except Exception as e:
            #    # a different kind of error was raised
            #    print "Error: ", e.message
            except message.Error as e:
                self.logger.error("ProtoBuf Error: %s", e)
Пример #11
0
    def handle(self):
        """ The implementation for the handler.


        """
        LoggerStatic.if_not_then_initialize("CnCRequestHandler(bot-channel)")
        data = bytearray(self.request[0])
        LoggerStatic.logger.debug("Got[%s]: %s", str(len(data)),
                                  ' '.join('{:02x}'.format(x) for x in data))
        # print "(Bot-channel) Got[" + str(len(data)) + "]:" + ' '.join('{:02x}'.format(x) for x in data)
        type_code = data[0]
        seq = str(data[1:3])
        seq_num = struct.unpack("H", seq)[0]
        if MariposaCnC.seq_num < seq_num:  # if seq num is lower update it
            MariposaCnC.seq_num = seq_num
        MariposaCnC.seq_num += 1
        if type_code == 0x61:  # join request
            # bot wants to connect
            LoggerStatic.logger.info("new join from bot: %s",
                                     self.client_address)
            # print "new join from bot: " + self.client_address[0]
            MariposaCnC.clients[
                self.client_address[0]] = ConnectionState.INIT_JOIN_SEND
            msg = MariposaProtocol.generate_initial_join_server_ack_ip_address(
                MariposaCnC.seq_num, self.client_address[0])
            # ack with remote ip
            NetUtility.send_message_ipv4_udp(self.client_address[0],
                                             MariposaCnC.bm_port, msg)
        elif type_code == 0x80:  # ack
            # bot or bot master acks a command response message, check by peer list
            if self.client_address[0] in MariposaCnC.clients:
                # bot acknowledging command, forward it to bm
                if MariposaCnC.clients[self.client_address[
                        0]] == ConnectionState.ALIVENESS_PHASE:
                    LoggerStatic.logger.info("bot acknowledges command: %s",
                                             self.client_address[0])
                    # print "bot acknowledges command: " + self.client_address[0]
                    NetUtility.send_message_ipv4_udp(MariposaCnC.bm_ip,
                                                     MariposaCnC.bm_port, data)
                else:
                    LoggerStatic.logger.info("connection half-opened: %s",
                                             self.client_address[0])
                    # print "connection half-opened: " + self.client_address[0]
            else:
                # bm acknowledging bot, do nothing
                pass
        elif type_code == 0x01:  # cmd/resp, send with sys info
            if self.client_address[0] in MariposaCnC.clients:
                # bot finalizing connection, forward to bm
                LoggerStatic.logger.info(
                    "bot finalized connection or is alive: %s",
                    self.client_address[0])
                # print "bot finalized connection or is alive: " + self.client_address[0]
                if MariposaCnC.clients[self.client_address[
                        0]] != ConnectionState.ALIVENESS_PHASE:
                    LoggerStatic.logger.info(
                        "new finalized connection, telling bot-master")
                    # print "new finalized connection, telling bot master"
                    NetUtility.send_message_ipv4_udp(MariposaCnC.bm_ip,
                                                     MariposaCnC.bm_port, data)
                MariposaCnC.clients[
                    self.client_address[0]] = ConnectionState.ALIVENESS_PHASE
                # tell bot that connection is established
                msg = MariposaProtocol.generate_initial_acknowledgement(
                    MariposaCnC.seq_num)
                NetUtility.send_message_ipv4_udp(self.client_address[0],
                                                 MariposaCnC.bm_port, msg)
            else:
                # bm sending command, broadcast to all alive peers
                LoggerStatic.logger.info("new order from bot-master")
                # print "new order from bm"
                for p, s in MariposaCnC.clients.iteritems():
                    if s == ConnectionState.ALIVENESS_PHASE:
                        NetUtility.send_message_ipv4_udp(
                            p, MariposaCnC.bm_port, data)
        else:
            pass
        MariposaCnC.seq_num += 1
Пример #12
0
    def agent_server_processor_thread(self, sock):
        """ This is the bot side message listener thread.

        :type sock: socket._socketobject
        :param sock: the socket to work with
        """
        is_graceful = False
        while self.active:
            # msg = ''
            try:
                # receive a message
                msg = NetUtility.receive_prefixed_message(sock)
                m = GenericMessage()
                m.ParseFromString(msg)
                self.logger.debug("(bot-side): got message> %s", str(m))
                # print "agent (bot-side): got message>\n", str(m)
                # check if bot wants to go down
                if m.message_type == messagetypes_pb2.ANNOUNCE:
                    if m.HasExtension(announcemessage_pb2.status_info):
                        if m.Extensions[
                                announcemessage_pb2.
                                status_info].state == announcemessage_pb2.GRACEFUL_SHUTDOWN:
                            is_graceful = True
                            self.logger.info("expecting graceful shutdown")
                            # print "expecting a graceful shutdown"
                # pass message to monitor
                self.client_socket.send(NetUtility.length_prefix_message(msg))
            except socket.error as e:
                # except this to happen if socket was close immaturely
                self.logger.warning("Socket Error: %s", e)
                # print "Socket Error: ", str(e)
                # check if we got a shutdown announcement
                if not is_graceful:
                    try:
                        # the bot crashed most likely, tell the monitor
                        self.logger.error("Instance has crashed!")
                        cm = messagegenerator.generate_announce_message(
                            0, announcemessage_pb2.CRASHED,
                            'AgentConnectorBaseDelegate')
                        self.client_socket.send(
                            NetUtility.length_prefix_message(
                                cm.SerializeToString()))
                    except socket.error:
                        pass
                    break
                # close the socket anyway since it is faulty
                self.logger.warning("Closing socket!")
                sock.close()
                self.socket_pool.remove(sock)
                break
            except RuntimeError as e:
                # except this to happen if the bot wants to close the socket
                if e.message == 'unexpected connection close':
                    try:
                        sock.shutdown(socket.SHUT_RDWR)
                    except socket.error:
                        pass
                    finally:
                        sock.close()
                        self.logger.info("socket has been closed by demand")
                        # print 'socket has been closed by demand'
                        self.socket_pool.remove(sock)
                        # check if we got a shutdown announcement
                        if not is_graceful:
                            try:
                                # the bot crash most likely, tell the monitor
                                self.logger.error("Instance has crashed!")
                                cm = messagegenerator.generate_announce_message(
                                    0, announcemessage_pb2.CRASHED,
                                    'AgentConnectorBaseDelegate')
                                self.client_socket.send(
                                    NetUtility.length_prefix_message(
                                        cm.SerializeToString()))
                            except socket.error:
                                pass
                        break
                else:
                    self.logger.error("RuntimeError: %s", e)
                    sock.close()
                    self.socket_pool.remove(sock)
                    break
            except message.Error as e:
                self.logger.error("ProtoBuf Error: %s", e)
Пример #13
0
    def agent_client_command_processor_thread(self):
        """ This is the monitor side message listener thread


        """
        while self.active is True:
            try:
                # receive a command
                msg = NetUtility.receive_prefixed_message(self.client_socket)
                m = GenericMessage()
                m.ParseFromString(msg)
                self.logger.debug("(monitor-side): got message> %s", str(m))
                # print "agent (monitor-side): got message>\n", str(m)
                # pass it on to the bot
                if m.message_type == messagetypes_pb2.PAYLOAD:
                    self.logger.info("received new payload")
                    # print "received a new payload"
                    if m.HasExtension(payloadmessage_pb2.payload_info):
                        if m.Extensions[
                                payloadmessage_pb2.
                                payload_info].source_type == payloadmessage_pb2.EMBEDDED:
                            if m.Extensions[
                                    payloadmessage_pb2.payload_info].size == 0:
                                self.logger.warning(
                                    "got the dummy payload, trying again...")
                                # print "got the dummy payload, trying again..."
                                sleep(1)
                                m = messagegenerator.generate_payload_request(
                                    0, self.payload_name)
                                self.client_socket.send(
                                    NetUtility.length_prefix_message(
                                        m.SerializeToString()))
                            else:
                                if self.bot_handle is not None:  # the current payload should be replaced
                                    self.logger.info(
                                        "old payload will be replaced")
                                    # print "old payload will be replaced"
                                    self.bot_handle.terminate()
                                    self.bot_handle = None
                                raw_payload = m.Extensions[
                                    payloadmessage_pb2.payload_info].content
                                try:
                                    f = open('tmp.zip', 'wb')
                                    f.write(raw_payload)
                                    f.flush()
                                    f.close()
                                    payloadutils.load_and_unpack('tmp.zip')
                                    meta = payloadutils.parse_meta_data()
                                    self.bot_handle = payloadutils.execute_with_metadata(
                                        meta)
                                    self.logger.info("started a new payload")
                                    # print "started a new payload"
                                except IOError as e:
                                    self.logger.error("IOError: %s", e)
                                    # print e.message
                                except OSError as e:
                                    self.logger.error("OSError: %s", e)
                        else:
                            pass
                else:
                    msg = NetUtility.length_prefix_message(
                        m.SerializeToString())
                    self.socket_pool[0].send(
                        msg
                    )  # note the first object should always be the bots socket
            except IndexError:
                # expect this to happen if no bot is running
                self.logger.error(
                    "IndexError: probably no bot-instance is running")
                # print "IndexError: probably no bot-instance is running"
            except socket.error as e:
                # except this to happen if socket was close immaturely
                self.logger.error("Socket Error: %s", e)
                # print "Socket Error: ", str(e)
                self.client_socket.close()
                break
            except RuntimeError as e:
                # except this to happen if the bot wants to close the socket
                if e.message == 'unexpected connection close':
                    try:
                        self.client_socket.shutdown(socket.SHUT_RDWR)
                    except socket.error:
                        pass
                    finally:
                        self.client_socket.close()
                        self.logger.info("socket has been closed by demand")
                        # print 'socket has been closed by demand'
                        break
                else:
                    self.logger.error("RuntimeError: %s", e)
                    self.client_socket.close()
                    break
            except message.Error as e:
                self.logger.error("ProtoBuf Error: %s", e)
                # print "ProtoBuf Error: ", e.message
        if self.bot_handle is not None:
            self.bot_handle.terminate()
            self.bot_handle = None