Ejemplo n.º 1
0
    def authenticateBackend(self, tried_username=None, tried_password=None):
        """
        This is called when the frontend is authenticated, so as to give us the option to authenticate with the
        username and password given by the attacker.
        """

        # we keep these here in case frontend has authenticated and backend hasn't established the secure channel yet;
        # in that case, tried credentials are stored to be used whenever usearauth with backend can be performed
        if tried_username and tried_password:
            self.frontendTriedUsername = tried_username
            self.frontendTriedPassword = tried_password

        # do nothing if frontend is not authenticated, or backend has not established a secure channel
        if not self.factory.server.frontendAuthenticated or not self.canAuth:
            return

        # we authenticate with the backend using the credentials provided
        # TODO create the account in the backend before (contact the pool of VMs for example)
        # so these credentials from the config may not be needed after all
        username = CowrieConfig.get("proxy", "backend_user").encode()
        password = CowrieConfig.get("proxy", "backend_pass").encode()

        log.msg(f"Will auth with backend: {username}/{password}")
        self.sendPacket(5, bin_string_to_hex(b"ssh-userauth"))
        payload = (
            bin_string_to_hex(username)
            + string_to_hex("ssh-connection")
            + string_to_hex("password")
            + b"\x00"
            + bin_string_to_hex(password)
        )

        self.sendPacket(50, payload)
        self.factory.server.backendConnected = True

        # send packets from the frontend that were waiting to go to the backend
        for packet in self.factory.server.delayedPackets:
            self.factory.server.sshParse.parse_packet("[SERVER]", packet[0], packet[1])
        self.factory.server.delayedPackets = []

        # backend auth is done, attackers will now be connected to the backend
        self.authDone = True
Ejemplo n.º 2
0
    def authenticateBackend(self, tried_username=None, tried_password=None):
        """
        This is called when the frontend is authenticated, so as to give us the option to authenticate with the
        username and password given by the attacker.
        """

        # we keep these here in case frontend has authenticated and backend hasn't established the secure channel yet;
        # in that case, tried credentials are stored to be used whenever usearauth with backend can be performed
        if tried_username and tried_password:
            self.frontendTriedUsername = tried_username
            self.frontendTriedPassword = tried_password

        # do nothing if frontend is not authenticated, or backend has not established a secure channel
        if not self.factory.server.frontendAuthenticated or not self.canAuth:
            return

        # we authenticate with the backend using the credentials provided
        # TODO create the account in the backend before (contact the pool of VMs for example)
        # so these credentials from the config may not be needed after all
        username = CowrieConfig().get('proxy', 'backend_user').encode()
        password = CowrieConfig().get('proxy', 'backend_pass').encode()

        log.msg('Will auth with backend: {0}/{1}'.format(username, password))
        self.sendPacket(5, bin_string_to_hex(b'ssh-userauth'))
        payload = bin_string_to_hex(username) + \
            string_to_hex('ssh-connection') + \
            string_to_hex('password') + \
            b'\x00' + \
            bin_string_to_hex(password)

        self.sendPacket(50, payload)
        self.factory.server.backendConnected = True

        # send packets from the frontend that were waiting to go to the backend
        for packet in self.factory.server.delayedPackets:
            self.factory.server.sshParse.parse_packet('[SERVER]', packet[0],
                                                      packet[1])
        self.factory.server.delayedPackets = []
