Beispiel #1
0
    def connectionMade(self):
        """
        Initializes the session
        """
        super(SSHProtocol, self).connectionMade()

        # Service related
        self.service_name = Config.ssh.name
        self.local_ip = Config.general.address
        self.local_port = Config.ssh.port
        self.log = log

        # Connection related
        self.user = self.terminal.transport.session.avatar
        self.remote = self.user.conn.transport.transport.client

        self._parser = FilesystemParser(Config.folder.filesystem)
        self.current_dir = expanduser("~")

        load = self.loadLoginTime(self.user.username)
        if not load:
            # Random, plausible last login time
            tdelta = timedelta(days=randint(1, 365), seconds=randint(0, 60), minutes=randint(0, 60), hours=randint(0, 24))
            now = datetime.now()
            login = now - tdelta
            loginStr = str(login.ctime())
        else:
            loginStr = load

        self.saveLoginTime(self.user.username)
        self.terminal.write("Last login: " + loginStr)
        self.terminal.nextLine()

        self.showPrompt()
Beispiel #2
0
    def connectionMade(self):
        """
        Initializes the session
        """
        super(SSHProtocol, self).connectionMade()

        self.user = self.terminal.transport.session.avatar
        self.userName = self.user.username.decode()
        self.name = config.sshName
        self.port = config.sshPort
        self._parser = FilesystemParser(config.path_to_filesys)
        self.userIP = self.user.conn.transport.transport.client[0]
        self.l = log
        self.current_dir = expanduser("~")

        load = self.loadLoginTime(self.userName)
        if load == False:
            # Zufällige, plausible last login time
            tdelta = timedelta(days=ri(1, 365),
                               seconds=ri(0, 60),
                               minutes=ri(0, 60),
                               hours=ri(0, 24))
            now = datetime.now()
            login = now - tdelta
            loginStr = str(login.ctime())
        else:
            loginStr = load

        self.saveLoginTime(self.userName)
        self.terminal.write("Last login: " + loginStr)
        self.terminal.nextLine()

        self.showPrompt()
Beispiel #3
0
 def setUp(self):
     self.ftp = FTPProtocol()
     FilesystemParser.honeytoken_directory = config.tokendir
     self.ftp._parser = FilesystemParser(config.resources + "/test_dir_sys.xml")
     self.ftp.factory = FactoryMock()
     self.ftp.transport = TransportMock()
     self.ftp.l = fakelogging
Beispiel #4
0
 def setUp(self):
     self.ssh = SSHProtocol()
     self.ssh.transport = TransportMock()
     self.ssh.terminal = TerminalBuffer()
     self.ssh.userName = "******"
     self.ssh.name = config.sshName
     self.ssh.port = config.sshPort
     FilesystemParser.honeytoken_directory = config.tokendir
     self.ssh._parser = FilesystemParser(config.resources +
                                         "/test_unix.xml")
     self.ssh.userIP = "TestIP"
     self.ssh.l = TestLogging
