示例#1
0
文件: tftp.py 项目: manteca/cowrie
    def makeTftpRetrieval(self):
        """
        """
        progresshook = Progress(self).progresshook

        if CONFIG.has_option('honeypot', 'download_limit_size'):
            self.limit_size = CONFIG.getint('honeypot', 'download_limit_size')

        self.artifactFile = Artifact(self.file_to_get)

        tclient = None
        url = ''

        try:
            tclient = tftpy.TftpClient(self.hostname, int(self.port))

            # tftpy can't handle unicode string as filename
            # so we have to convert unicode type to str type
            tclient.download(str(self.file_to_get), self.artifactFile,
                             progresshook)

            url = 'tftp://%s/%s' % (self.hostname, self.file_to_get.strip('/'))

            self.file_to_get = self.fs.resolve_path(self.file_to_get,
                                                    self.protocol.cwd)

            if hasattr(tclient.context, 'metrics'):
                self.fs.mkfile(self.file_to_get, 0, 0,
                               tclient.context.metrics.bytes, 33188)
            else:
                self.fs.mkfile(self.file_to_get, 0, 0, 0, 33188)

        except tftpy.TftpException:
            if tclient and tclient.context and not tclient.context.fileobj.closed:
                tclient.context.fileobj.close()

        if url:

            # log to cowrie.log
            log.msg(
                format=
                'Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
                url=url,
                outfile=self.artifactFile.shasumFilename,
                shasum=self.artifactFile.shasum)

            self.protocol.logDispatch(
                eventid='cowrie.session.file_download',
                format=
                'Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
                url=url,
                outfile=self.artifactFile.shasumFilename,
                shasum=self.artifactFile.shasum,
                destfile=self.file_to_get)

            # Update the honeyfs to point to downloaded file
            self.fs.update_realfile(self.fs.getfile(self.file_to_get),
                                    self.artifactFile.shasumFilename)
            self.fs.chown(self.file_to_get, self.protocol.user.uid,
                          self.protocol.user.gid)
示例#2
0
    def makeTftpRetrieval(self):
        progresshook = Progress(self).progresshook

        self.artifactFile = Artifact(self.file_to_get)

        tclient = None
        url = ""

        try:
            tclient = tftpy.TftpClient(self.hostname, int(self.port))

            # tftpy can't handle unicode string as filename
            # so we have to convert unicode type to str type
            tclient.download(str(self.file_to_get), self.artifactFile,
                             progresshook)

            url = "tftp://{}/{}".format(self.hostname,
                                        self.file_to_get.strip("/"))

            self.file_to_get = self.fs.resolve_path(self.file_to_get,
                                                    self.protocol.cwd)

            if hasattr(tclient.context, "metrics"):
                self.fs.mkfile(self.file_to_get, 0, 0,
                               tclient.context.metrics.bytes, 33188)
            else:
                self.fs.mkfile(self.file_to_get, 0, 0, 0, 33188)

        except tftpy.TftpException:
            if tclient and tclient.context and not tclient.context.fileobj.closed:
                tclient.context.fileobj.close()

        if url:
            # log to cowrie.log
            log.msg(
                format=
                "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
                url=url,
                outfile=self.artifactFile.shasumFilename,
                shasum=self.artifactFile.shasum,
            )

            self.protocol.logDispatch(
                eventid="cowrie.session.file_download",
                format=
                "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
                url=url,
                outfile=self.artifactFile.shasumFilename,
                shasum=self.artifactFile.shasum,
                destfile=self.file_to_get,
            )

            # Update the honeyfs to point to downloaded file
            self.fs.update_realfile(self.fs.getfile(self.file_to_get),
                                    self.artifactFile.shasumFilename)
            self.fs.chown(self.file_to_get, self.protocol.user.uid,
                          self.protocol.user.gid)
示例#3
0
    def download(self, url, fakeoutfile, *args, **kwargs):
        """
        url - URL to download
        fakeoutfile - file in guest's fs that attacker wants content to be downloaded to
        """
        try:
            parsed = compat.urllib_parse.urlparse(url)
            scheme = parsed.scheme
            host = parsed.hostname.decode('utf8')
            port = parsed.port or (443 if scheme == b'https' else 80)
            if scheme != b'http' and scheme != b'https':
                raise NotImplementedError
            if not host:
                return None
        except Exception:
            self.errorWrite('%s: Unsupported scheme.\n' % (url, ))
            return None

        # File in host's fs that will hold content of the downloaded file
        # HTTPDownloader will close() the file object so need to preserve the name
        self.artifactFile = Artifact(self.outfile)

        if not self.quiet:
            self.errorWrite(
                '--%s--  %s\n' %
                (time.strftime('%Y-%m-%d %H:%M:%S'), url.decode('utf8')))
            self.errorWrite('Connecting to %s:%d... connected.\n' %
                            (host, port))
            self.errorWrite('HTTP request sent, awaiting response... ')

        factory = HTTPProgressDownloader(self, fakeoutfile, url,
                                         self.artifactFile, *args, **kwargs)

        out_addr = None
        if CowrieConfig().has_option('honeypot', 'out_addr'):
            out_addr = (CowrieConfig().get('honeypot', 'out_addr'), 0)

        if scheme == b'https':
            context_factory = ssl.optionsForClientTLS(hostname=host)
            self.connection = reactor.connectSSL(host,
                                                 port,
                                                 factory,
                                                 context_factory,
                                                 bindAddress=out_addr)

        elif scheme == b'http':
            self.connection = reactor.connectTCP(host,
                                                 port,
                                                 factory,
                                                 bindAddress=out_addr)
        else:
            raise NotImplementedError

        return factory.deferred
示例#4
0
    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, 'cqO:P:', 'header=')
        except getopt.GetoptError:
            self.errorWrite('Unrecognized option\n')
            self.exit()
            return

        if len(args):
            url = args[0].strip()
        else:
            self.errorWrite('wget: missing URL\n')
            self.errorWrite('Usage: wget [OPTION]... [URL]...\n\n')
            self.errorWrite('Try `wget --help\' for more options.\n')
            self.exit()
            return

        outfile = None
        self.quiet = False
        for opt in optlist:
            if opt[0] == '-O':
                outfile = opt[1]
            if opt[0] == '-q':
                self.quiet = True

        # for some reason getopt doesn't recognize "-O -"
        # use try..except for the case if passed command is malformed
        try:
            if not outfile:
                if '-O' in args:
                    outfile = args[args.index('-O') + 1]
        except Exception:
            pass

        if '://' not in url:
            url = 'http://%s' % url

        urldata = compat.urllib_parse.urlparse(url)

        url = url.encode('utf8')

        if outfile is None:
            outfile = urldata.path.split('/')[-1]
            if not len(outfile.strip()) or not urldata.path.count('/'):
                outfile = 'index.html'

        if outfile != '-':
            outfile = self.fs.resolve_path(outfile, self.protocol.cwd)
            path = os.path.dirname(outfile)
            if not path or not self.fs.exists(path) or not self.fs.isdir(path):
                self.errorWrite(
                    'wget: %s: Cannot open: No such file or directory\n' %
                    outfile)
                self.exit()
                return

        self.url = url
        self.protocol.logDispatch(eventid='cowrie.session.file_download',
                                  format='Downloaded URL (%(url)s)',
                                  url=self.url)
        self.exit()
        return

        self.artifactFile = Artifact(outfile)
        # HTTPDownloader will close() the file object so need to preserve the name

        d = self.download(url, outfile, self.artifactFile)
        if d:
            d.addCallback(self.success, outfile)
            d.addErrback(self.error, url)
        else:
            self.exit()