Ejemplo n.º 3
0
    def parse_packet(self, parent, message_num, payload):
        self.data = payload
        self.packetSize = len(payload)
        self.sendOn = True

        if message_num in self.packetLayout:
            packet = self.packetLayout[message_num]
        else:
            packet = 'UNKNOWN_{0}'.format(message_num)

        if parent == '[SERVER]':
            direction = 'PROXY -> BACKEND'
        else:
            direction = 'BACKEND -> PROXY'

        # log raw packets if user sets so
        if CowrieConfig().getboolean('proxy', 'log_raw', fallback=False):
            log.msg(eventid='cowrie.proxy.ssh',
                    format="%(direction)s - %(packet)s - %(payload)s",
                    direction=direction,
                    packet=packet.ljust(37),
                    payload=repr(payload),
                    protocol='ssh')

        if packet == 'SSH_MSG_SERVICE_REQUEST':
            service = self.extract_string()
            if service == b'ssh-userauth':
                self.sendOn = False

        # - UserAuth
        if packet == 'SSH_MSG_USERAUTH_REQUEST':
            self.sendOn = False
            self.username = self.extract_string()
            self.extract_string()  # service
            self.auth_type = self.extract_string()

            if self.auth_type == b'password':
                self.extract_bool()
                self.password = self.extract_string()
                # self.server.sendPacket(52, b'')

            elif self.auth_type == b'publickey':
                self.sendOn = False
                self.server.sendPacket(
                    51,
                    string_to_hex('password') + chr(0).encode())

        elif packet == 'SSH_MSG_USERAUTH_FAILURE':
            self.sendOn = False
            auth_list = self.extract_string()

            if b'publickey' in auth_list:
                log.msg('[SSH] Detected Public Key Auth - Disabling!')
                payload = string_to_hex('password') + chr(0).encode()

        elif packet == 'SSH_MSG_USERAUTH_SUCCESS':
            self.sendOn = False
            if len(self.username) > 0 and len(self.password) > 0:
                # self.server.login_successful(self.username, self.password)
                pass

        elif packet == 'SSH_MSG_USERAUTH_INFO_REQUEST':
            self.sendOn = False
            self.auth_type = b'keyboard-interactive'
            self.extract_string()
            self.extract_string()
            self.extract_string()
            num_prompts = self.extract_int(4)
            for i in range(0, num_prompts):
                request = self.extract_string()
                self.extract_bool()

                if 'password' in request.lower():
                    self.expect_password = i

        elif packet == 'SSH_MSG_USERAUTH_INFO_RESPONSE':
            self.sendOn = False
            num_responses = self.extract_int(4)
            for i in range(0, num_responses):
                response = self.extract_string()
                if i == self.expect_password:
                    self.password = response

        # - End UserAuth
        # - Channels
        elif packet == 'SSH_MSG_CHANNEL_OPEN':
            channel_type = self.extract_string()
            channel_id = self.extract_int(4)

            log.msg('got channel {} request'.format(channel_type))

            if channel_type == b'session':
                self.create_channel(parent, channel_id, channel_type)
            elif channel_type == b'direct-tcpip' or channel_type == b'forwarded-tcpip':
                self.extract_int(4)
                self.extract_int(4)

                dst_ip = self.extract_string()
                dst_port = self.extract_int(4)

                src_ip = self.extract_string()
                src_port = self.extract_int(4)

                if CowrieConfig().getboolean('ssh', 'forwarding'):
                    log.msg(
                        eventid='cowrie.direct-tcpip.request',
                        format=
                        'direct-tcp connection request to %(dst_ip)s:%(dst_port)s '
                        'from %(src_ip)s:%(src_port)s',
                        dst_ip=dst_ip,
                        dst_port=dst_port,
                        src_ip=src_ip,
                        src_port=src_port)

                    the_uuid = uuid.uuid4().hex
                    self.create_channel(parent, channel_id, channel_type)

                    if parent == '[SERVER]':
                        other_parent = '[CLIENT]'
                        the_name = '[LPRTF' + str(channel_id) + ']'
                    else:
                        other_parent = '[SERVER]'
                        the_name = '[RPRTF' + str(channel_id) + ']'

                    channel = self.get_channel(channel_id, other_parent)
                    channel['name'] = the_name
                    channel['session'] = port_forward.PortForward(
                        the_uuid, channel['name'], self)
                else:
                    log.msg(
                        '[SSH] Detected Port Forwarding Channel - Disabling!')
                    log.msg(
                        eventid='cowrie.direct-tcpip.data',
                        format=
                        'discarded direct-tcp forward request %(id)s to %(dst_ip)s:%(dst_port)s ',
                        dst_ip=dst_ip,
                        dst_port=dst_port)

                    self.sendOn = False
                    self.send_back(
                        parent, 92,
                        int_to_hex(channel_id) + int_to_hex(1) +
                        string_to_hex('open failed') + int_to_hex(0))
            else:
                # UNKNOWN CHANNEL TYPE
                if channel_type not in [b'exit-status']:
                    log.msg('[SSH Unknown Channel Type Detected - {0}'.format(
                        channel_type))

        elif packet == 'SSH_MSG_CHANNEL_OPEN_CONFIRMATION':
            channel = self.get_channel(self.extract_int(4), parent)
            # SENDER
            sender_id = self.extract_int(4)

            if parent == '[SERVER]':
                channel['serverID'] = sender_id
            elif parent == '[CLIENT]':
                channel['clientID'] = sender_id
                # CHANNEL OPENED

        elif packet == 'SSH_MSG_CHANNEL_OPEN_FAILURE':
            channel = self.get_channel(self.extract_int(4), parent)
            self.channels.remove(channel)
            # CHANNEL FAILED TO OPEN

        elif packet == 'SSH_MSG_CHANNEL_REQUEST':
            channel = self.get_channel(self.extract_int(4), parent)
            channel_type = self.extract_string()
            the_uuid = uuid.uuid4().hex

            if channel_type == b'shell':
                channel['name'] = '[TERM' + str(channel['serverID']) + ']'
                channel['session'] = term.Term(the_uuid, channel['name'], self,
                                               channel['clientID'])

            elif channel_type == b'exec':
                channel['name'] = '[EXEC' + str(channel['serverID']) + ']'
                self.extract_bool()
                command = self.extract_string()
                channel['session'] = exec_term.ExecTerm(
                    the_uuid, channel['name'], self, channel['serverID'],
                    command)

            elif channel_type == b'subsystem':
                self.extract_bool()
                subsystem = self.extract_string()

                if subsystem == b'sftp':
                    if CowrieConfig().getboolean('ssh', 'sftp_enabled'):
                        channel['name'] = '[SFTP' + str(
                            channel['serverID']) + ']'
                        # self.out.channel_opened(the_uuid, channel['name'])
                        channel['session'] = sftp.SFTP(the_uuid,
                                                       channel['name'], self)
                    else:
                        # log.msg(log.LPURPLE, '[SSH]', 'Detected SFTP Channel Request - Disabling!')
                        self.sendOn = False
                        self.send_back(parent, 100,
                                       int_to_hex(channel['serverID']))
                else:
                    # UNKNOWN SUBSYSTEM
                    log.msg('[SSH] Unknown Subsystem Type Detected - ' +
                            subsystem.decode())
            else:
                # UNKNOWN CHANNEL REQUEST TYPE
                if channel_type not in [
                        b'window-change', b'env', b'pty-req', b'exit-status',
                        b'exit-signal'
                ]:
                    log.msg(
                        '[SSH] Unknown Channel Request Type Detected - {0}'.
                        format(channel_type.decode()))

        elif packet == 'SSH_MSG_CHANNEL_FAILURE':
            pass

        elif packet == 'SSH_MSG_CHANNEL_CLOSE':
            channel = self.get_channel(self.extract_int(4), parent)
            # Is this needed?!
            channel[parent] = True

            if '[SERVER]' in channel and '[CLIENT]' in channel:
                # CHANNEL CLOSED
                if channel['session'] is not None:
                    log.msg('remote close')
                    channel['session'].channel_closed()

                self.channels.remove(channel)
        # - END Channels
        # - ChannelData
        elif packet == 'SSH_MSG_CHANNEL_DATA':
            channel = self.get_channel(self.extract_int(4), parent)
            channel['session'].parse_packet(parent, self.extract_string())

        elif packet == 'SSH_MSG_CHANNEL_EXTENDED_DATA':
            channel = self.get_channel(self.extract_int(4), parent)
            self.extract_int(4)
            channel['session'].parse_packet(parent, self.extract_string())
        # - END ChannelData

        elif packet == 'SSH_MSG_GLOBAL_REQUEST':
            channel_type = self.extract_string()
            if channel_type == b'tcpip-forward':
                if not CowrieConfig().getboolean(['ssh', 'forwarding']):
                    self.sendOn = False
                    self.send_back(parent, 82, '')

        if self.sendOn:
            if parent == '[SERVER]':
                self.client.sendPacket(message_num, payload)
            else:
                self.server.sendPacket(message_num, payload)