Beispiel #5
0
class SSHProtocol(recvline.HistoricRecvLine):

    def connectionMade(self):
        """
        Initializes the session
        """
        super(SSHProtocol, self).connectionMade()

        # Service related
        self.service_name = Config.ssh.name
        self.local_ip = Config.general.address
        self.local_port = Config.ssh.port
        self.log = log

        # Connection related
        self.user = self.terminal.transport.session.avatar
        self.remote = self.user.conn.transport.transport.client

        self._parser = FilesystemParser(Config.folder.filesystem)
        self.current_dir = expanduser("~")

        load = self.loadLoginTime(self.user.username)
        if not load:
            # Random, plausible last login time
            tdelta = timedelta(days=randint(1, 365), seconds=randint(0, 60), minutes=randint(0, 60), hours=randint(0, 24))
            now = datetime.now()
            login = now - tdelta
            loginStr = str(login.ctime())
        else:
            loginStr = load

        self.saveLoginTime(self.user.username)
        self.terminal.write("Last login: "******"user profiles" to keep an attacker from filling the memory
        if len(lastLoginTime) <= 10000:
            if Config.general.use_utc:
                lastLoginTime[username] = str(datetime.utcnow().ctime())
            else:
                lastLoginTime[username] = str(datetime.now().ctime())

    def loadLoginTime(self, username):
        if username in lastLoginTime:
            return lastLoginTime[username]
        else:
            return False

    def print(self, lines, log=None):
        """
        Prints a  response to the client's terminal
        :param lines: a line or list of lines to be printed
        :param log: string that will appear in the log file
        """
        if not isinstance(lines, list):  # if only a single line should be printed
            lines = [lines]
        for line in lines:
            self.terminal.write(line)
            self.terminal.nextLine()
        if not log:
            log = lines
        self.log.response(self.service_name, self.remote[0], self.remote[1],
                          self.local_ip, self.local_port, log, self.user.username)

    def showPrompt(self):
        """
        Show prompt at start of line.
        """
        self.terminal.write(self.user.username + "@" + Config.general.hostname + ":" + self._parser.get_formatted_path() + "$ ")

    def getCommandFunc(self, cmd):
        """
        Get the corresponding function to a command.
        :param cmd: the command to search for
        :return: the corresponding "ssh_" function
        """
        return getattr(self, 'ssh_' + cmd, None)

    def get_help(self, cmd):
        """
        Get the helptext for a command
        :param cmd:
        :return: the corresponding text
        """
        helptext = ""
        append = False
        with open(str(Config.ssh.helptext_folder)) as helps:
            for line in helps:
                if append and re.match("^\S", line):
                    return helptext
                if re.match("^" + cmd, line):
                    append = True
                if append:
                    helptext = helptext + line
        return helptext

    def handle_arguments(self, args):
        """
        Split arguments in path and list of arguments
        :param args: arguments
        :return: path, arguments
        """
        path = ""
        arguments = []

        for arg in args:
            if not arg.startswith("-"):
                path = arg
            else:
                for char in arg:
                    if char != "-":
                        arguments.append(char)
        return path, arguments

    def lineReceived(self, line):
        """
        What to do, when we receive input. Also handles real command execution.
        :param line: the line received
        """
        line = line.strip()
        if line:
            line = line.decode()

            # log call, we received a request
            self.log.request(self.service_name, self.remote[0], self.remote[1],
                             self.local_ip, self.local_port, line, self.user.username)

            res = None

            if Config.ssh.real_shell:
                # Forwarding commands to the real shell

                if "cd" in line:
                    try:
                        self.current_dir = subprocess.check_output(line + " && pwd",
                                                                   stderr=subprocess.STDOUT,
                                                                   shell=True,
                                                                   cwd=self.current_dir).decode().strip()
                    except subprocess.CalledProcessError as e:
                        res = e.output
                        res = res.decode()
                        res = res.split("\n")[:-1]
                if "exit" in line:
                    self.ssh_exit()
                else:
                    try:
                        res = subprocess.check_output(line, stderr=subprocess.STDOUT, shell=True, cwd=self.current_dir)
                    except subprocess.CalledProcessError as e:
                        res = e.output
                    res = res.decode()
                    res = res.split("\n")[:-1]

            else:
                # faking an ssh session

                cmdAndArgs = line.split()
                cmd = cmdAndArgs[0]
                args = cmdAndArgs[1:]
                func = self.getCommandFunc(cmd)
                if func:
                    try:
                        res = func(*args)
                    except Exception as e:
                        self.log.err(str(e))
                else:
                    res = cmd + ": command not found"

            if res:
                if not isinstance(res, tuple):  # If only response and no log text
                    res = (res, "")
                self.print(*res)
        self.showPrompt()

    def ssh_help(self, cmd=''):
        """
        Prints the GNU bash help for cmd or the universal help text if cmd is not given
        :param cmd: the command
        """

        if cmd:
            func = self.getCommandFunc(cmd)
            if func:
                text = self.get_help(cmd)
            if not func or not text:
                text = "help: no help topics match `{}'.  " \
                       "Try `help help' or `man -k {}' or `info {}'.".format(cmd, cmd, cmd)
            return text

        gnuhelp = []

        with open(str(Config.ssh.gnuhelp_folder)) as file:
            for line in file:
                gnuhelp.append(line)

        return gnuhelp, "Help text"

    def ssh_pwd(self):
        """
        Prints the path to the current directory in fake filesystem
        """
        return self._parser.get_current_path()

    def ssh_echo(self, *args):
        """
        Prints whatever is in args
        """
        return " ".join(args)

    def ssh_whoami(self):
        """
        prints the username
        """
        return self.user.username

    def ssh_exit(self):
        """
        close the connection
        """
        self.terminal.nextLine()
        self.terminal.loseConnection()

    def ssh_clear(self):
        """clear the terminal"""
        self.terminal.reset()

    def ssh_cd(self, *args):
        """
        Change directory in fake filesystem
        :param args: arguments and path
        """
        res = None
        if args:
            res = self._parser.cd(args[-1])
        return res

    def ssh_ls(self, *args):
        """
        Lists the content of the given directory in faked filesystem
        or of the current one if no path is given in args
        :param args: arguments and path
        """
        path, arguments = self.handle_arguments(args)

        try:
            lines = self._parser.ls(path).split("\n")[:-1]  # Split puts an empty string after the last "/n"
        except Exception:
            return "ls: " + path + ": No such file or directory."

        for line in lines:
            if line and line[0] == "." and "a" not in arguments:
                lines.remove(line)
        lines = lines

        return lines, "ls Text"

    def ssh_mkdir(self, *args):
        """
        Creates a directory in the fake filesystem
        :param args: path to be created
        :return:
        """
        return self._parser.mkdir(args[-1])

    def ssh_touch(self, *args):
        """
        Creates a file in the fake filesystem
        :param args: path to the new file
        """
        return self._parser.touch(args[-1])

    def ssh_rm(self, *args):
        """
        removes whatever is at the specified path
        :param args: arguments and path
        :return:
        """
        path, arguments = self.handle_arguments(args)

        if "r" in arguments and "f" in arguments and path == "/":
            time.sleep(4)
            self.ssh_exit()  # r e a l i s m
            return
        if self._parser.valid_directory(path) and "r" not in arguments:
            return "rm: " + args[-1] + ": is a directory"

        return self._parser.delete(path)

    def ssh_mv(self, *args):
        """
        Moves an element in the fake filesystem
        :param args: arguments, original path, new path
        """
        res = self._parser.move(args[-2], args[-1])
        if res:
            return "mv: " + res

    def ssh_cat(self, *args):
        """
        Display the content of a file
        :param args: filepath
        """
        try:
            response = self._parser.cat(args[-1])
        except Exception as e:
            if str(e) == "File not found":
                response = "cat: " + args[-1] + ": File or directory not found"
            if str(e) == "Is a directory":
                response = "cat: " + args[-1] + ": Is a directory"

        return response

    def ssh_wget(self, *args):
        """
        Downloads a file from the internet
        :param args: url
        """

        # Handle URL
        url = args[-1]
        filename = url.split('/')[-1].split('#')[0].split('?')[0]
        if not re.match(r"^https?://", url):
            url = "http://" + url
        if not re.match(r"^https?://.*\..*/", url):  # wenn die URL nichts hinter dem "/" nach der TLD hat
            filename = "index.html"

        # Determine filename
        i = 1
        while filename in os.listdir(Config.folder.quarantine):
            filename = filename + "." + str(i)
            i += 1

        # Write to disk
        filepath = ""
        if Config.ssh.accept_files:
            request.urlretrieve(url, Config.folder.quarantine / filename)
            filepath = Config.folder.quarantine / filename
        self.log.file(self.name, self.userIP, filename, filepath, self.user.username)

    def ssh_ll(self, *args):
        """
        Alias for ls -l
        :param args: arguments
        """
        return self.ssh_ls(*args + ("-l",))
Beispiel #6
0
 def __init__(self):
     self._parser = FilesystemParser()
     self.user = "******"
     self.l = hg_log
Beispiel #7
0
class FTPProtocol(FTP):
    overwritten_commands_whitelist = [
        'CWD', 'DELE', 'LIST', 'MDTM', 'MKD', 'PASS', 'PWD', 'RETR', 'RMD',
        'RNTO', 'SIZE', 'STOR', 'USER'
    ]

    inherited_commands_whitelist = [
        'FEAT', 'CDUP', 'NOOP', 'PASV', 'QUIT', 'RNFR', 'PORT', 'TYPE', 'SYST',
        'STRU', 'MODE'
    ]

    inherited_responses = {
        'FEAT': " ",
        'NOOP': RESPONSE.get(CMD_OK),
        'PASV': RESPONSE.get(ENTERING_PASV_MODE),
        'QUIT': " ",
        'RNFR': RESPONSE.get(REQ_FILE_ACTN_PENDING_FURTHER_INFO),
        'PORT': " ",
        'TYPE': " ",
        'SYST': " ",
        'STRU': " ",
        'MODE': " "
    }

    honeytokenDirectory = str(Config.folder.honeytoken_files)
    receivedDataDirectory = str(Config.folder.quarantine)

    lastmodified = dt.now()

    def __init__(self):
        self._parser = FilesystemParser()
        self.user = "******"
        self.l = hg_log

    def ftp_PWD(self):
        """
        Print current directory in faked filesystem.
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port, "PWD",
                       self.user, "PWD")
        cur = " " + self._parser.get_formatted_path()
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port, cur,
                        self.user, "PWD")
        return PWD_REPLY, cur

    def ftp_CWD(self, path):
        """
        Change current directory in faked filesystem to path
        if path is valid.

        @param path: path to navigate to
        @type path: str
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "CWD " + path, self.user, "CWD")
        if self._parser.valid_directory(path):
            self._parser.cd(path)
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(REQ_FILE_ACTN_COMPLETED_OK, "ab"),
                            self.user, "CWD")
            return (REQ_FILE_ACTN_COMPLETED_OK, )
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        RESPONSE.get(FILE_NOT_FOUND), self.user, "CWD")
        return defer.fail(FileNotFoundError(path))

    def ftp_DELE(self, path):
        """
        If path is valid path in faked filesystem, delete
        directory/file at path in faked filesystem.

        @param path: path of directory/file
        @type path: str
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "DELE " + path, self.user, "DELE")
        if self._parser.valid_path(path):
            self._parser.delete(path)
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(REQ_FILE_ACTN_COMPLETED_OK),
                            self.user, "DELE")
            return REQ_FILE_ACTN_COMPLETED_OK
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        RESPONSE.get(FILE_NOT_FOUND), self.user, "DELE")
        return defer.fail(FileNotFoundError(path))

    def ftp_LIST(self, path=''):
        """
        Return childs of directory at path in fake filesystem.
        (first 5 lines copied from twisted.protocols.ftp.FTP.ftp_LIST)

        @param path: path of directory
        @type path: str
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "LS " + path, self.user, "LS")
        if self.dtpInstance is None or not self.dtpInstance.isConnected:
            self.l.response(
                FTPService._name,
                self.transport.getPeer().host, FTPService._port,
                BAD_CMD_SEQ + ': PORT or PASV required before RETR', self.user,
                "LS")
            return defer.fail(
                BadCmdSequenceError('must send PORT or PASV before RETR'))

        if path.lower() in ['-a', '-l', '-la', '-al']:
            path = ''

        if self._parser.valid_directory(path):
            files = self._parser.ls(path).split()
            self.reply(DATA_CNX_ALREADY_OPEN_START_XFR)
            [
                self.dtpInstance.sendLine(file.encode(self._encoding))
                for file in files
            ]
            self.dtpInstance.transport.loseConnection()
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(TXFR_COMPLETE_OK), self.user, "LS")
            return (TXFR_COMPLETE_OK, )
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        RESPONSE.get(FILE_NOT_FOUND), self.user, "LS")
        return defer.fail(FileNotFoundError(path))

    def ftp_MDTM(self, path):
        """
        If path is valid path to 'file' in faked filesystem,
        return self.lastmodified.

        @param path: path to file/directory
        @type path: str
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "MDTM " + path, self.user, "MDTM")
        if self._parser.valid_path(path):
            response = self.lastmodified.strftime('%Y%m%d%H%M%S')
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            FILE_STATUS + " " + response, self.user, "MDTM")
            return (FILE_STATUS, response)
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        RESPONSE.get(FILE_NOT_FOUND), self.user, "MDTM")
        return defer.fail(FileNotFoundError(path))

    def ftp_MKD(self, name):
        """
        In faked filesystem: create a directory at path.

        @param path: new directory's path
        @type path: str
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "MKD " + name, self.user, "MKD")
        validName = not set('[~!@#$%^&*()+{}":;\']+$').intersection(name)
        if (not self._parser.valid_directory(name)) and validName:
            self._parser.mkdir(name)
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(MKD_REPLY) + " " + name, self.user,
                            "MKD")
            return (MKD_REPLY, name)
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        RESPONSE.get(FILE_NOT_FOUND), self.user, "MKD")
        return defer.fail(FileNotFoundError(name))

    def ftp_RMD(self, path):
        """
        In faked filesystem: remove directory at path.

        @param path: path to directory
        @type path: str
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "RMD " + path, self.user, "RMD")
        if self._parser.valid_directory(path):
            self._parser.delete(path)
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(REQ_FILE_ACTN_COMPLETED_OK),
                            self.user, "RMD")
            return (REQ_FILE_ACTN_COMPLETED_OK, )
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        RESPONSE.get(FILE_NOT_FOUND), self.user, "RMD")
        return defer.fail(FileNotFoundError(path))

    def ftp_RNTO(self, toName):
        """
        Renames a previously chosen file to toName.

        @param toName: new name of the file
        @type toName: str
        """
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "RNTO " + toName, self.user, "RNTO")
        fromName = self._fromName
        del self._fromName
        self.state = self.AUTHED
        validToName = not set('[~!@#$%^&*()+{}":;\']+$').intersection(toName)

        if (self._parser.valid_path(fromName)) and validToName:
            self._parser.rename(fromName, toName)
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(REQ_FILE_ACTN_COMPLETED_OK),
                            self.user, "RNTO")
            return (REQ_FILE_ACTN_COMPLETED_OK, )
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        RESPONSE.get(FILE_NOT_FOUND) % fromName, self.user,
                        "RNTO")
        return defer.fail(FileNotFoundError(fromName))

    def ftp_SIZE(self, path):
        """
        Return a random number between 100 and 5000000,
        if path is a valid path in faked filesystem.

        @param path: path to file
        @type path: str
        """
        response = ''
        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "SIZE " + path, self.user, "SIZE")
        if not self._parser.valid_path(path):
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(FILE_NOT_FOUND), self.user, "SIZE")
            return defer.fail(FileNotFoundError(path))
        if self._parser.valid_directory(path):
            response = random.randint(20000, 5000000)
        if self._parser.valid_file(path):
            response = random.randint(100, 30000)
        self.l.response(FTPService._name,
                        self.transport.getPeer().host, FTPService._port,
                        FILE_STATUS + " " + str(response), self.user, "SIZE")
        return FILE_STATUS, response

    def ftp_STOR(self, path):
        """
        Stores an uploaded  File in  self.receivedDataDirectory.

        @param path: path to file
        @type path: str
        """
        abs_path = self._parser.get_absolute_path(path)  # Windows-Mode etc.
        filename = abs_path.split("/")[-1]

        if self.dtpInstance is None:
            raise BadCmdSequenceError('PORT or PASV required before STOR')

        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "STOR " + path, self.user, "STOR")

        if not self._parser.valid_file(path):
            self._parser.touch(path)

        self.setTimeout(None)

        def enableTimeout(result):
            self.setTimeout(self.factory.timeOut)
            return result

        def cbOpened(file):
            """
            File was open for reading. Launch the data transfer channel via
            the file consumer.
            """
            d = file.receive()
            d.addCallback(cbConsumer)
            d.addCallback(lambda ignored: file.close())
            d.addCallbacks(cbSent, ebSent)
            return d

        def ebOpened(err):
            """
            Called when failed to open the file for reading.
            For known errors, return the FTP error code.
            For all other, return a file not found error.
            """
            if isinstance(err.value, FTPCmdError):
                return (err.value.errorCode, path)
            log.err(err, "Unexpected error received while opening file:")
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(FILE_NOT_FOUND), self.user, "STOR")
            return FILE_NOT_FOUND, path

        def cbConsumer(cons):
            """
            Called after the file was opended for reading.
            Prepare the data transfer channel and send the response
            to the command channel.
            """
            if not self.binary:
                cons = ASCIIConsumerWrapper(cons)

            d = self.dtpInstance.registerConsumer(cons)

            if self.dtpInstance.isConnected:
                self.reply(DATA_CNX_ALREADY_OPEN_START_XFR)
            else:
                self.reply(FILE_STATUS_OK_OPEN_DATA_CNX)
            return d

        def cbSent(result):
            """
            Called from data transport when transfer is done.
            """
            if Config.ftp.accept_files:
                self.l.file(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            filename,
                            self.receivedDataDirectory + "/" + filename,
                            self.user)
            else:
                self.l.file(FTPService._name,
                            self.transport.getPeer().host,
                            FTPService._port,
                            filename,
                            user=self.user)
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(TXFR_COMPLETE_OK), self.user, "STOR")
            return (TXFR_COMPLETE_OK, )

        def ebSent(err):
            """
            Called from data transport when there are errors during the
            transfer.
            """
            log.err(err, "Unexpected error received during transfer:")
            if err.check(FTPCmdError):
                return err
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            RESPONSE.get(CNX_CLOSED_TXFR_ABORTED), self.user,
                            "STOR")
            return (CNX_CLOSED_TXFR_ABORTED, )

        if Config.ftp.accept_files:
            i = 1
            name = filename
            while name in os.listdir(self.receivedDataDirectory):
                name = filename + "." + str(i)
                i += 1
            fObj = open(self.receivedDataDirectory + "/" + name, 'wb')
            d = defer.succeed(FW(fObj))
        else:
            d = defer.succeed()
        d.addCallbacks(cbOpened, ebOpened)
        d.addBoth(enableTimeout)

        return d

    def ftp_RETR(self, path):
        """
        This command causes the content of a file to be sent over the data
        transfer channel. If the path is to a folder, an error will be raised.

        @type path: str
        @param path: The path to the file which should be transferred over the
        data transfer channel.
        """
        if self.dtpInstance is None:
            raise BadCmdSequenceError('PORT or PASV required before RETR')

        self.l.request(FTPService._name,
                       self.transport.getPeer().host, FTPService._port,
                       "RETR " + path, self.user, "RETR")

        honeytoken_filenames = os.listdir(self.honeytokenDirectory)

        if not (self._parser.valid_file(path)
                and path in honeytoken_filenames):
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            FILE_NOT_FOUND, self.user, "RETR")
            return FILE_NOT_FOUND, path

        self.setTimeout(None)

        def enableTimeout(result):
            self.setTimeout(self.factory.timeOut)
            return result

        if not self.binary:
            cons = ASCIIConsumerWrapper(self.dtpInstance)
        else:
            cons = self.dtpInstance

        def cbSent(result):
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            TXFR_COMPLETE_OK, self.user, "RETR")
            return (TXFR_COMPLETE_OK, )

        def ebSent(err):
            log.msg("Unexpected error attempting to transmit file to client:")
            log.err(err)
            if err.check(FTPCmdError):
                return err
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            CNX_CLOSED_TXFR_ABORTED, self.user, "RETR")
            return (CNX_CLOSED_TXFR_ABORTED, )

        def cbOpened(file):
            if self.dtpInstance.isConnected:
                self.reply(DATA_CNX_ALREADY_OPEN_START_XFR)
            else:
                self.reply(FILE_STATUS_OK_OPEN_DATA_CNX)

            d = file.send(cons)
            d.addCallbacks(cbSent, ebSent)
            return d

        def ebOpened(err):
            if not err.check(PermissionDeniedError, FileNotFoundError,
                             IsADirectoryError):
                log.msg(
                    "Unexpected error attempting to open file for transmission:"
                )
                log.err(err)
            if err.check(FTPCmdError):
                return (err.value.errorCode, path)
            self.l.response(FTPService._name,
                            self.transport.getPeer().host, FTPService._port,
                            FILE_NOT_FOUND, self.user, "RETR")
            return FILE_NOT_FOUND, path

        fObj = open(self.honeytokenDirectory + '/' + path, 'rb')
        d = defer.succeed(FR(fObj))
        d.addCallbacks(cbOpened, ebOpened)
        d.addBoth(enableTimeout)

        return d

    def ftp_PASS(self, password):
        """
        Second part of login.  Get the password the peer wants to
        authenticate with.
        """
        if self.factory.allowAnonymous and self._user == self.factory.userAnonymous:
            # anonymous login
            creds = credentials.Anonymous()
            reply = GUEST_LOGGED_IN_PROCEED
        else:
            # user login
            creds = credentials.UsernamePassword(self._user, password)
            reply = USR_LOGGED_IN_PROCEED
            self.user = self._user
        del self._user

        def _cbLogin(result):
            (interface, avatar, logout) = result
            assert interface is IFTPShell, "The realm is busted, jerk."
            self.shell = avatar
            self.logout = logout
            self.workingDirectory = []
            self.state = self.AUTHED
            self.l.login(
                FTPService._name,
                self.transport.getPeer().host, FTPService._port, True,
                self.user, password,
                str(FTPService.credchecker.try_get_tokens(self.user,
                                                          password)))
            return reply

        def _ebLogin(failure):
            failure.trap(cred_error.UnauthorizedLogin,
                         cred_error.UnhandledCredentials)
            self.state = self.UNAUTH
            self.l.login(
                FTPService._name,
                self.transport.getPeer().host, FTPService._port, False,
                self.user, password,
                str(FTPService.credchecker.try_get_tokens(self.user,
                                                          password)))
            self.user = '******'
            raise AuthorizationError

        d = self.portal.login(creds, None, IFTPShell)
        d.addCallbacks(_cbLogin, _ebLogin)
        return d

    def ftp_USER(self, username):
        """
        First part of login.  Get the username the peer wants to
        authenticate as.
        """
        if not username:
            return defer.fail(CmdSyntaxError('USER requires an argument'))

        self._user = username
        self.state = self.INAUTH
        if self.factory.allowAnonymous and self._user == self.factory.userAnonymous:
            return GUEST_NAME_OK_NEED_EMAIL
        else:
            return USR_NAME_OK_NEED_PASS, username

    def processCommand(self, cmd, *params):
        """
        Processes an FTP-Command.

        @param cmd: Received FTP-Command
        @param params: Received Parameters for FTP-Command
        """
        def call_ftp_command(command):
            if command in self.overwritten_commands_whitelist:
                method = getattr(self, "ftp_" + command, None)
                return method(*params)
            if command in self.inherited_commands_whitelist:
                self.l.request(FTPService._name,
                               self.transport.getPeer().host, FTPService._port,
                               command, self.user, command)
                self.l.response(FTPService._name,
                                self.transport.getPeer().host,
                                FTPService._port,
                                self.inherited_responses.get(command),
                                self.user, command)
                method = getattr(self, "ftp_" + command, None)
                return method(*params)
            return defer.fail(CmdNotImplementedError(command))

        cmd = cmd.upper()

        if self.state == self.UNAUTH:
            if cmd == 'USER':
                return self.ftp_USER(*params)
            elif cmd == 'PASS':
                return BAD_CMD_SEQ, "USER required before PASS"
            else:
                return NOT_LOGGED_IN

        elif self.state == self.INAUTH:
            if cmd == 'PASS':
                return self.ftp_PASS(*params)
            else:
                return BAD_CMD_SEQ, "PASS required after USER"

        elif self.state == self.AUTHED:
            return call_ftp_command(cmd)

        elif self.state == self.RENAMING:
            if cmd == 'RNTO':
                return self.ftp_RNTO(*params)
            else:
                return BAD_CMD_SEQ, "RNTO required after RNFR"
Beispiel #8
0
 def setUp(self):
     FilesystemParser.honeytoken_directory = config.tokendir
     self.fp = FilesystemParser(resources._path[0] + '/test_unix.xml')
Beispiel #9
0
class FilesystemParserUnixTest(unittest.TestCase):
    def setUp(self):
        FilesystemParser.honeytoken_directory = config.tokendir
        self.fp = FilesystemParser(resources._path[0] + '/test_unix.xml')

    def test_get_absolute_path(self):
        self.assertEqual("/home/root",
                         self.fp.get_absolute_path("../../bin/../home/root"))
        self.assertEqual("/bin", self.fp.get_absolute_path("/../home/../bin"))

    def test_tree_contains(self):
        self.assertTrue(self.fp.tree_contains("id_rsa.pub"))
        self.assertFalse(self.fp.tree_contains("michgibtsnicht"))

    def test_add_honeytoken_files(self):
        self.assertTrue(self.fp.tree_contains("id_rsa"))
        self.assertTrue(self.fp.tree_contains("id_rsa.pub"))
        self.assertTrue(self.fp.tree_contains("suspicious_data.txt"))

    def test_get_element(self):
        self.assertEqual(self.fp.get_element([]).attrib['name'], "/")

    def test_get_current_path(self):
        self.fp.cd("/home/root")
        self.assertEqual(self.fp.get_current_path(), "/home/root")
        self.fp.cd("..")
        self.assertEqual(self.fp.get_current_path(), "/home")
        self.fp.cd("/")
        self.assertEqual(self.fp.get_current_path(), "/")

    def test_get_formatted_path(self):
        self.fp.cd("/home/root")
        self.assertEqual(self.fp.get_formatted_path(), "~")
        self.fp.cd("/home")
        self.assertFalse(self.fp.get_formatted_path() == "~")

    def test_mkdir(self):
        self.fp.mkdir("new_folder_01")
        self.assertTrue(self.fp.tree_contains("new_folder_01"))
        self.assertEqual(self.fp.ls().count("new_folder_01"),
                         1)  # pruefen, dass nicht mehrfach erzeugt

        self.fp.mkdir("~/new_folder_02")
        self.assertTrue(self.fp.tree_contains("new_folder_02"))
        self.fp.mkdir("../new_folder_03")
        self.assertTrue(self.fp.tree_contains("new_folder_03"))

        response = self.fp.mkdir("~/new_folder_02")
        self.assertEqual(
            response,
            "mkdir: cannot create directory 'new_folder_02': File exists")

    def test_touch(self):
        self.fp.mkdir("new_file_01")
        self.assertTrue(self.fp.tree_contains("new_file_01"))
        self.assertEqual(self.fp.ls().count("new_file_01"),
                         1)  # pruefen, dass nicht mehrfach erzeugt
        self.fp.mkdir("~/new_file_02")
        self.assertTrue(self.fp.tree_contains("new_file_02"))
        self.fp.mkdir("../new_file_03")
        self.assertTrue(self.fp.tree_contains("new_file_03"))

    def test_ls(self):
        self.assertEqual(self.fp.ls("/var"), "log\nmail\nspool\ntmp\n")
        self.assertEqual(self.fp.ls("/var/log"), "")
        self.fp.cd("~")
        self.assertEqual(self.fp.ls(".ssh"), "id_rsa\nid_rsa.pub\n")

    def test_change_dir(self):
        path = self.fp.get_current_path()  # alten Pfad merken
        self.fp.cd("./..")
        self.assertEqual(
            self.fp.get_current_path().split("/")[-1],
            path.split("/")[-2])  # neuer Pfad = alter Pfad ohne letzten /

        self.fp.cd("~")
        path = self.fp.get_current_path()  # alten Pfad merken
        self.fp.cd("../.")
        self.assertEqual(
            self.fp.get_current_path().split("/")[-1],
            path.split("/")[-2])  # neuer Pfad = alter Pfad ohne letzten /

        self.fp.cd("/")
        self.assertEqual(self.fp.get_current_path(), "/")

        self.fp.cd("~")
        self.assertEqual(self.fp.get_formatted_path(), "~")

        self.fp.cd("../..")
        self.fp.cd("../../..")
        self.assertEqual(self.fp.get_current_path(), "/")

        path = "mich/gibtsnicht"
        self.assertEqual(self.fp.cd(path),
                         path + ": No such file or directory")

        path = "~~"
        self.assertEqual(self.fp.cd(path),
                         path + ": No such file or directory")

    def test_get_absoulte_path(self):
        self.fp.cd("/home/root")
        self.assertEqual(self.fp.get_absolute_path("~"), "/home/root")
        self.assertEqual(self.fp.get_absolute_path("./."), "/home/root")
        self.assertEqual(self.fp.get_absolute_path("./"), "/home/root")
        self.assertEqual(self.fp.get_absolute_path("."), "/home/root")
        self.assertEqual(self.fp.get_absolute_path("/"), "/")
        self.assertEqual(self.fp.get_absolute_path("/home"), "/home")
        self.assertEqual(self.fp.get_absolute_path("/home/../bin"), "/bin")
        self.assertEqual(self.fp.get_absolute_path(""), "")
        self.fp.cd("/")
        self.assertEqual(self.fp.get_absolute_path("C:\\Benutzer"),
                         "/C:\\Benutzer")
        self.assertEqual(
            self.fp.get_absolute_path(
                "/#wasistdaßfür1Verzeichnis,_vong_Name_her?\\\n"),
            "/#wasistdaßfür1Verzeichnis,_vong_Name_her?\\\n")
        self.assertEqual(self.fp.get_absolute_path("/PfadDarfMitSlashEnden/"),
                         "/PfadDarfMitSlashEnden")

    def test_valid_dir(self):
        self.assertTrue(self.fp.valid_directory("/home/root"))
        self.assertTrue(self.fp.valid_directory("/home/root/"))
        self.assertTrue(self.fp.valid_directory("/"))
        self.assertTrue(self.fp.valid_directory("~"))
        self.assertTrue(self.fp.valid_directory(".."))
        self.assertTrue(self.fp.valid_directory("./.."))
        self.assertTrue(self.fp.valid_directory("../.."))
        self.assertTrue(self.fp.valid_directory("."))
        self.assertTrue(self.fp.valid_directory("./."))
        self.assertTrue(self.fp.valid_directory("../."))

        self.assertFalse(self.fp.valid_directory("..."))

    def test_valid_file(self):
        self.assertTrue(self.fp.valid_file("~/.ssh/id_rsa"))
        self.assertTrue(self.fp.valid_file("~/.ssh/id_rsa.pub"))

        self.assertFalse(self.fp.valid_file("michgibtsnicht!1!"))

    def test_delete(self):
        self.fp.cd("/")
        self.fp.mkdir("testdir")
        self.fp.cd("testdir")
        self.fp.cd("..")

        self.assertTrue("testdir" in self.fp.ls())
        self.assertEqual(self.fp.ls().count("testdir"), 1)

        self.fp.delete("testdir")
        self.assertFalse("testdir" in self.fp.ls())

        self.fp.touch("testfile")
        self.assertTrue("testfile" in self.fp.ls())
        self.assertEqual(self.fp.ls().count("testfile"), 1)

        response = self.fp.delete(".")
        self.assertEqual(
            response,
            "rm: refusing to remove '.' or '..' directory: skipping '.'")

        response = self.fp.delete("..")
        self.assertEqual(
            response,
            "rm: refusing to remove '.' or '..' directory: skipping '..'")

    def test_rename(self):
        self.fp.cd("/")
        self.fp.touch("old_name")
        self.fp.rename("old_name", "new_name")

        self.assertFalse("old_name" in self.fp.ls())

        self.assertTrue("new_name" in self.fp.ls())
        self.assertEqual(self.fp.ls().count("new_name"), 1)

    def test_move(self):
        self.fp.cd("/")
        self.fp.mkdir("testdir")
        self.fp.touch("testfile")
        response = self.fp.move("testfile", "testdir")
        self.assertEqual(response, "Not possible")

        self.fp.mkdir("testdir/testrecursive")
        self.fp.move("testdir", "/bin/testdir")
        self.assertFalse("testdir" in self.fp.ls())

        self.assertTrue("testdir" in self.fp.ls("/bin"))
        self.assertEqual(self.fp.ls("/bin").count("testdir"), 1)

        self.assertTrue("testrecursive" in self.fp.ls("/bin/testdir"))
        self.assertEqual(self.fp.ls("/bin/testdir").count("testrecursive"), 1)

    def test_cat(self):
        self.fp.cd("~")
        self.assertTrue(
            "-----BEGIN RSA PRIVATE KEY-----" in self.fp.cat(".ssh/id_rsa"))
        self.assertFalse(self.fp.cat("~/suspicious_data.txt") == "")
Beispiel #10
0
class FilesystemParserWindowsTest(unittest.TestCase):
    def setUp(self):
        FilesystemParser.honeytoken_directory = config.tokendir
        self.fp = FilesystemParser(resources._path[0] + '/test_dir_sys.xml')

    def test_get_absolute_path(self):
        self.assertEqual(self.fp.get_absolute_path("~"), "/Benutzer/TestUser")

    def test_tree_contains(self):
        self.assertTrue(self.fp.tree_contains("scan_01.jpg"))
        self.assertTrue(self.fp.tree_contains("Firefox"))
        self.assertTrue(self.fp.tree_contains("id_rsa"))
        self.assertFalse(self.fp.tree_contains("michgibtsnicht"))

    def test_add_honeytoken_files(self):
        print(self.fp.ls())
        self.assertTrue(self.fp.tree_contains("id_rsa"))
        self.assertTrue(self.fp.tree_contains("suspicious_data.txt"))

    def test_get_element(self):
        self.assertEqual(self.fp.get_element([]).attrib['name'], "C:")

    def test_get_current_path(self):
        self.fp.cd("\Programme\Firefox")
        self.assertEqual(self.fp.get_current_path(), "/Programme/Firefox")
        self.fp.cd("..")
        self.assertEqual(self.fp.get_current_path(), "/Programme")
        self.fp.cd("\\")
        self.assertEqual(self.fp.get_current_path(), "/")

    def test_mkdir(self):
        self.fp.mkdir("new_folder_01")
        self.assertTrue(self.fp.tree_contains("new_folder_01"))
        self.assertEqual(self.fp.ls().count("new_folder_01"),
                         1)  # pruefen, dass nicht mehrfach erzeugt

        self.fp.mkdir("~/new_folder_02")
        self.assertTrue(self.fp.tree_contains("new_folder_02"))
        self.fp.mkdir("../new_folder_03")
        self.assertTrue(self.fp.tree_contains("new_folder_03"))

        response = self.fp.mkdir("~/new_folder_02")
        self.assertEqual(
            response,
            "mkdir: cannot create directory 'new_folder_02': File exists")

    def test_touch(self):
        self.fp.mkdir("new_file_01")
        self.assertTrue(self.fp.tree_contains("new_file_01"))
        self.assertEqual(self.fp.ls().count("new_file_01"),
                         1)  # pruefen, dass nicht mehrfach erzeugt
        self.fp.mkdir("~/new_file_02")
        self.assertTrue(self.fp.tree_contains("new_file_02"))
        self.fp.mkdir("../new_file_03")
        self.assertTrue(self.fp.tree_contains("new_file_03"))

    def test_ls(self):
        self.assertEqual(self.fp.ls("\Benutzer\TestUser\Musik"), "asdf.mp3\n")
        self.assertEqual(self.fp.ls("~/Downloads/"), "")

    def test_change_dir(self):
        path = self.fp.get_current_path()  # alten Pfad merken
        self.fp.cd("./..")
        self.assertEqual(
            self.fp.get_current_path().split("/")[-1],
            path.split("/")[-2])  # neuer Pfad = alter Pfad ohne letzten /

        self.fp.cd("~")
        path = self.fp.get_current_path()  # alten Pfad merken
        self.fp.cd("../.")
        self.assertEqual(
            self.fp.get_current_path().split("/")[-1],
            path.split("/")[-2])  # neuer Pfad = alter Pfad ohne letzten /

        self.fp.cd("/")
        self.assertEqual(self.fp.get_current_path(), "/")

        self.fp.cd("~")
        self.assertEqual(self.fp.get_formatted_path(),
                         "C:\\Benutzer\\TestUser")

        self.fp.cd("../..")
        self.fp.cd("../../..")
        self.assertEqual(self.fp.get_current_path(), "/")

        path = "mich/gibtsnicht"
        self.assertEqual(self.fp.cd(path),
                         path + ": No such file or directory")

        path = "~~"
        self.assertEqual(self.fp.cd(path),
                         path + ": No such file or directory")

    def test_valid_dir(self):
        self.fp.cd("~")
        self.assertTrue(self.fp.valid_directory("..\..\Programme\Firefox"))
        self.assertTrue(self.fp.valid_directory("/"))
        self.assertTrue(self.fp.valid_directory("~"))
        self.assertTrue(self.fp.valid_directory(".."))
        self.assertTrue(self.fp.valid_directory("./.."))
        self.assertTrue(self.fp.valid_directory("../.."))
        self.assertTrue(self.fp.valid_directory("."))
        self.assertTrue(self.fp.valid_directory("./."))
        self.assertTrue(self.fp.valid_directory("../."))

        self.assertFalse(self.fp.valid_directory("..."))

    def test_valid_file(self):
        self.assertFalse(self.fp.valid_file("michgibtsnicht!1!"))

    def test_delete(self):
        self.fp.cd("/")
        self.fp.mkdir("testdir")
        self.fp.cd("testdir")
        self.fp.cd("..")

        self.assertTrue("testdir" in self.fp.ls())
        self.assertEqual(self.fp.ls().count("testdir"), 1)

        self.fp.delete("testdir")
        self.assertFalse("testdir" in self.fp.ls())

        self.fp.touch("testfile")
        self.assertTrue("testfile" in self.fp.ls())
        self.assertEqual(self.fp.ls().count("testfile"), 1)

        response = self.fp.delete(".")
        self.assertEqual(
            response,
            "rm: refusing to remove '.' or '..' directory: skipping '.'")

        response = self.fp.delete("..")
        self.assertEqual(
            response,
            "rm: refusing to remove '.' or '..' directory: skipping '..'")

    def test_rename(self):
        self.fp.cd("/")
        self.fp.touch("old_name")
        self.fp.rename("old_name", "new_name")

        self.assertFalse("old_name" in self.fp.ls())

        self.assertTrue("new_name" in self.fp.ls())
        self.assertEqual(self.fp.ls().count("new_name"), 1)

    def test_move(self):
        self.fp.cd("/")
        self.fp.mkdir("testdir")
        self.fp.touch("testfile")
        response = self.fp.move("testfile", "testdir")
        self.assertEqual(response, "Not possible")

        # self.fp.mkdir("testdir/testrecursive")
        # self.fp.move("testdir", "/bin/testdir")
        # self.assertFalse("testdir" in self.fp.ls())

        # self.assertTrue("testdir" in self.fp.ls("/bin"))
        # self.assertEqual(self.fp.ls("/bin").count("testdir"), 1)

        # self.assertTrue("testrecursive" in self.fp.ls("/bin/testdir"))
        # self.assertEqual(self.fp.ls("/bin/testdir").count("testrecursive"), 1)

    def test_cat(self):
        # self.assertTrue("-----BEGIN RSA PRIVATE KEY-----" in self.fp.cat("~/.ssh/id_rsa"))
        # self.assertTrue("ssh-rsa " in self.fp.cat("~/.ssh/id_rsa.pub"))
        self.assertFalse(self.fp.cat("~/suspicious_data.txt") == "")