示例#5
0
    def start(self):
        try:
            optlist, args = getopt.getopt(
                self.args, "sho:O", ["help", "manual", "silent"]
            )
        except getopt.GetoptError as err:
            # TODO: should be 'unknown' instead of 'not recognized'
            self.write(f"curl: {err}\n")
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        for opt in optlist:
            if opt[0] == "-h" or opt[0] == "--help":
                self.write(CURL_HELP)
                self.exit()
                return
            elif opt[0] == "-s" or opt[0] == "--silent":
                self.silent = True

        if len(args):
            if args[0] is not None:
                url = str(args[0]).strip()
        else:
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        if "://" not in url:
            url = "http://" + url
        urldata = compat.urllib_parse.urlparse(url)

        outfile = None
        for opt in optlist:
            if opt[0] == "-o":
                outfile = opt[1]
            if opt[0] == "-O":
                outfile = urldata.path.split("/")[-1]
                if (
                    outfile is None
                    or not len(outfile.strip())
                    or not urldata.path.count("/")
                ):
                    self.write("curl: Remote file name has no length!\n")
                    self.exit()
                    return

        if outfile:
            outfile = self.fs.resolve_path(outfile, self.protocol.cwd)
            path = os.path.dirname(outfile)
            if not path or not self.fs.exists(path) or not self.fs.isdir(path):
                self.write(
                    "curl: %s: Cannot open: No such file or directory\n" % outfile
                )
                self.exit()
                return

        url = url.encode("ascii")
        self.url = url

        self.artifactFile = Artifact(outfile)
        # HTTPDownloader will close() the file object so need to preserve the name

        self.deferred = self.download(url, outfile, self.artifactFile)
        if self.deferred:
            self.deferred.addCallback(self.success, outfile)
            self.deferred.addErrback(self.error, url)
示例#6
0
文件: ftpget.py 项目: hkarhani/cowrie
    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, "cvu:p:P:")
        except getopt.GetoptError:
            self.help()
            self.exit()
            return

        if len(args) < 2:
            self.help()
            self.exit()
            return

        self.verbose = False
        self.username = ""
        self.password = ""
        self.port = 21
        self.host = ""
        self.local_file = ""
        self.remote_path = ""

        for opt in optlist:
            if opt[0] == "-v":
                self.verbose = True
            elif opt[0] == "-u":
                self.username = opt[1]
            elif opt[0] == "-p":
                self.password = opt[1]
            elif opt[0] == "-P":
                try:
                    self.port = int(opt[1])
                except ValueError:
                    pass

        if len(args) == 2:
            self.host, self.remote_path = args
        elif len(args) >= 3:
            self.host, self.local_file, self.remote_path = args[:3]

        self.remote_dir = os.path.dirname(self.remote_path)
        self.remote_file = os.path.basename(self.remote_path)
        if not self.local_file:
            self.local_file = self.remote_file

        fakeoutfile = self.fs.resolve_path(self.local_file, self.protocol.cwd)
        path = os.path.dirname(fakeoutfile)
        if not path or not self.fs.exists(path) or not self.fs.isdir(path):
            self.write("ftpget: can't open '%s': No such file or directory" %
                       self.local_file)
            self.exit()
            return

        self.url_log = "ftp://"
        if self.username:
            self.url_log = f"{self.url_log}{self.username}"
            if self.password:
                self.url_log = f"{self.url_log}:{self.password}"
            self.url_log = f"{self.url_log}@"
        self.url_log = f"{self.url_log}{self.host}"
        if self.port != 21:
            self.url_log = f"{self.url_log}:{self.port}"
        self.url_log = f"{self.url_log}/{self.remote_path}"

        self.artifactFile = Artifact(self.local_file)

        result = self.ftp_download()

        self.artifactFile.close()

        if not result:
            # log to cowrie.log
            log.msg(
                format="Attempt to download file(s) from URL (%(url)s) failed",
                url=self.url_log,
            )

            self.protocol.logDispatch(
                eventid="cowrie.session.file_download.failed",
                format="Attempt to download file(s) from URL (%(url)s) failed",
                url=self.url_log,
            )
            self.exit()
            return

        # log to cowrie.log
        log.msg(
            format=
            "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum,
        )

        self.protocol.logDispatch(
            eventid="cowrie.session.file_download",
            format=
            "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum,
            destfile=self.local_file,
        )

        # Update the honeyfs to point to downloaded file
        self.fs.mkfile(fakeoutfile, 0, 0,
                       os.path.getsize(self.artifactFile.shasumFilename),
                       33188)
        self.fs.update_realfile(self.fs.getfile(fakeoutfile),
                                self.artifactFile.shasumFilename)
        self.fs.chown(fakeoutfile, self.protocol.user.uid,
                      self.protocol.user.gid)

        self.exit()
示例#7
0
    def start(self) -> None:
        try:
            optlist, args = getopt.getopt(
                self.args, "sho:O", ["help", "manual", "silent"]
            )
        except getopt.GetoptError as err:
            # TODO: should be 'unknown' instead of 'not recognized'
            self.write(f"curl: {err}\n")
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        for opt in optlist:
            if opt[0] == "-h" or opt[0] == "--help":
                self.write(CURL_HELP)
                self.exit()
                return
            elif opt[0] == "-s" or opt[0] == "--silent":
                self.silent = True

        if len(args):
            if args[0] is not None:
                url = str(args[0]).strip()
        else:
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        if "://" not in url:
            url = "http://" + url
        urldata = compat.urllib_parse.urlparse(url)

        for opt in optlist:
            if opt[0] == "-o":
                self.outfile = opt[1]
            if opt[0] == "-O":
                self.outfile = urldata.path.split("/")[-1]
                if (
                    self.outfile is None
                    or not len(self.outfile.strip())
                    or not urldata.path.count("/")
                ):
                    self.write("curl: Remote file name has no length!\n")
                    self.exit()
                    return

        if self.outfile:
            self.outfile = self.fs.resolve_path(self.outfile, self.protocol.cwd)
            if self.outfile:
                path = os.path.dirname(self.outfile)
            if not path or not self.fs.exists(path) or not self.fs.isdir(path):
                self.write(
                    f"curl: {self.outfile}: Cannot open: No such file or directory\n"
                )
                self.exit()
                return

        self.url = url.encode("ascii")

        parsed = compat.urllib_parse.urlparse(url)
        if parsed.hostname:
            self.host = parsed.hostname
        if parsed.scheme:
            scheme = parsed.scheme
        # port: int = parsed.port or (443 if scheme == "https" else 80)
        if scheme != "http" and scheme != "https":
            self.errorWrite(
                f'curl: (1) Protocol "{scheme}" not supported or disabled in libcurl\n'
            )
            self.exit()
            return

        # TODO: need to do full name resolution in case someon passes DNS name pointing to local address
        try:
            if ipaddress.ip_address(self.host).is_private:
                self.errorWrite(f"curl: (6) Could not resolve host: {self.host}\n")
                self.exit()
                return None
        except ValueError:
            pass

        self.artifact = Artifact("curl-download")

        self.deferred = self.treqDownload(url)
        if self.deferred:
            self.deferred.addCallback(self.success)
            self.deferred.addErrback(self.error)