Ejemplo n.º 4
0
    def parse_num_packet(self, parent: str, message_num: int, payload: bytes) -> None:
        self.data = payload
        self.packetSize = len(payload)
        self.sendOn = True

        if message_num in self.packetLayout:
            packet = self.packetLayout[message_num]
        else:
            packet = f"UNKNOWN_{message_num}"

        if parent == "[SERVER]":
            direction = "PROXY -> BACKEND"
        else:
            direction = "BACKEND -> PROXY"

        # log raw packets if user sets so
        if CowrieConfig.getboolean("proxy", "log_raw", fallback=False):
            log.msg(
                eventid="cowrie.proxy.ssh",
                format="%(direction)s - %(packet)s - %(payload)s",
                direction=direction,
                packet=packet.ljust(37),
                payload=repr(payload),
                protocol="ssh",
            )

        if packet == "SSH_MSG_SERVICE_REQUEST":
            service = self.extract_string()
            if service == b"ssh-userauth":
                self.sendOn = False

        # - UserAuth
        if packet == "SSH_MSG_USERAUTH_REQUEST":
            self.sendOn = False
            self.username = self.extract_string()
            self.extract_string()  # service
            self.auth_type = self.extract_string()

            if self.auth_type == b"password":
                self.extract_bool()
                self.password = self.extract_string()
                # self.server.sendPacket(52, b'')

            elif self.auth_type == b"publickey":
                self.sendOn = False
                self.server.sendPacket(51, string_to_hex("password") + chr(0).encode())

        elif packet == "SSH_MSG_USERAUTH_FAILURE":
            self.sendOn = False
            auth_list = self.extract_string()

            if b"publickey" in auth_list:
                log.msg("[SSH] Detected Public Key Auth - Disabling!")
                payload = string_to_hex("password") + chr(0).encode()

        elif packet == "SSH_MSG_USERAUTH_SUCCESS":
            self.sendOn = False

        elif packet == "SSH_MSG_USERAUTH_INFO_REQUEST":
            self.sendOn = False
            self.auth_type = b"keyboard-interactive"
            self.extract_string()
            self.extract_string()
            self.extract_string()
            num_prompts = self.extract_int(4)
            for i in range(0, num_prompts):
                request = self.extract_string()
                self.extract_bool()

                if b"password" in request.lower():
                    self.expect_password = i

        elif packet == "SSH_MSG_USERAUTH_INFO_RESPONSE":
            self.sendOn = False
            num_responses = self.extract_int(4)
            for i in range(0, num_responses):
                response = self.extract_string()
                if i == self.expect_password:
                    self.password = response

        # - End UserAuth
        # - Channels
        elif packet == "SSH_MSG_CHANNEL_OPEN":
            channel_type = self.extract_string()
            channel_id = self.extract_int(4)

            log.msg(f"got channel {channel_type!r} request")

            if channel_type == b"session":
                # if using an interactive session reset frontend timeout
                self.server.setTimeout(
                    CowrieConfig.getint("honeypot", "interactive_timeout", fallback=300)
                )

                self.create_channel(parent, channel_id, channel_type)

            elif channel_type == b"direct-tcpip" or channel_type == b"forwarded-tcpip":
                self.extract_int(4)
                self.extract_int(4)

                dst_ip = self.extract_string()
                dst_port = self.extract_int(4)

                src_ip = self.extract_string()
                src_port = self.extract_int(4)

                if CowrieConfig.getboolean("ssh", "forwarding"):
                    log.msg(
                        eventid="cowrie.direct-tcpip.request",
                        format="direct-tcp connection request to %(dst_ip)s:%(dst_port)s "
                        "from %(src_ip)s:%(src_port)s",
                        dst_ip=dst_ip,
                        dst_port=dst_port,
                        src_ip=src_ip,
                        src_port=src_port,
                    )

                    the_uuid = uuid.uuid4().hex
                    self.create_channel(parent, channel_id, channel_type)

                    if parent == "[SERVER]":
                        other_parent = "[CLIENT]"
                        the_name = "[LPRTF" + str(channel_id) + "]"
                    else:
                        other_parent = "[SERVER]"
                        the_name = "[RPRTF" + str(channel_id) + "]"

                    channel = self.get_channel(channel_id, other_parent)
                    channel["name"] = the_name
                    channel["session"] = port_forward.PortForward(
                        the_uuid, channel["name"], self
                    )

                else:
                    log.msg("[SSH] Detected Port Forwarding Channel - Disabling!")
                    log.msg(
                        eventid="cowrie.direct-tcpip.data",
                        format="discarded direct-tcp forward request %(id)s to %(dst_ip)s:%(dst_port)s ",
                        dst_ip=dst_ip,
                        dst_port=dst_port,
                    )

                    self.sendOn = False
                    self.send_back(
                        parent,
                        92,
                        int_to_hex(channel_id)
                        + int_to_hex(1)
                        + string_to_hex("open failed")
                        + int_to_hex(0),
                    )
            else:
                # UNKNOWN CHANNEL TYPE
                if channel_type not in [b"exit-status"]:
                    log.msg(f"[SSH Unknown Channel Type Detected - {channel_type!r}")

        elif packet == "SSH_MSG_CHANNEL_OPEN_CONFIRMATION":
            channel = self.get_channel(self.extract_int(4), parent)
            # SENDER
            sender_id = self.extract_int(4)

            if parent == "[SERVER]":
                channel["serverID"] = sender_id
            elif parent == "[CLIENT]":
                channel["clientID"] = sender_id
                # CHANNEL OPENED

        elif packet == "SSH_MSG_CHANNEL_OPEN_FAILURE":
            channel = self.get_channel(self.extract_int(4), parent)
            self.channels.remove(channel)
            # CHANNEL FAILED TO OPEN

        elif packet == "SSH_MSG_CHANNEL_REQUEST":
            channel = self.get_channel(self.extract_int(4), parent)
            channel_type = self.extract_string()
            the_uuid = uuid.uuid4().hex

            if channel_type == b"shell":
                channel["name"] = "[TERM" + str(channel["serverID"]) + "]"
                channel["session"] = term.Term(
                    the_uuid, channel["name"], self, channel["clientID"]
                )

            elif channel_type == b"exec":
                channel["name"] = "[EXEC" + str(channel["serverID"]) + "]"
                self.extract_bool()
                command = self.extract_string()
                channel["session"] = exec_term.ExecTerm(
                    the_uuid, channel["name"], self, channel["serverID"], command
                )

            elif channel_type == b"subsystem":
                self.extract_bool()
                subsystem = self.extract_string()

                if subsystem == b"sftp":
                    if CowrieConfig.getboolean("ssh", "sftp_enabled"):
                        channel["name"] = "[SFTP" + str(channel["serverID"]) + "]"
                        # self.out.channel_opened(the_uuid, channel['name'])
                        channel["session"] = sftp.SFTP(the_uuid, channel["name"], self)
                    else:
                        # log.msg(log.LPURPLE, '[SSH]', 'Detected SFTP Channel Request - Disabling!')
                        self.sendOn = False
                        self.send_back(parent, 100, int_to_hex(channel["serverID"]))
                else:
                    # UNKNOWN SUBSYSTEM
                    log.msg(
                        "[SSH] Unknown Subsystem Type Detected - " + subsystem.decode()
                    )
            else:
                # UNKNOWN CHANNEL REQUEST TYPE
                if channel_type not in [
                    b"window-change",
                    b"env",
                    b"pty-req",
                    b"exit-status",
                    b"exit-signal",
                ]:
                    log.msg(
                        f"[SSH] Unknown Channel Request Type Detected - {channel_type.decode()}"
                    )

        elif packet == "SSH_MSG_CHANNEL_FAILURE":
            pass

        elif packet == "SSH_MSG_CHANNEL_CLOSE":
            channel = self.get_channel(self.extract_int(4), parent)
            # Is this needed?!
            channel[parent] = True

            if "[SERVER]" in channel and "[CLIENT]" in channel:
                # CHANNEL CLOSED
                if channel["session"] is not None:
                    log.msg("remote close")
                    channel["session"].channel_closed()

                self.channels.remove(channel)
        # - END Channels
        # - ChannelData
        elif packet == "SSH_MSG_CHANNEL_DATA":
            channel = self.get_channel(self.extract_int(4), parent)
            channel["session"].parse_packet(parent, self.extract_string())

        elif packet == "SSH_MSG_CHANNEL_EXTENDED_DATA":
            channel = self.get_channel(self.extract_int(4), parent)
            self.extract_int(4)
            channel["session"].parse_packet(parent, self.extract_string())
        # - END ChannelData

        elif packet == "SSH_MSG_GLOBAL_REQUEST":
            channel_type = self.extract_string()
            if channel_type == b"tcpip-forward":
                if not CowrieConfig.getboolean("ssh", "forwarding"):
                    self.sendOn = False
                    self.send_back(parent, 82, "")

        if self.sendOn:
            if parent == "[SERVER]":
                self.client.sendPacket(message_num, payload)
            else:
                self.server.sendPacket(message_num, payload)