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
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 = []
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)
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)