示例#8
0
class Command_curl(HoneyPotCommand):
    """
    curl command
    """

    limit_size: int = CowrieConfig.getint("honeypot", "download_limit_size", fallback=0)
    outfile: Optional[str] = None  # outfile is the file saved inside the honeypot
    artifact: Artifact  # artifact is the file saved for forensics in the real file system
    currentlength: int = 0  # partial size during download
    totallength: int = 0  # total length
    silent: bool = False
    url: bytes
    host: str

    def start(self) -> None:
        try:
            optlist, args = getopt.getopt(
                self.args, "sho:O", ["help", "manual", "silent"]
            )
        except getopt.GetoptError as err:
            # TODO: should be 'unknown' instead of 'not recognized'
            self.write(f"curl: {err}\n")
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        for opt in optlist:
            if opt[0] == "-h" or opt[0] == "--help":
                self.write(CURL_HELP)
                self.exit()
                return
            elif opt[0] == "-s" or opt[0] == "--silent":
                self.silent = True

        if len(args):
            if args[0] is not None:
                url = str(args[0]).strip()
        else:
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        if "://" not in url:
            url = "http://" + url
        urldata = compat.urllib_parse.urlparse(url)

        for opt in optlist:
            if opt[0] == "-o":
                self.outfile = opt[1]
            if opt[0] == "-O":
                self.outfile = urldata.path.split("/")[-1]
                if (
                    self.outfile is None
                    or not len(self.outfile.strip())
                    or not urldata.path.count("/")
                ):
                    self.write("curl: Remote file name has no length!\n")
                    self.exit()
                    return

        if self.outfile:
            self.outfile = self.fs.resolve_path(self.outfile, self.protocol.cwd)
            if self.outfile:
                path = os.path.dirname(self.outfile)
            if not path or not self.fs.exists(path) or not self.fs.isdir(path):
                self.write(
                    f"curl: {self.outfile}: Cannot open: No such file or directory\n"
                )
                self.exit()
                return

        self.url = url.encode("ascii")

        parsed = compat.urllib_parse.urlparse(url)
        if parsed.hostname:
            self.host = parsed.hostname
        if parsed.scheme:
            scheme = parsed.scheme
        # port: int = parsed.port or (443 if scheme == "https" else 80)
        if scheme != "http" and scheme != "https":
            self.errorWrite(
                f'curl: (1) Protocol "{scheme}" not supported or disabled in libcurl\n'
            )
            self.exit()
            return

        # TODO: need to do full name resolution in case someon passes DNS name pointing to local address
        try:
            if ipaddress.ip_address(self.host).is_private:
                self.errorWrite(f"curl: (6) Could not resolve host: {self.host}\n")
                self.exit()
                return None
        except ValueError:
            pass

        self.artifact = Artifact("curl-download")

        self.deferred = self.treqDownload(url)
        if self.deferred:
            self.deferred.addCallback(self.success)
            self.deferred.addErrback(self.error)

    def treqDownload(self, url):
        """
        Download `url`
        """
        headers = {"User-Agent": ["curl/7.38.0"]}

        # TODO: use designated outbound interface
        # out_addr = None
        # if CowrieConfig.has_option("honeypot", "out_addr"):
        #     out_addr = (CowrieConfig.get("honeypot", "out_addr"), 0)

        deferred = treq.get(url=url, allow_redirects=False, headers=headers, timeout=10)
        return deferred

    def handle_CTRL_C(self):
        self.write("^C\n")
        self.exit()

    def success(self, response):
        """
        successful treq get
        """
        self.totallength = response.length
        # TODO possible this is UNKNOWN_LENGTH
        if self.limit_size > 0 and self.totallength > self.limit_size:
            log.msg(
                f"Not saving URL ({self.url}) (size: {self.totallength}) exceeds file size limit ({self.limit_size})"
            )
            self.exit()
            return

        if self.outfile and not self.silent:
            self.write(
                "  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current\n"
            )
            self.write(
                "                                 Dload  Upload   Total   Spent    Left  Speed\n"
            )

        deferred = treq.collect(response, self.collect)
        deferred.addCallback(self.collectioncomplete)
        return deferred

    def collect(self, data: bytes) -> None:
        """
        partial collect
        """
        self.currentlength += len(data)
        if self.limit_size > 0 and self.currentlength > self.limit_size:
            log.msg(
                f"Not saving URL ({self.url.decode()}) (size: {self.currentlength}) exceeds file size limit ({self.limit_size})"
            )
            self.exit()
            return

        self.artifact.write(data)

        if self.outfile and not self.silent:
            self.write(
                "\r100  {}  100  {}    0     0  {}      0 --:--:-- --:--:-- --:--:-- {}".format(
                    self.currentlength, self.currentlength, 63673, 65181
                )
            )

        if not self.outfile:
            self.writeBytes(data)

    def collectioncomplete(self, data: None) -> None:
        """
        this gets called once collection is complete
        """
        self.artifact.close()

        if self.outfile and not self.silent:
            self.write("\n")

        # Update the honeyfs to point to artifact file if output is to file
        if self.outfile:
            self.fs.mkfile(self.outfile, 0, 0, self.currentlength, 33188)
            self.fs.chown(self.outfile, self.protocol.user.uid, self.protocol.user.gid)
            self.fs.update_realfile(
                self.fs.getfile(self.outfile), self.artifact.shasumFilename
            )

        self.protocol.logDispatch(
            eventid="cowrie.session.file_download",
            format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
            url=self.url,
            filename=self.artifact.shasumFilename,
            shasum=self.artifact.shasum,
        )
        log.msg(
            eventid="cowrie.session.file_download",
            format="Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
            url=self.url,
            filename=self.artifact.shasumFilename,
            shasum=self.artifact.shasum,
        )
        self.exit()

    def error(self, response):
        """
        handle any exceptions
        """
        if response.check(error.DNSLookupError) is not None:
            self.write(f"curl: (6) Could not resolve host: {self.host}\n")
            self.exit()
            return

        # possible errors:
        # defer.CancelledError,
        # error.ConnectingCancelledError,

        log.msg(response.printTraceback())
        if hasattr(response, "getErrorMessage"):  # Exceptions
            errormsg = response.getErrorMessage()
        log.msg(errormsg)
        self.write("\n")
        self.protocol.logDispatch(
            eventid="cowrie.session.file_download.failed",
            format="Attempt to download file(s) from URL (%(url)s) failed",
            url=self.url,
        )
        self.exit()
示例#9
0
class Command_ftpget(HoneyPotCommand):
    """
    ftpget command
    """

    download_path = CowrieConfig.get("honeypot", "download_path")
    verbose: bool
    host: str
    port: int
    username: str
    password: str
    remote_path: str
    remote_dir: str
    remote_file: str
    artifactFile: Artifact

    def help(self):
        self.write(
            """BusyBox v1.20.2 (2016-06-22 15:12:53 EDT) multi-call binary.

Usage: ftpget [OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE

Download a file via FTP

    -c Continue previous transfer
    -v Verbose
    -u USER     Username
    -p PASS     Password
    -P NUM      Port\n\n""")

    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, "cvu:p:P:")
        except getopt.GetoptError:
            self.help()
            self.exit()
            return

        if len(args) < 2:
            self.help()
            self.exit()
            return

        self.verbose = False
        self.username = ""
        self.password = ""
        self.port = 21
        self.host = ""
        self.local_file = ""
        self.remote_path = ""

        for opt in optlist:
            if opt[0] == "-v":
                self.verbose = True
            elif opt[0] == "-u":
                self.username = opt[1]
            elif opt[0] == "-p":
                self.password = opt[1]
            elif opt[0] == "-P":
                try:
                    self.port = int(opt[1])
                except ValueError:
                    pass

        if len(args) == 2:
            self.host, self.remote_path = args
        elif len(args) >= 3:
            self.host, self.local_file, self.remote_path = args[:3]

        self.remote_dir = os.path.dirname(self.remote_path)
        self.remote_file = os.path.basename(self.remote_path)
        if not self.local_file:
            self.local_file = self.remote_file

        fakeoutfile = self.fs.resolve_path(self.local_file, self.protocol.cwd)
        path = os.path.dirname(fakeoutfile)
        if not path or not self.fs.exists(path) or not self.fs.isdir(path):
            self.write(
                "ftpget: can't open '{}': No such file or directory".format(
                    self.local_file))
            self.exit()
            return

        self.url_log = "ftp://"
        if self.username:
            self.url_log = f"{self.url_log}{self.username}"
            if self.password:
                self.url_log = f"{self.url_log}:{self.password}"
            self.url_log = f"{self.url_log}@"
        self.url_log = f"{self.url_log}{self.host}"
        if self.port != 21:
            self.url_log = f"{self.url_log}:{self.port}"
        self.url_log = f"{self.url_log}/{self.remote_path}"

        self.artifactFile = Artifact(self.local_file)

        result = self.ftp_download()

        self.artifactFile.close()

        if not result:
            # log to cowrie.log
            log.msg(
                format="Attempt to download file(s) from URL (%(url)s) failed",
                url=self.url_log,
            )

            self.protocol.logDispatch(
                eventid="cowrie.session.file_download.failed",
                format="Attempt to download file(s) from URL (%(url)s) failed",
                url=self.url_log,
            )
            self.exit()
            return

        # log to cowrie.log
        log.msg(
            format=
            "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum,
        )

        self.protocol.logDispatch(
            eventid="cowrie.session.file_download",
            format=
            "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s",
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum,
            destfile=self.local_file,
        )

        # Update the honeyfs to point to downloaded file
        self.fs.mkfile(fakeoutfile, 0, 0,
                       os.path.getsize(self.artifactFile.shasumFilename),
                       33188)
        self.fs.update_realfile(self.fs.getfile(fakeoutfile),
                                self.artifactFile.shasumFilename)
        self.fs.chown(fakeoutfile, self.protocol.user.uid,
                      self.protocol.user.gid)

        self.exit()

    def ftp_download(self):
        out_addr = ("", 0)
        if CowrieConfig.has_option("honeypot", "out_addr"):
            out_addr = (CowrieConfig.get("honeypot", "out_addr"), 0)

        ftp = FTP(source_address=out_addr)

        # connect
        if self.verbose:
            self.write(f"Connecting to {self.host}\n"
                       )  # TODO: add its IP address after the host

        try:
            ftp.connect(host=self.host, port=self.port, timeout=30)
        except Exception as e:
            log.msg("FTP connect failed: host={}, port={}, err={}".format(
                self.host, self.port, str(e)))
            self.write(
                "ftpget: can't connect to remote host: Connection refused\n")
            return False

        # login
        if self.verbose:
            self.write("ftpget: cmd (null) (null)\n")
            if self.username:
                self.write(f"ftpget: cmd USER {self.username}\n")
            else:
                self.write("ftpget: cmd USER anonymous\n")
            if self.password:
                self.write(f"ftpget: cmd PASS {self.password}\n")
            else:
                self.write("ftpget: cmd PASS busybox@\n")

        try:
            ftp.login(user=self.username, passwd=self.password)
        except Exception as e:
            log.msg("FTP login failed: user={}, passwd={}, err={}".format(
                self.username, self.password, str(e)))
            self.write(
                f"ftpget: unexpected server response to USER: {str(e)}\n")
            try:
                ftp.quit()
            except socket.timeout:
                pass
            return False

        # download
        if self.verbose:
            self.write("ftpget: cmd TYPE I (null)\n")
            self.write("ftpget: cmd PASV (null)\n")
            self.write(f"ftpget: cmd SIZE {self.remote_path}\n")
            self.write(f"ftpget: cmd RETR {self.remote_path}\n")

        try:
            ftp.cwd(self.remote_dir)
            ftp.retrbinary(f"RETR {self.remote_file}", self.artifactFile.write)
        except Exception as e:
            log.msg(f"FTP retrieval failed: {str(e)}")
            self.write(
                f"ftpget: unexpected server response to USER: {str(e)}\n")
            try:
                ftp.quit()
            except socket.timeout:
                pass
            return False

        # quit
        if self.verbose:
            self.write("ftpget: cmd (null) (null)\n")
            self.write("ftpget: cmd QUIT (null)\n")

        try:
            ftp.quit()
        except socket.timeout:
            pass

        return True
示例#10
0
文件: ftpget.py 项目: Mato-Z/cowrie
class command_ftpget(HoneyPotCommand):

    def help(self):
        self.write("""BusyBox v1.20.2 (2016-06-22 15:12:53 EDT) multi-call binary.

Usage: ftpget [OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE

Download a file via FTP

    -c Continue previous transfer
    -v Verbose
    -u USER     Username
    -p PASS     Password
    -P NUM      Port\n\n""")

    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, 'cvu:p:P:')
        except getopt.GetoptError:
            self.help()
            self.exit()
            return

        if len(args) < 2:
            self.help()
            self.exit()
            return

        self.verbose = False
        self.username = ''
        self.password = ''
        self.port = 21
        self.host = ''
        self.local_file = ''
        self.remote_path = ''

        for opt in optlist:
            if opt[0] == '-v':
                self.verbose = True
            elif opt[0] == '-u':
                self.username = opt[1]
            elif opt[0] == '-p':
                self.password = opt[1]
            elif opt[0] == '-P':
                try:
                    self.port = int(opt[1])
                except ValueError:
                    pass

        if len(args) == 2:
            self.host, self.remote_path = args
        elif len(args) >= 3:
            self.host, self.local_file, self.remote_path = args[:3]

        self.remote_dir = os.path.dirname(self.remote_path)
        self.remote_file = os.path.basename(self.remote_path)
        if not self.local_file:
            self.local_file = self.remote_file

        fakeoutfile = self.fs.resolve_path(self.local_file, self.protocol.cwd)
        path = os.path.dirname(fakeoutfile)
        if not path or not self.fs.exists(path) or not self.fs.isdir(path):
            self.write('ftpget: can\'t open \'%s\': No such file or directory' % self.local_file)
            self.exit()
            return

        self.download_path = CONFIG.get('honeypot', 'download_path')

        self.url_log = 'ftp://'
        if self.username:
            self.url_log = '{}{}'.format(self.url_log, self.username)
            if self.password:
                self.url_log = '{}:{}'.format(self.url_log, self.password)
            self.url_log = '{}@'.format(self.url_log)
        self.url_log = '{}{}'.format(self.url_log, self.host)
        if self.port != 21:
            self.url_log = '{}:{}'.format(self.url_log, self.port)
        self.url_log = '{}/{}'.format(self.url_log, self.remote_path)

        self.artifactFile = Artifact(self.local_file)

        result = self.ftp_download()

        self.artifactFile.close()

        if not result:
            # log to cowrie.log
            log.msg(format='Attempt to download file(s) from URL (%(url)s) failed',
                    url=self.url_log)

            self.protocol.logDispatch(eventid='cowrie.session.file_download.failed',
                                      format='Attempt to download file(s) from URL (%(url)s) failed',
                                      url=self.url_log)
            self.exit()
            return

        # log to cowrie.log
        log.msg(format='Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
                url=self.url_log,
                outfile=self.artifactFile.shasumFilename,
                shasum=self.artifactFile.shasum)

        self.protocol.logDispatch(eventid='cowrie.session.file_download',
                                  format='Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
                                  url=self.url_log,
                                  outfile=self.artifactFile.shasumFilename,
                                  shasum=self.artifactFile.shasum,
                                  destfile=self.local_file)

        # Update the honeyfs to point to downloaded file
        self.fs.mkfile(fakeoutfile, 0, 0, os.path.getsize(self.artifactFile.shasumFilename), 33188)
        self.fs.update_realfile(self.fs.getfile(fakeoutfile), self.artifactFile.shasumFilename)
        self.fs.chown(fakeoutfile, self.protocol.user.uid, self.protocol.user.gid)

        self.exit()

    def ftp_download(self):
        out_addr = ('', 0)
        if CONFIG.has_option('honeypot', 'out_addr'):
            out_addr = (CONFIG.get('honeypot', 'out_addr'), 0)

        ftp = FTP(source_address=out_addr)

        # connect
        if self.verbose:
            self.write('Connecting to %s\n' % self.host)  # TODO: add its IP address after the host

        try:
            ftp.connect(host=self.host, port=self.port, timeout=30)
        except Exception as e:
            log.msg('FTP connect failed: host=%s, port=%s, err=%s' % (self.host, self.port, str(e)))
            self.write('ftpget: can\'t connect to remote host: Connection refused\n')
            return False

        # login
        if self.verbose:
            self.write('ftpget: cmd (null) (null)\n')
            if self.username:
                self.write('ftpget: cmd USER %s\n' % self.username)
            else:
                self.write('ftpget: cmd USER anonymous\n')
            if self.password:
                self.write('ftpget: cmd PASS %s\n' % self.password)
            else:
                self.write('ftpget: cmd PASS busybox@\n')

        try:
            ftp.login(user=self.username, passwd=self.password)
        except Exception as e:
            log.msg('FTP login failed: user=%s, passwd=%s, err=%s' % (self.username, self.password, str(e)))
            self.write('ftpget: unexpected server response to USER: %s\n' % str(e))
            try:
                ftp.quit()
            except socket.timeout:
                pass
            return False

        # download
        if self.verbose:
            self.write('ftpget: cmd TYPE I (null)\n')
            self.write('ftpget: cmd PASV (null)\n')
            self.write('ftpget: cmd SIZE %s\n' % self.remote_path)
            self.write('ftpget: cmd RETR %s\n' % self.remote_path)

        try:
            ftp.cwd(self.remote_dir)
            ftp.retrbinary('RETR %s' % self.remote_file, self.artifactFile.write)
        except Exception as e:
            log.msg('FTP retrieval failed: %s' % str(e))
            self.write('ftpget: unexpected server response to USER: %s\n' % str(e))
            try:
                ftp.quit()
            except socket.timeout:
                pass
            return False

        # quit
        if self.verbose:
            self.write('ftpget: cmd (null) (null)\n')
            self.write('ftpget: cmd QUIT (null)\n')

        try:
            ftp.quit()
        except socket.timeout:
            pass

        return True
示例#11
0
    def start(self):
        url: str
        try:
            optlist, args = getopt.getopt(self.args, "cqO:P:", ["header="])
        except getopt.GetoptError:
            self.errorWrite("Unrecognized option\n")
            self.exit()
            return

        if len(args):
            url = args[0].strip()
        else:
            self.errorWrite("wget: missing URL\n")
            self.errorWrite("Usage: wget [OPTION]... [URL]...\n\n")
            self.errorWrite("Try `wget --help' for more options.\n")
            self.exit()
            return

        self.outfile: str = None
        self.quiet = False
        for opt in optlist:
            if opt[0] == "-O":
                self.outfile = opt[1]
            if opt[0] == "-q":
                self.quiet = True

        # for some reason getopt doesn't recognize "-O -"
        # use try..except for the case if passed command is malformed
        try:
            if not self.outfile:
                if "-O" in args:
                    self.outfile = args[args.index("-O") + 1]
        except Exception:
            pass

        if "://" not in url:
            url = f"http://{url}"

        urldata = compat.urllib_parse.urlparse(url)

        self.host = urldata.hostname

        # TODO: need to do full name resolution in case someon passes DNS name pointing to local address
        try:
            if ipaddress.ip_address(self.host).is_private:
                self.errorWrite(
                    f"curl: (6) Could not resolve host: {self.host}\n")
                self.exit()
                return None
        except ValueError:
            pass

        self.url = url.encode("utf8")

        if self.outfile is None:
            self.outfile = urldata.path.split("/")[-1]
            if not len(self.outfile.strip()) or not urldata.path.count("/"):
                self.outfile = "index.html"

        if self.outfile != "-":
            self.outfile = self.fs.resolve_path(self.outfile,
                                                self.protocol.cwd)
            path = os.path.dirname(self.outfile)
            if not path or not self.fs.exists(path) or not self.fs.isdir(path):
                self.errorWrite(
                    "wget: {}: Cannot open: No such file or directory\n".
                    format(self.outfile))
                self.exit()
                return

        self.artifact = Artifact("curl-download")

        if not self.quiet:
            tm = time.strftime("%Y-%m-%d %H:%M:%S")
            self.errorWrite(f"--{tm}--  {url}\n")
            self.errorWrite(
                f"Connecting to {self.host}:{urldata.port}... connected.\n")
            self.errorWrite("HTTP request sent, awaiting response... ")

        self.deferred = self.wgetDownload(url)
        if self.deferred:
            self.deferred.addCallback(self.success)
            self.deferred.addErrback(self.error)
示例#12
0
class Command_wget(HoneyPotCommand):
    """
    wget command
    """

    limit_size: int = CowrieConfig.getint("honeypot",
                                          "download_limit_size",
                                          fallback=0)
    quiet: bool = False

    outfile: Optional[
        str] = None  # outfile is the file saved inside the honeypot
    artifact: Artifact  # artifact is the file saved for forensics in the real file system
    currentlength: int = 0  # partial size during download
    totallength: int = 0  # total length
    proglen: int = 0
    url: bytes
    host: str
    started: float

    def start(self):
        url: str
        try:
            optlist, args = getopt.getopt(self.args, "cqO:P:", ["header="])
        except getopt.GetoptError:
            self.errorWrite("Unrecognized option\n")
            self.exit()
            return

        if len(args):
            url = args[0].strip()
        else:
            self.errorWrite("wget: missing URL\n")
            self.errorWrite("Usage: wget [OPTION]... [URL]...\n\n")
            self.errorWrite("Try `wget --help' for more options.\n")
            self.exit()
            return

        self.outfile: str = None
        self.quiet = False
        for opt in optlist:
            if opt[0] == "-O":
                self.outfile = opt[1]
            if opt[0] == "-q":
                self.quiet = True

        # for some reason getopt doesn't recognize "-O -"
        # use try..except for the case if passed command is malformed
        try:
            if not self.outfile:
                if "-O" in args:
                    self.outfile = args[args.index("-O") + 1]
        except Exception:
            pass

        if "://" not in url:
            url = f"http://{url}"

        urldata = compat.urllib_parse.urlparse(url)

        self.host = urldata.hostname

        # TODO: need to do full name resolution in case someon passes DNS name pointing to local address
        try:
            if ipaddress.ip_address(self.host).is_private:
                self.errorWrite(
                    f"curl: (6) Could not resolve host: {self.host}\n")
                self.exit()
                return None
        except ValueError:
            pass

        self.url = url.encode("utf8")

        if self.outfile is None:
            self.outfile = urldata.path.split("/")[-1]
            if not len(self.outfile.strip()) or not urldata.path.count("/"):
                self.outfile = "index.html"

        if self.outfile != "-":
            self.outfile = self.fs.resolve_path(self.outfile,
                                                self.protocol.cwd)
            path = os.path.dirname(self.outfile)
            if not path or not self.fs.exists(path) or not self.fs.isdir(path):
                self.errorWrite(
                    "wget: {}: Cannot open: No such file or directory\n".
                    format(self.outfile))
                self.exit()
                return

        self.artifact = Artifact("curl-download")

        if not self.quiet:
            tm = time.strftime("%Y-%m-%d %H:%M:%S")
            self.errorWrite(f"--{tm}--  {url}\n")
            self.errorWrite(
                f"Connecting to {self.host}:{urldata.port}... connected.\n")
            self.errorWrite("HTTP request sent, awaiting response... ")

        self.deferred = self.wgetDownload(url)
        if self.deferred:
            self.deferred.addCallback(self.success)
            self.deferred.addErrback(self.error)

    def wgetDownload(self, url):
        """
        Download `url`
        """
        headers = {"User-Agent": ["curl/7.38.0"]}

        # TODO: use designated outbound interface
        # out_addr = None
        # if CowrieConfig.has_option("honeypot", "out_addr"):
        #     out_addr = (CowrieConfig.get("honeypot", "out_addr"), 0)

        deferred = treq.get(url=url,
                            allow_redirects=True,
                            headers=headers,
                            timeout=10)
        return deferred

    def handle_CTRL_C(self) -> None:
        self.write("^C\n")
        self.exit()

    def success(self, response):
        """
        successful treq get
        """
        # TODO possible this is UNKNOWN_LENGTH
        if response.length != UNKNOWN_LENGTH:
            self.totallength = response.length
        else:
            self.totallength = 0

        if self.limit_size > 0 and self.totallength > self.limit_size:
            log.msg(
                f"Not saving URL ({self.url.decode()}) (size: {self.totallength}) exceeds file size limit ({self.limit_size})"
            )
            self.exit()
            return

        self.started = time.time()

        if not self.quiet:
            self.errorWrite("200 OK\n")

        if response.headers.hasHeader(b"content-type"):
            self.contenttype = response.headers.getRawHeaders(
                b"content-type")[0].decode()
        else:
            self.contenttype = "text/whatever"

        if not self.quiet:
            if response.length != UNKNOWN_LENGTH:
                self.errorWrite(
                    f"Length: {self.totallength} ({sizeof_fmt(self.totallength)}) [{self.contenttype}]\n"
                )
            else:
                self.errorWrite(f"Length: unspecified [{self.contenttype}]\n")

            if self.outfile is None:
                self.errorWrite("Saving to: `STDOUT'\n\n")
            else:
                self.errorWrite(f"Saving to: `{self.outfile}'\n\n")

        deferred = treq.collect(response, self.collect)
        deferred.addCallback(self.collectioncomplete)
        return deferred

    def collect(self, data: bytes) -> None:
        """
        partial collect
        """
        self.currentlength += len(data)
        if self.limit_size > 0 and self.currentlength > self.limit_size:
            log.msg(
                f"Not saving URL ({self.url.decode()}) (size: {self.currentlength}) exceeds file size limit ({self.limit_size})"
            )
            self.exit()
            return

        self.artifact.write(data)

        self.speed = self.currentlength / (time.time() - self.started)
        if self.totallength != 0:
            percent = int(self.currentlength / self.totallength * 100)
            spercent = f"{percent}%"
            eta = (self.totallength - self.currentlength) / self.speed
        else:
            spercent = f"{self.currentlength / 1000}K"
            percent = 0
            eta = 0.0

        s = "\r%s [%s] %s %dK/s  eta %s" % (
            spercent.rjust(3),
            ("%s>" % (int(39.0 / 100.0 * percent) * "=")).ljust(39),
            splitthousands(str(int(self.currentlength))).ljust(12),
            self.speed / 1000,
            tdiff(eta),
        )
        if not self.quiet:
            self.errorWrite(s.ljust(self.proglen))
        self.proglen = len(s)
        self.lastupdate = time.time()

        if not self.outfile:
            self.writeBytes(data)

    def collectioncomplete(self, data: None) -> None:
        """
        this gets called once collection is complete
        """
        self.artifact.close()

        self.totallength = self.currentlength

        if not self.quiet:
            self.errorWrite("\r100%%[%s] %s %dK/s" % (
                "%s>" % (38 * "="),
                splitthousands(str(int(self.totallength))).ljust(12),
                self.speed / 1000,
            ))
            self.errorWrite("\n\n")
            self.errorWrite("%s (%d KB/s) - `%s' saved [%d/%d]\n\n" % (
                time.strftime("%Y-%m-%d %H:%M:%S"),
                self.speed / 1000,
                self.outfile,
                self.currentlength,
                self.totallength,
            ))

        # Update the honeyfs to point to artifact file if output is to file
        if self.outfile:
            self.fs.mkfile(self.outfile, 0, 0, self.currentlength, 33188)
            self.fs.chown(self.outfile, self.protocol.user.uid,
                          self.protocol.user.gid)
            self.fs.update_realfile(self.fs.getfile(self.outfile),
                                    self.artifact.shasumFilename)

        self.protocol.logDispatch(
            eventid="cowrie.session.file_download",
            format=
            "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
            url=self.url,
            filename=self.artifact.shasumFilename,
            shasum=self.artifact.shasum,
        )
        log.msg(
            eventid="cowrie.session.file_download",
            format=
            "Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(filename)s",
            url=self.url,
            filename=self.artifact.shasumFilename,
            shasum=self.artifact.shasum,
        )
        self.exit()

    def error(self, response):
        """
        handle errors
        """
        print(response)

        if response.check(error.DNSLookupError) is not None:
            self.write(
                f"Resolving no.such ({self.host})... failed: nodename nor servname provided, or not known.\n"
            )
            self.write(f"wget: unable to resolve host address ‘{self.host}’\n")
            self.exit()
            return

        log.msg(response.printTraceback())
        if hasattr(response, "getErrorMessage"):  # Exceptions
            errormsg = response.getErrorMessage()
        log.msg(errormsg)
        self.write("\n")
        self.protocol.logDispatch(
            eventid="cowrie.session.file_download.failed",
            format="Attempt to download file(s) from URL (%(url)s) failed",
            url=self.url.decode(),
        )
        self.exit()
示例#13
0
    def download(self, url, fakeoutfile, *args, **kwargs):
        """
        url - URL to download
        fakeoutfile - file in guest's fs that attacker wants content to be downloaded to
        """
        try:
            parsed = compat.urllib_parse.urlparse(url)
            scheme = parsed.scheme
            host = parsed.hostname.decode("utf8")
            port = parsed.port or (443 if scheme == b"https" else 80)
            if scheme != b"http" and scheme != b"https":
                raise NotImplementedError
            if not host:
                return None
        except Exception:
            self.errorWrite(f"{url}: Unsupported scheme.\n")
            return None

        if not self.quiet:
            self.errorWrite(
                "--{}--  {}\n".format(
                    time.strftime("%Y-%m-%d %H:%M:%S"), url.decode("utf8")
                )
            )
            self.errorWrite(f"Connecting to {host}:{port}... connected.\n")
            self.errorWrite("HTTP request sent, awaiting response... ")

        # TODO: need to do full name resolution.
        try:
            if ipaddress.ip_address(host).is_private:
                self.errorWrite(
                    "Resolving {} ({})... failed: nodename nor servname provided, or not known.\n".format(
                        host, host
                    )
                )
                self.errorWrite(f"wget: unable to resolve host address ‘{host}’\n")
                return None
        except ValueError:
            pass

        # File in host's fs that will hold content of the downloaded file
        # HTTPDownloader will close() the file object so need to preserve the name
        self.artifactFile = Artifact(self.outfile)

        factory = HTTPProgressDownloader(
            self, fakeoutfile, url, self.artifactFile, *args, **kwargs
        )

        out_addr = None
        if CowrieConfig.has_option("honeypot", "out_addr"):
            out_addr = (CowrieConfig.get("honeypot", "out_addr"), 0)

        if scheme == b"https":
            context_factory = ssl.optionsForClientTLS(hostname=host)
            self.connection = reactor.connectSSL(
                host, port, factory, context_factory, bindAddress=out_addr
            )

        elif scheme == b"http":
            self.connection = reactor.connectTCP(
                host, port, factory, bindAddress=out_addr
            )
        else:
            raise NotImplementedError

        return factory.deferred
示例#14
0
文件: ftpget.py 项目: Mato-Z/cowrie
    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, 'cvu:p:P:')
        except getopt.GetoptError:
            self.help()
            self.exit()
            return

        if len(args) < 2:
            self.help()
            self.exit()
            return

        self.verbose = False
        self.username = ''
        self.password = ''
        self.port = 21
        self.host = ''
        self.local_file = ''
        self.remote_path = ''

        for opt in optlist:
            if opt[0] == '-v':
                self.verbose = True
            elif opt[0] == '-u':
                self.username = opt[1]
            elif opt[0] == '-p':
                self.password = opt[1]
            elif opt[0] == '-P':
                try:
                    self.port = int(opt[1])
                except ValueError:
                    pass

        if len(args) == 2:
            self.host, self.remote_path = args
        elif len(args) >= 3:
            self.host, self.local_file, self.remote_path = args[:3]

        self.remote_dir = os.path.dirname(self.remote_path)
        self.remote_file = os.path.basename(self.remote_path)
        if not self.local_file:
            self.local_file = self.remote_file

        fakeoutfile = self.fs.resolve_path(self.local_file, self.protocol.cwd)
        path = os.path.dirname(fakeoutfile)
        if not path or not self.fs.exists(path) or not self.fs.isdir(path):
            self.write('ftpget: can\'t open \'%s\': No such file or directory' % self.local_file)
            self.exit()
            return

        self.download_path = CONFIG.get('honeypot', 'download_path')

        self.url_log = 'ftp://'
        if self.username:
            self.url_log = '{}{}'.format(self.url_log, self.username)
            if self.password:
                self.url_log = '{}:{}'.format(self.url_log, self.password)
            self.url_log = '{}@'.format(self.url_log)
        self.url_log = '{}{}'.format(self.url_log, self.host)
        if self.port != 21:
            self.url_log = '{}:{}'.format(self.url_log, self.port)
        self.url_log = '{}/{}'.format(self.url_log, self.remote_path)

        self.artifactFile = Artifact(self.local_file)

        result = self.ftp_download()

        self.artifactFile.close()

        if not result:
            # log to cowrie.log
            log.msg(format='Attempt to download file(s) from URL (%(url)s) failed',
                    url=self.url_log)

            self.protocol.logDispatch(eventid='cowrie.session.file_download.failed',
                                      format='Attempt to download file(s) from URL (%(url)s) failed',
                                      url=self.url_log)
            self.exit()
            return

        # log to cowrie.log
        log.msg(format='Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
                url=self.url_log,
                outfile=self.artifactFile.shasumFilename,
                shasum=self.artifactFile.shasum)

        self.protocol.logDispatch(eventid='cowrie.session.file_download',
                                  format='Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
                                  url=self.url_log,
                                  outfile=self.artifactFile.shasumFilename,
                                  shasum=self.artifactFile.shasum,
                                  destfile=self.local_file)

        # Update the honeyfs to point to downloaded file
        self.fs.mkfile(fakeoutfile, 0, 0, os.path.getsize(self.artifactFile.shasumFilename), 33188)
        self.fs.update_realfile(self.fs.getfile(fakeoutfile), self.artifactFile.shasumFilename)
        self.fs.chown(fakeoutfile, self.protocol.user.uid, self.protocol.user.gid)

        self.exit()
示例#15
0
class command_ftpget(HoneyPotCommand):
    """
    """
    def help(self):
        self.write(
            """BusyBox v1.20.2 (2016-06-22 15:12:53 EDT) multi-call binary.

Usage: ftpget [OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE

Download a file via FTP

    -c Continue previous transfer
    -v Verbose
    -u USER     Username
    -p PASS     Password
    -P NUM      Port\n\n""")

    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, 'cvu:p:P:')
        except getopt.GetoptError:
            self.help()
            self.exit()
            return

        if len(args) < 2:
            self.help()
            self.exit()
            return

        self.verbose = False
        self.username = ''
        self.password = ''
        self.port = 21
        self.host = ''
        self.local_file = ''
        self.remote_path = ''

        for opt in optlist:
            if opt[0] == '-v':
                self.verbose = True
            elif opt[0] == '-u':
                self.username = opt[1]
            elif opt[0] == '-p':
                self.password = opt[1]
            elif opt[0] == '-P':
                try:
                    self.port = int(opt[1])
                except ValueError:
                    pass

        if len(args) == 2:
            self.host, self.remote_path = args
        elif len(args) >= 3:
            self.host, self.local_file, self.remote_path = args[:3]

        self.remote_dir = os.path.dirname(self.remote_path)
        self.remote_file = os.path.basename(self.remote_path)
        if not self.local_file:
            self.local_file = self.remote_file

        fakeoutfile = self.fs.resolve_path(self.local_file, self.protocol.cwd)
        path = os.path.dirname(fakeoutfile)
        if not path or not self.fs.exists(path) or not self.fs.isdir(path):
            self.write(
                'ftpget: can\'t open \'%s\': No such file or directory' %
                self.local_file)
            self.exit()
            return

        self.download_path = CONFIG.get('honeypot', 'download_path')

        self.url_log = 'ftp://'
        if self.username:
            self.url_log = '{}{}'.format(self.url_log, self.username)
            if self.password:
                self.url_log = '{}:{}'.format(self.url_log, self.password)
            self.url_log = '{}@'.format(self.url_log)
        self.url_log = '{}{}'.format(self.url_log, self.host)
        if self.port != 21:
            self.url_log = '{}:{}'.format(self.url_log, self.port)
        self.url_log = '{}/{}'.format(self.url_log, self.remote_path)

        self.artifactFile = Artifact(self.local_file)

        result = self.ftp_download()

        self.artifactFile.close()

        if not result:
            # log to cowrie.log
            log.msg(
                format='Attempt to download file(s) from URL (%(url)s) failed',
                url=self.url_log)

            self.protocol.logDispatch(
                eventid='cowrie.session.file_download.failed',
                format='Attempt to download file(s) from URL (%(url)s) failed',
                url=self.url_log)
            self.exit()
            return

        # log to cowrie.log
        log.msg(
            format=
            'Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum)

        self.protocol.logDispatch(
            eventid='cowrie.session.file_download',
            format=
            'Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum,
            destfile=self.local_file)

        # Update the honeyfs to point to downloaded file
        self.fs.mkfile(fakeoutfile, 0, 0,
                       os.path.getsize(self.artifactFile.shasumFilename),
                       33188)
        self.fs.update_realfile(self.fs.getfile(fakeoutfile),
                                self.artifactFile.shasumFilename)
        self.fs.chown(fakeoutfile, self.protocol.user.uid,
                      self.protocol.user.gid)

        self.exit()

    def ftp_download(self):

        out_addr = ('', 0)
        if CONFIG.has_option('honeypot', 'out_addr'):
            out_addr = (CONFIG.get('honeypot', 'out_addr'), 0)

        ftp = FTP(source_address=out_addr)

        # connect
        if self.verbose:
            self.write('Connecting to %s\n' %
                       self.host)  # TODO: add its IP address after the host

        try:
            ftp.connect(host=self.host, port=self.port, timeout=30)
        except Exception as e:
            log.msg('FTP connect failed: host=%s, port=%s, err=%s' %
                    (self.host, self.port, str(e)))
            self.write(
                'ftpget: can\'t connect to remote host: Connection refused\n')
            return False

        # login
        if self.verbose:
            self.write('ftpget: cmd (null) (null)\n')
            if self.username:
                self.write('ftpget: cmd USER %s\n' % self.username)
            else:
                self.write('ftpget: cmd USER anonymous\n')
            if self.password:
                self.write('ftpget: cmd PASS %s\n' % self.password)
            else:
                self.write('ftpget: cmd PASS busybox@\n')

        try:
            ftp.login(user=self.username, passwd=self.password)
        except Exception as e:
            log.msg('FTP login failed: user=%s, passwd=%s, err=%s' %
                    (self.username, self.password, str(e)))
            self.write('ftpget: unexpected server response to USER: %s\n' %
                       str(e))
            try:
                ftp.quit()
            except socket.timeout:
                pass
            return False

        # download
        if self.verbose:
            self.write('ftpget: cmd TYPE I (null)\n')
            self.write('ftpget: cmd PASV (null)\n')
            self.write('ftpget: cmd SIZE %s\n' % self.remote_path)
            self.write('ftpget: cmd RETR %s\n' % self.remote_path)

        try:
            ftp.cwd(self.remote_dir)
            ftp.retrbinary('RETR %s' % self.remote_file,
                           self.artifactFile.write)
        except Exception as e:
            log.msg('FTP retrieval failed: %s' % str(e))
            self.write('ftpget: unexpected server response to USER: %s\n' %
                       str(e))
            try:
                ftp.quit()
            except socket.timeout:
                pass
            return False

        # quit
        if self.verbose:
            self.write('ftpget: cmd (null) (null)\n')
            self.write('ftpget: cmd QUIT (null)\n')

        try:
            ftp.quit()
        except socket.timeout:
            pass

        return True
示例#16
0
    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, 'cvu:p:P:')
        except getopt.GetoptError:
            self.help()
            self.exit()
            return

        if len(args) < 2:
            self.help()
            self.exit()
            return

        self.verbose = False
        self.username = ''
        self.password = ''
        self.port = 21
        self.host = ''
        self.local_file = ''
        self.remote_path = ''

        for opt in optlist:
            if opt[0] == '-v':
                self.verbose = True
            elif opt[0] == '-u':
                self.username = opt[1]
            elif opt[0] == '-p':
                self.password = opt[1]
            elif opt[0] == '-P':
                try:
                    self.port = int(opt[1])
                except ValueError:
                    pass

        if len(args) == 2:
            self.host, self.remote_path = args
        elif len(args) >= 3:
            self.host, self.local_file, self.remote_path = args[:3]

        self.remote_dir = os.path.dirname(self.remote_path)
        self.remote_file = os.path.basename(self.remote_path)
        if not self.local_file:
            self.local_file = self.remote_file

        fakeoutfile = self.fs.resolve_path(self.local_file, self.protocol.cwd)
        path = os.path.dirname(fakeoutfile)
        if not path or not self.fs.exists(path) or not self.fs.isdir(path):
            self.write(
                'ftpget: can\'t open \'%s\': No such file or directory' %
                self.local_file)
            self.exit()
            return

        self.download_path = CONFIG.get('honeypot', 'download_path')

        self.url_log = 'ftp://'
        if self.username:
            self.url_log = '{}{}'.format(self.url_log, self.username)
            if self.password:
                self.url_log = '{}:{}'.format(self.url_log, self.password)
            self.url_log = '{}@'.format(self.url_log)
        self.url_log = '{}{}'.format(self.url_log, self.host)
        if self.port != 21:
            self.url_log = '{}:{}'.format(self.url_log, self.port)
        self.url_log = '{}/{}'.format(self.url_log, self.remote_path)

        self.artifactFile = Artifact(self.local_file)

        result = self.ftp_download()

        self.artifactFile.close()

        if not result:
            # log to cowrie.log
            log.msg(
                format='Attempt to download file(s) from URL (%(url)s) failed',
                url=self.url_log)

            self.protocol.logDispatch(
                eventid='cowrie.session.file_download.failed',
                format='Attempt to download file(s) from URL (%(url)s) failed',
                url=self.url_log)
            self.exit()
            return

        # log to cowrie.log
        log.msg(
            format=
            'Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum)

        self.protocol.logDispatch(
            eventid='cowrie.session.file_download',
            format=
            'Downloaded URL (%(url)s) with SHA-256 %(shasum)s to %(outfile)s',
            url=self.url_log,
            outfile=self.artifactFile.shasumFilename,
            shasum=self.artifactFile.shasum,
            destfile=self.local_file)

        # Update the honeyfs to point to downloaded file
        self.fs.mkfile(fakeoutfile, 0, 0,
                       os.path.getsize(self.artifactFile.shasumFilename),
                       33188)
        self.fs.update_realfile(self.fs.getfile(fakeoutfile),
                                self.artifactFile.shasumFilename)
        self.fs.chown(fakeoutfile, self.protocol.user.uid,
                      self.protocol.user.gid)

        self.exit()
示例#17
0
文件: curl.py 项目: zql2532666/cowrie
    def start(self):
        try:
            optlist, args = getopt.getopt(self.args, 'sho:O',
                                          ['help', 'manual', 'silent'])
        except getopt.GetoptError as err:
            # TODO: should be 'unknown' instead of 'not recognized'
            self.write("curl: {}\n".format(err))
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        for opt in optlist:
            if opt[0] == '-h' or opt[0] == '--help':
                self.curl_help()
                return
            elif opt[0] == '-s' or opt[0] == '--silent':
                self.silent = True

        if len(args):
            if args[0] is not None:
                url = str(args[0]).strip()
        else:
            self.write(
                "curl: try 'curl --help' or 'curl --manual' for more information\n"
            )
            self.exit()
            return

        if '://' not in url:
            url = 'http://' + url
        urldata = compat.urllib_parse.urlparse(url)

        outfile = None
        for opt in optlist:
            if opt[0] == '-o':
                outfile = opt[1]
            if opt[0] == '-O':
                outfile = urldata.path.split('/')[-1]
                if outfile is None or not len(
                        outfile.strip()) or not urldata.path.count('/'):
                    self.write('curl: Remote file name has no length!\n')
                    self.exit()
                    return

        if outfile:
            outfile = self.fs.resolve_path(outfile, self.protocol.cwd)
            path = os.path.dirname(outfile)
            if not path or \
                    not self.fs.exists(path) or \
                    not self.fs.isdir(path):
                self.write(
                    'curl: %s: Cannot open: No such file or directory\n' %
                    outfile)
                self.exit()
                return

        url = url.encode('ascii')
        self.url = url

        self.artifactFile = Artifact(outfile)
        # HTTPDownloader will close() the file object so need to preserve the name

        self.deferred = self.download(url, outfile, self.artifactFile)
        if self.deferred:
            self.deferred.addCallback(self.success, outfile)
            self.deferred.addErrback(self.error, url)