Example #1
0
    def _lowest_privilege_test(self, response):
        regex_str = 'User/Group </td><td class="v">(.*?)\((\d.*?)\)/(\d.*?)</td>'
        lowest_privilege_test = re.search(regex_str, response.get_body(), re.I)
        if lowest_privilege_test:
            lpt_uname = lowest_privilege_test.group(1)
            lpt_uid = lowest_privilege_test.group(2)
            lpt_uid = int(lpt_uid)
            lpt_gid = lowest_privilege_test.group(3)
            if lpt_uid < 99 or lpt_gid < 99 or \
            re.match('root|apache|daemon|bin|operator|adm', lpt_uname, re.I):

                desc = 'phpinfo()::PHP may be executing as a higher privileged'\
                       ' group. Username: %s, UserID: %s, GroupID: %s.' 
                desc = desc % (lpt_uname, lpt_uid, lpt_gid)
                
                v = Vuln('PHP lowest_privilege_test:fail', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                lpt_name = 'privilege:' + lpt_uname
                lpt_desc = 'phpinfo()::PHP is executing under '
                lpt_desc += 'username: '******', '
                lpt_desc += 'userID: ' + str(lpt_uid) + ', '
                lpt_desc += 'groupID: ' + lpt_gid
                i = Info(lpt_name, lpt_desc, response.id, self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', i)
                om.out.information(i.get_desc())
Example #2
0
    def _check_if_exists(self, web_shell_url):
        """
        Check if the file exists.

        :param web_shell_url: The URL to check
        """
        try:
            response = self._uri_opener.GET(web_shell_url, cache=True)
        except BaseFrameworkException:
            om.out.debug('Failed to GET webshell:' + web_shell_url)
        else:
            if self._is_possible_backdoor(response):
                desc = 'A web backdoor was found at: "%s"; this could ' \
                       'indicate that the server has been compromised.'
                desc = desc % response.get_url()

                v = Vuln('Potential web backdoor', desc, severity.HIGH,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'backdoors', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)
Example #3
0
    def _send_and_check(self, repo_url, repo_get_files, repo, domain_path):
        """
        Check if a repository index exists in the domain_path.

        :return: None, everything is saved to the self.out_queue.
        """
        http_response = self.http_get_and_parse(repo_url)

        if not is_404(http_response):

            filenames = repo_get_files(http_response.get_body())

            parsed_url_set = set()

            for filename in self._clean_filenames(filenames):
                test_url = domain_path.url_join(filename)
                if test_url not in self._analyzed_filenames:
                    parsed_url_set.add(test_url)
                    self._analyzed_filenames.add(filename)

            self.worker_pool.map(self.http_get_and_parse, parsed_url_set)

            if parsed_url_set:
                desc = 'A %s was found at: "%s"; this could indicate that'\
                       ' a %s is accessible. You might be able to download'\
                       ' the Web application source code.'
                desc = desc % (repo, http_response.get_url(), repo)
                
                v = Vuln('Source code repository', desc, severity.MEDIUM,
                         http_response.id, self.get_name())
                v.set_url(http_response.get_url())
                
                kb.kb.append(self, repo, v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #4
0
    def crawl(self, fuzzable_request):
        """
        Plugin entry point, perform all the work.
        """
        to_check = self._get_to_check(fuzzable_request.get_url())

        # I found some URLs, create fuzzable requests
        phishtank_matches = self._is_in_phishtank(to_check)
        for ptm in phishtank_matches:
            response = self._uri_opener.GET(ptm.url)
            for fr in self._create_fuzzable_requests(response):
                self.output_queue.put(fr)

        # Only create the vuln object once
        if phishtank_matches:
            desc = 'The URL: "%s" seems to be involved in a phishing scam.' \
                   ' Please see %s for more info.'
            desc = desc % (ptm.url, ptm.more_info_URL)
            
            v = Vuln('Phishing scam', desc, severity.MEDIUM, response.id,
                     self.get_name())
            v.set_url(ptm.url)
            
            kb.kb.append(self, 'phishtank', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #5
0
    def _check_if_exists(self, web_shell_url):
        """
        Check if the file exists.

        :param web_shell_url: The URL to check
        """
        try:
            response = self._uri_opener.GET(web_shell_url, cache=True)
        except BaseFrameworkException:
            om.out.debug('Failed to GET webshell:' + web_shell_url)
        else:
            signature = self._match_signature(response)
            if signature is None:
                return

            desc = (u'An HTTP response matching the web backdoor signature'
                    u' "%s" was found at: "%s"; this could indicate that the'
                    u' server has been compromised.')
            desc %= (signature, response.get_url())

            # It's probability is higher if we found a long signature
            _severity = severity.HIGH if len(signature) > 8 else severity.MEDIUM

            v = Vuln(u'Potential web backdoor', desc, _severity,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'backdoors', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            fr = FuzzableRequest.from_http_response(response)
            self.output_queue.put(fr)
Example #6
0
    def _find_auth_uri(self, response):
        """
        Analyze a 200 response and report any findings of http://user:[email protected]/
        :return: None
        """
        #
        #   Analyze the HTTP URL
        #
        if ('@' in response.get_uri() and
                self._auth_uri_regex.match(response.get_uri().url_string)):
            # An authentication URI was found!
            desc = 'The resource: "%s" has a user and password in' \
                   ' the URI.'
            desc = desc % response.get_uri()
            v = Vuln('Basic HTTP credentials', desc, severity.HIGH,
                     response.id, self.get_name())

            v.set_url(response.get_url())
            v.add_to_highlight(response.get_uri().url_string)

            kb.kb.append(self, 'userPassUri', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

        #
        #   Analyze the HTTP response body
        #
        url_list = []
        try:
            DocumentParser = parser_cache.dpc.get_document_parser_for(response)
        except BaseFrameworkException, w3:
            msg = 'Failed to find a suitable document parser. ' \
                'Exception: ' + str(w3)
            om.out.debug(msg)
Example #7
0
    def _analyze_crossdomain_clientaccesspolicy(self, url, response, file_name):

        # https://github.com/andresriancho/w3af/issues/14491
        if file_name not in self.FILE_TAG_ATTR:
            return

        try:
            dom = xml.dom.minidom.parseString(response.get_body())
        except Exception:
            # Report this, it may be interesting for the final user
            # not a vulnerability per-se... but... it's information after all
            if 'allow-access-from' in response.get_body() or \
            'cross-domain-policy' in response.get_body() or \
            'cross-domain-access' in response.get_body():

                desc = 'The "%s" file at: "%s" is not a valid XML.'
                desc %= (file_name, response.get_url())

                i = Info('Invalid RIA settings file', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'info', i)
                om.out.information(i.get_desc())

            return

        tag, attribute = self.FILE_TAG_ATTR.get(file_name)
        url_list = dom.getElementsByTagName(tag)

        for url in url_list:
            url = url.getAttribute(attribute)

            if url == '*':
                desc = 'The "%s" file at "%s" allows flash/silverlight'\
                       ' access from any site.'
                desc %= (file_name, response.get_url())

                v = Vuln('Insecure RIA settings', desc, severity.LOW,
                         response.id, self.get_name())
                v.set_url(response.get_url())
                v.set_method('GET')

                kb.kb.append(self, 'vuln', v)
                om.out.vulnerability(v.get_desc(),
                                     severity=v.get_severity())
            else:
                desc = 'The "%s" file at "%s" allows flash/silverlight'\
                       ' access from "%s".'
                desc %= (file_name, response.get_url(), url)

                i = Info('Cross-domain allow ACL', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())
                i.set_method('GET')

                kb.kb.append(self, 'info', i)
                om.out.information(i.get_desc())
Example #8
0
    def _analyze_crossdomain_clientaccesspolicy(self, url, response, file_name):
        try:
            dom = xml.dom.minidom.parseString(response.get_body())
        except Exception:
            # Report this, it may be interesting for the final user
            # not a vulnerability per-se... but... it's information after all
            if 'allow-access-from' in response.get_body() or \
            'cross-domain-policy' in response.get_body() or \
            'cross-domain-access' in response.get_body():

                desc = 'The "%s" file at: "%s" is not a valid XML.'
                desc = desc % (file_name, response.get_url())
            
                i = Info('Invalid RIA settings file', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())
                
                kb.kb.append(self, 'info', i)
                om.out.information(i.get_desc())
        else:
            if file_name == 'crossdomain.xml':
                url_list = dom.getElementsByTagName("allow-access-from")
                attribute = 'domain'
            if file_name == 'clientaccesspolicy.xml':
                url_list = dom.getElementsByTagName("domain")
                attribute = 'uri'

            for url in url_list:
                url = url.getAttribute(attribute)

                if url == '*':
                    desc = 'The "%s" file at "%s" allows flash/silverlight'\
                           ' access from any site.'
                    desc = desc % (file_name, response.get_url())

                    v = Vuln('Insecure RIA settings', desc, severity.LOW,
                             response.id, self.get_name())
                    v.set_url(response.get_url())
                    v.set_method('GET')

                    kb.kb.append(self, 'vuln', v)
                    om.out.vulnerability(v.get_desc(),
                                         severity=v.get_severity())
                else:
                    desc = 'The "%s" file at "%s" allows flash/silverlight'\
                           ' access from "%s".'
                    desc = desc % (file_name, response.get_url(), url)

                    i = Info('Cross-domain allow ACL', desc, response.id,
                             self.get_name())
                    i.set_url(response.get_url())
                    i.set_method('GET')

                    kb.kb.append(self, 'info', i)
                    om.out.information(i.get_desc())
Example #9
0
 def _display_errors(self, response):
     regex_str = 'display_errors</td><td class="v">(On|<i>no value</i>)</td>'
     display_errors = re.search(regex_str, response.get_body(), re.I)
     if display_errors:
         desc = 'The phpinfo()::display_errors is enabled.'
         v = Vuln('PHP display_errors: On', desc,
                  severity.MEDIUM, response.id, self.get_name())
         v.set_url(response.get_url())
         
         kb.kb.append(self, 'phpinfo', v)
         om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #10
0
 def _expose_php(self, response):
     regex_str = 'expose_php</td><td class="v">(On|<i>no value</i>)</td>'
     expose_php = re.search(regex_str, response.get_body(), re.I)
     if expose_php:
         desc = 'The phpinfo()::expose_php is enabled.'
         v = Vuln('PHP expose_php: On', desc,
                  severity.MEDIUM, response.id, self.get_name())
         v.set_url(response.get_url())
         
         kb.kb.append(self, 'phpinfo', v)
         om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #11
0
 def _session_cookie_httponly(self, response):
     regex_str = 'session\.cookie_httponly</td><td class="v">(Off|no|0)</td>'
     session_cookie_httponly = re.search(regex_str, response.get_body(), re.I)
     if session_cookie_httponly:
         desc = 'The phpinfo()::session.cookie_httponly is off.'
         v = Vuln('PHP session.cookie_httponly: Off', desc,
                  severity.MEDIUM, response.id, self.get_name())
         v.set_url(response.get_url())
         
         kb.kb.append(self, 'phpinfo', v)
         om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #12
0
 def _allow_url_include(self, response):
     regex_str = 'allow_url_include</td><td class="v">(On|<i>no value</i>)</td>'
     allow_url_include = re.search(regex_str, response.get_body(), re.I)
     if allow_url_include:
         desc = 'The phpinfo()::allow_url_include is enabled.'
         v = Vuln('PHP allow_url_include: On', desc,
                  severity.MEDIUM, response.id, self.get_name())
         v.set_url(response.get_url())
         
         kb.kb.append(self, 'phpinfo', v)
         om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #13
0
    def _session_save_path(self, response):
        regex_str = 'session\.save_path</td><td class="v">(<i>no value</i>)</td>'
        session_save_path = re.search(regex_str, response.get_body(), re.I)
        if session_save_path:
            desc = 'The phpinfo()::session.save_path may be set to world-'\
                   'accessible directory.'
            v = Vuln('PHP session_save_path:Everyone', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #14
0
 def _session_use_trans(self, response):
     regex_str = 'session\.use_trans</td><td class="v">(On)</td>'
     session_use_trans = re.search(regex_str, response.get_body(), re.I)
     if session_use_trans:
         desc = 'The phpinfo()::session.use_trans is enabled. This makes'\
                ' session hijacking easier.'
         v = Vuln('PHP session_use_trans: On', desc,
                  severity.MEDIUM, response.id, self.get_name())
         v.set_url(response.get_url())
         
         kb.kb.append(self, 'phpinfo', v)
         om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #15
0
    def _upload_tmp_dir(self, response):
        regex_str = 'upload_tmp_dir</td><td class="v">(<i>no value</i>)</td>'
        upload_tmp_dir = re.search(regex_str, response.get_body(), re.I)
        if upload_tmp_dir:
            desc = 'The phpinfo()::upload_tmp_dir may be set to world-'\
                   'accessible directory.'
            v = Vuln('PHP upload_tmp_dir:Everyone', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #16
0
 def _cgi_force_redirect(self, response):
     regex_str = 'cgi_force_redirect</td><td class="v">(.*?)</td>'
     cgi_force_redirect = re.search(regex_str, response.get_body(), re.I)
     if cgi_force_redirect:
         utd = cgi_force_redirect.group(1) + ''
         if utd != 'On':
             desc = 'The phpinfo()::CGI::force_redirect is disabled.'
             v = Vuln('PHP cgi_force_redirect: Off', desc,
                      severity.MEDIUM, response.id, self.get_name())
             v.set_url(response.get_url())
             
             kb.kb.append(self, 'phpinfo', v)
             om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #17
0
 def _default_charset(self, response):
     regex_str = 'default_charset</td><td class="v">(Off|no|0)</td>'
     default_charset = re.search(regex_str, response.get_body(), re.I)
     if default_charset:
         desc = 'The phpinfo()::default_charset is set to none. This'\
                ' makes PHP scripts vulnerable to variable charset'\
                ' encoding XSS.'
         v = Vuln('PHP default_charset: Off', desc,
                  severity.MEDIUM, response.id, self.get_name())
         v.set_url(response.get_url())
         
         kb.kb.append(self, 'phpinfo', v)
         om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #18
0
    def _brute_worker(self, url, combination):
        """
        Try a user/password combination with HTTP basic authentication against
        a specific URL.

        :param url: A string representation of an URL
        :param combination: A tuple that contains (user,pass)
        """
        # Remember that this worker is called from a thread which lives in a
        # threadpool. If the worker finds something, it has to let the rest know
        # and the way we do that is by setting self._found.
        #
        # If one thread sees that we already bruteforced the access, the rest
        # will simply no-op
        if not self._found or not self._stop_on_first:
            user, passwd = combination

            raw_values = "%s:%s" % (user, passwd)
            auth = 'Basic %s' % base64.b64encode(raw_values).strip()
            headers = Headers([('Authorization', auth)])

            fr = FuzzableRequest(url, headers=headers, method='GET')

            try:
                response = self._uri_opener.send_mutant(fr, cache=False,
                                                        grep=False)
            except BaseFrameworkException, w3:
                msg = 'Exception while brute-forcing basic authentication,'\
                      ' error message: "%s".'
                om.out.debug(msg % w3)
            else:
                # GET was OK
                if response.get_code() != 401:
                    self._found = True
                    
                    desc = 'Found authentication credentials to: "%s".'\
                           ' A valid user and password combination is: %s/%s .'
                    desc = desc % (url, user, passwd)
                    v = Vuln('Guessable credentials', desc,
                             severity.HIGH, response.id, self.get_name())
                    v.set_url(url)
                    
                    v['user'] = user
                    v['pass'] = passwd
                    v['response'] = response
                    v['request'] = fr

                    kb.kb.append(self, 'auth', v)
                    om.out.vulnerability(v.get_desc(),
                                         severity=v.get_severity())
Example #19
0
 def _disable_functions(self, response):
     regex_str = 'disable_functions</td><td class="v">(.*?)</td>'
     disable_functions = re.search(regex_str, response.get_body(), re.I)
     if disable_functions:
         secure_df = 8
         df = disable_functions.group(1)
         dfe = df.split(',')
         if len(dfe) < secure_df:
             desc = 'The phpinfo()::disable_functions are set to few.'
             v = Vuln('PHP disable_functions:few', desc,
                      severity.MEDIUM, response.id, self.get_name())
             v.set_url(response.get_url())
             
             kb.kb.append(self, 'phpinfo', v)
             om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #20
0
 def _memory_limit(self, response):
     regex_str = 'memory_limit</td><td class="v">(\d.*?)</td>'
     memory_limit = re.search(regex_str, response.get_body(), re.I)
     if memory_limit:
         secure_ml = 10
         ml = memory_limit.group(1) + ''
         ml = ml.replace('M', '')
         if ml > secure_ml:
             desc = 'The phpinfo()::memory_limit is set to higher value'\
                    ' (%s).' % memory_limit.group(1)
             v = Vuln('PHP memory_limit:high', desc,
                      severity.MEDIUM, response.id, self.get_name())
             v.set_url(response.get_url())
             
             kb.kb.append(self, 'phpinfo', v)
             om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #21
0
    def _post_max_size(self, response):
        regex_str = 'post_max_size</td><td class="v">(\d.*?)</td>'
        post_max_size = re.search(
            regex_str, response.get_body(), re.IGNORECASE)
        if post_max_size:
            secure_pms = 20
            pms = post_max_size.group(1) + ''
            pms = pms.replace('M', '')
            pms = int(pms)
            if pms > secure_pms:
                desc = 'The phpinfo()::post_max_size is set to higher value'\
                       ' (%s).' % post_max_size.group(1)
                v = Vuln('PHP post_max_size:high', desc,
                         severity.LOW, response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #22
0
 def _upload_max_filesize(self, response):
     regex_str = 'upload_max_filesize</td><td class="v">(\d.*?)</td>'
     upload_max_filesize = re.search(
         regex_str, response.get_body(), re.IGNORECASE)
     if upload_max_filesize:
         secure_umf = 20
         umf = upload_max_filesize.group(1) + ''
         umf = umf.replace('M', '')
         umf = int(umf)
         if umf > secure_umf:
             desc = 'The phpinfo()::upload_max_filesize is set to higher'\
                    ' value (%s).' % upload_max_filesize.group(1)
             v = Vuln('PHP upload_max_filesize:high', desc,
                      severity.LOW, response.id, self.get_name())
             v.set_url(response.get_url())
             
             kb.kb.append(self, 'phpinfo', v)
             om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #23
0
    def _post_max_size(self, response):
        regex_str = 'post_max_size</td><td class="v">(\d.*?)</td>'
        post_max_size = re.search(
            regex_str, response.get_body(), re.IGNORECASE)
        if post_max_size:
            secure_pms = 20
            pms = post_max_size.group(1) + ''
            pms = pms.replace('M', '')
            pms = int(pms)
            if pms > secure_pms:
                desc = 'The phpinfo()::post_max_size is set to higher value'\
                       ' (%s).' % post_max_size.group(1)
                v = Vuln('PHP post_max_size:high', desc,
                         severity.LOW, response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #24
0
 def _upload_max_filesize(self, response):
     regex_str = 'upload_max_filesize</td><td class="v">(\d.*?)</td>'
     upload_max_filesize = re.search(
         regex_str, response.get_body(), re.IGNORECASE)
     if upload_max_filesize:
         secure_umf = 20
         umf = upload_max_filesize.group(1) + ''
         umf = umf.replace('M', '')
         umf = int(umf)
         if umf > secure_umf:
             desc = 'The phpinfo()::upload_max_filesize is set to higher'\
                    ' value (%s).' % upload_max_filesize.group(1)
             v = Vuln('PHP upload_max_filesize:high', desc,
                      severity.LOW, response.id, self.get_name())
             v.set_url(response.get_url())
             
             kb.kb.append(self, 'phpinfo', v)
             om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #25
0
    def _check_and_analyze(self, domain_path, php_info_filename):
        """
        Check if a php_info_filename exists in the domain_path.
        :return: None, everything is put() into the self.output_queue.
        """
        php_info_url = domain_path.url_join(php_info_filename)

        response = self._uri_opener.GET(php_info_url,
                                        cache=True,
                                        grep=False)

        if is_404(response):
            return

        # Check if it is a phpinfo file
        php_version = self.PHP_VERSION_RE.search(response.get_body(), re.I)
        sysinfo = self.SYSTEM_RE.search(response.get_body(), re.I)

        if not php_version:
            return

        if not sysinfo:
            return

        # Create the fuzzable request and send it to the core
        fr = FuzzableRequest.from_http_response(response)
        self.output_queue.put(fr)

        desc = ('The phpinfo() file was found at: %s. The version'
                ' of PHP is: "%s" and the system information is:'
                ' "%s".')
        desc %= (response.get_url(), php_version.group(2), sysinfo.group(1))

        v = Vuln('phpinfo() file found', desc, severity.MEDIUM,
                 response.id, self.get_name())
        v.set_url(response.get_url())

        kb.kb.append(self, 'phpinfo', v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())

        if not self._has_audited:
            self._has_audited = True
            self.audit_phpinfo(response)
Example #26
0
    def _check_and_analyze(self, domain_path):
        """
        Check if a .DS_Store filename exists in the domain_path.

        :return: None, everything is saved to the self.out_queue.
        """
        # Request the file
        url = domain_path.url_join(self.DS_STORE)

        try:
            response = self.http_get_and_parse(url, binary_response=True)
        except BaseFrameworkException as w3:
            msg = 'Failed to GET .DS_Store file: %s. Exception: %s.'
            om.out.debug(msg, (url, w3))
            return

        # Check if it's a .DS_Store file
        if is_404(response):
            return

        try:
            store = DsStore(response.get_raw_body())
            entries = store.get_file_entries()
        except Exception as e:
            om.out.debug('Unexpected error while parsing DS_Store file: "%s"' % e)
            return

        parsed_url_list = []

        for filename in entries:
            parsed_url_list.append(domain_path.url_join(filename))

        self.worker_pool.map(self.http_get_and_parse, parsed_url_list)

        desc = ('A .DS_Store file was found at: %s. The contents of this file'
                ' disclose filenames')
        desc %= (response.get_url())

        v = Vuln('.DS_Store file found', desc, severity.LOW, response.id, self.get_name())
        v.set_url(response.get_url())

        kb.kb.append(self, 'dot_ds_store', v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #27
0
def lowest_privilege_test(response):
    regex_str = 'User/Group </td><td class="v">(.*?)\((\d.*?)\)/(\d.*?)</td>'
    lowest_privilege_test_mo = re.search(regex_str, response.get_body(), re.I)

    if not lowest_privilege_test_mo:
        return

    lpt_uname = lowest_privilege_test_mo.group(1)

    lpt_uid = lowest_privilege_test_mo.group(2)
    lpt_uid = int(lpt_uid)

    lpt_gid = lowest_privilege_test_mo.group(3)
    lpt_gid = int(lpt_gid)

    is_privileged_username_mo = re.match('root|apache|daemon|bin|operator|adm',
                                         lpt_uname, re.I)

    if lpt_uid < 99 or lpt_gid < 99 or is_privileged_username_mo:

        desc = ('phpinfo()::PHP may be executing as a higher privileged'
                ' user or group. Username: %s, User id: %s, Group id: %s.')
        desc %= (lpt_uname, lpt_uid, lpt_gid)

        v = Vuln('PHP running with privileged user', desc, severity.MEDIUM,
                 response.id, 'phpinfo')
        v.set_url(response.get_url())

        kb.kb.append('phpinfo', 'phpinfo', v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())
    else:
        desc = ('PHP seems to be running as a low privileged user.'
                ' Username: %s, User id: %s, Group id: %s.')

        desc %= (lpt_uname, lpt_uid, lpt_gid)

        i = Info('PHP running as low privileged user', desc, response.id,
                 'phpinfo')
        i.set_url(response.get_url())

        kb.kb.append('phpinfo', 'phpinfo', i)
        om.out.information(i.get_desc())
Example #28
0
    def _curl_file_support(self, response):
        regex_str = '<h1 class="p">PHP Version (\d).(\d).(\d)</h1>'
        curl_file_support = re.search(regex_str, response.get_body(), re.I)
        if curl_file_support:
            php_major_ver = curl_file_support.group(1)
            php_minor_ver = curl_file_support.group(2)
            php_rev_ver = curl_file_support.group(3)

            current_ver = php_major_ver + '.' + php_minor_ver + \
                '' + php_rev_ver
            current_ver = float(current_ver)
            php_major_ver = int(php_major_ver)
            php_minor_ver = int(php_minor_ver)
            php_rev_ver = int(php_rev_ver)

            cv4check = float(4.44)
            cv5check = float(5.16)
            curl_vuln = 1

            if php_major_ver == 4:
                if current_ver >= cv4check:
                    curl_vuln = 0
            elif php_major_ver == 5:
                if current_ver >= cv5check:
                    curl_vuln = 0
            elif php_major_ver >= 6:
                curl_vuln = 0
            else:
                curl_vuln = 0

            if curl_vuln == 1:
                desc = 'The phpinfo()::cURL::file_support has a security hole'\
                       ' present in this version of PHP allows the cURL'\
                       ' functions to bypass safe_mode and open_basedir'\
                       ' restrictions.'
                v = Vuln('PHP curl_file_support:not_fixed', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #29
0
def curl_file_support(response):
    regex_str = '<h1 class="p">PHP Version (\d).(\d).(\d)</h1>'
    curl_file_support_mo = re.search(regex_str, response.get_body(), re.I)

    if not curl_file_support_mo:
        return

    php_major_ver = curl_file_support_mo.group(1)
    php_minor_ver = curl_file_support_mo.group(2)
    php_rev_ver = curl_file_support_mo.group(3)

    current_ver = php_major_ver + '.' + php_minor_ver + php_rev_ver
    current_ver = float(current_ver)
    php_major_ver = int(php_major_ver)

    cv4check = float(4.44)
    cv5check = float(5.16)
    curl_vuln = 1

    if php_major_ver == 4:
        if current_ver >= cv4check:
            curl_vuln = 0
    elif php_major_ver == 5:
        if current_ver >= cv5check:
            curl_vuln = 0
    elif php_major_ver >= 6:
        curl_vuln = 0
    else:
        curl_vuln = 0

    if curl_vuln == 1:
        desc = ('The phpinfo()::cURL::file_support has a security hole'
                ' present in this version of PHP allows the cURL'
                ' functions to bypass safe_mode and open_basedir'
                ' restrictions.')
        v = Vuln('PHP curl_file_support:not_fixed', desc, severity.MEDIUM,
                 response.id, 'phpinfo')
        v.set_url(response.get_url())

        kb.kb.append('phpinfo', 'phpinfo', v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #30
0
    def _enable_dl(self, response):
        regex_str = 'enable_dl</td><td class="v">(On|Off)</td>'
        enable_dl = re.search(regex_str, response.get_body(), re.I)
        if enable_dl:
            rg = enable_dl.group(1)
            if rg == 'On':
                desc = 'The phpinfo()::enable_dl is on.'
                v = Vuln('PHP enable_dl: On', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                ed_name = 'PHP enable_dl: Off'
                ed_desc = 'The phpinfo()::enable_dl is off.'
                i = Info(ed_name, ed_desc, response.id, self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', i)
                om.out.information(i.get_desc())
Example #31
0
    def _register_globals(self, response):
        regex_str = 'register_globals</td><td class="v">(On|Off)</td>'
        register_globals = re.search(regex_str, response.get_body(), re.I)

        if register_globals:
            rg = register_globals.group(1)
            if rg == 'On':
                desc = 'The phpinfo()::register_globals is on.'
                v = Vuln('PHP register_globals: On', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                rg_name = 'PHP register_globals: Off'
                rg_desc = 'The phpinfo()::register_globals is off.'
                i = Info(rg_name, rg_desc, response.id, self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', i)
                om.out.information(i.get_desc())
Example #32
0
def memory_limit(response):
    regex_str = 'memory_limit</td><td class="v">(\d.*?)</td>'
    memory_limit_mo = re.search(regex_str, response.get_body(), re.I)

    if not memory_limit_mo:
        return

    secure_ml = 10

    ml = memory_limit_mo.group(1) + ''
    ml = ml.replace('M', '')
    ml = int(ml)

    if ml > secure_ml:
        desc = 'The phpinfo()::memory_limit is set to a high value: %s'
        desc %= (memory_limit_mo.group(1), )

        v = Vuln('PHP high memory limit', desc, severity.MEDIUM, response.id,
                 'phpinfo')
        v.set_url(response.get_url())

        kb.kb.append('phpinfo', 'phpinfo', v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #33
0
    def _check_if_exists(self, web_shell_url):
        """
        Check if the file exists.

        :param web_shell_url: The URL to check
        """
        try:
            response = self._uri_opener.GET(web_shell_url, cache=True)
        except BaseFrameworkException:
            om.out.debug('Failed to GET webshell:' + web_shell_url)
        else:
            if response.get_code() == 200:
                signature = self._match_signature(response)
                if signature is None:
                    return

                desc = (
                    u'An HTTP response matching the web backdoor signature'
                    u' "%s" was found at: "%s"; this could indicate that the'
                    u' server has been compromised.')
                desc %= (signature, response.get_url())

                # It's probability is higher if we found a long signature
                _severity = severity.HIGH if len(
                    signature) > 8 else severity.MEDIUM

                v = Vuln(u'Potential web backdoor', desc, _severity,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'backdoors', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)
            else:
                return
Example #34
0
    def _verify_upload(self, domain_path, rand_file, upload_id, debugging_id):
        """
        Verify if the file was uploaded.

        :param domain_path: http://localhost/f00/
        :param rand_file: The filename that was (potentially) uploaded
        :param upload_id: The id of the POST request to author.dll
        """
        target_url = domain_path.url_join(rand_file)

        try:
            res = self._uri_opener.GET(target_url,
                                       cache=False,
                                       grep=False,
                                       debugging_id=debugging_id)
        except BaseFrameworkException as e:
            om.out.debug('Exception while verifying if the file that was uploaded'
                         'using author.dll was there: %s' % e)
        else:
            # The file we uploaded has the reversed filename as body
            if rand_file[::-1] not in res.get_body():
                return

            desc = ('An insecure configuration in the frontpage extensions'
                    ' allows unauthenticated users to upload files to the'
                    ' remote web server.')

            response_ids = [upload_id, res.id] if upload_id is not None else [res.id]

            v = Vuln('Insecure Frontpage extensions configuration', desc,
                     severity.HIGH, response_ids, self.get_name())

            v.set_url(target_url)
            v.set_method('POST')

            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            self.kb_append(self, 'frontpage', v)
Example #35
0
    def crawl(self, fuzzable_request):
        """
        Plugin entry point, performs all the work.
        """
        to_check = self._get_to_check(fuzzable_request.get_url())

        # I found some URLs, create fuzzable requests
        pt_handler = self._is_in_phishtank(to_check)

        for ptm in pt_handler.matches:
            fr = FuzzableRequest(ptm.url)
            self.output_queue.put(fr)

        # Only create the vuln object once
        if pt_handler.matches:
            desc = 'The URL: "%s" seems to be involved in a phishing scam.' \
                   ' Please see %s for more info.'
            desc = desc % (ptm.url, ptm.more_info_url)

            v = Vuln('Phishing scam', desc, severity.MEDIUM, [], self.get_name())
            v.set_url(ptm.url)

            kb.kb.append(self, 'phishtank', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #36
0
def post_max_size(response):
    regex_str = 'post_max_size</td><td class="v">(\d.*?)</td>'
    post_max_size_mo = re.search(regex_str, response.get_body(), re.IGNORECASE)

    if not post_max_size_mo:
        return

    secure_pms = 20
    pms = post_max_size_mo.group(1) + ''
    pms = pms.replace('M', '')
    pms = int(pms)

    if pms <= secure_pms:
        return

    desc = 'The phpinfo()::post_max_size is set to a high value: %s'
    desc %= (post_max_size_mo.group(1), )

    v = Vuln('PHP high POST max size', desc, severity.LOW, response.id,
             'phpinfo')
    v.set_url(response.get_url())

    kb.kb.append('phpinfo', 'phpinfo', v)
    om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #37
0
                return

            desc = ('An insecure configuration in the frontpage extensions'
                    ' allows unauthenticated users to upload files to the'
                    ' remote web server.')

            response_ids = [upload_id, res.id
                            ] if upload_id is not None else [res.id]

            v = Vuln('Insecure Frontpage extensions configuration', desc,
                     severity.HIGH, response_ids, self.get_name())

            v.set_url(target_url)
            v.set_method('POST')

            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            self.kb_append(self, 'frontpage', v)

    def get_plugin_deps(self):
        """
        :return: A list with the names of the plugins that should be run before
                 the current one.
        """
        return ['infrastructure.frontpage_version']

    def get_long_desc(self):
        """
        :return: A DETAILED description of the plugin functions and features.
        """
        return """
        This plugin audits the frontpage extension configuration by trying to
Example #38
0
    def audit_phpinfo(self, response):
        """
        Scan for insecure php settings
        :author: Aung Khant (aungkhant[at]yehg.net)
        :return none

        two divisions: vulnerable settings and useful informative settings

        """

        ##### [Vulnerable Settings] #####

        ### [register_globals] ###
        regex_str = 'register_globals</td><td class="v">(On|Off)</td>'
        register_globals = re.search(regex_str, response.get_body(), re.I)
        rg_flag = ''
        if register_globals:
            rg = register_globals.group(1)
            if (rg == 'On'):
                desc = 'The phpinfo()::register_globals is on.'
                v = Vuln('PHP register_globals: On', desc, severity.MEDIUM,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                rg_flag = 'info'
                rg_name = 'PHP register_globals: Off'
                rg_desc = 'The phpinfo()::register_globals is off.'

        ### [/register_globals] ###

        ### [allow_url_fopen] ###
        regex_str = 'allow_url_fopen</td><td class="v">(On|<i>no value</i>)</td>'
        allow_url_fopen = re.search(regex_str, response.get_body(), re.I)
        if allow_url_fopen:
            desc = 'The phpinfo()::allow_url_fopen is enabled.'
            v = Vuln('PHP allow_url_fopen: On', desc, severity.MEDIUM,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/allow_url_fopen] ###

        ### [allow_url_include] ###
        regex_str = 'allow_url_include</td><td class="v">(On|<i>no value</i>)</td>'
        allow_url_include = re.search(regex_str, response.get_body(), re.I)
        if allow_url_include:
            desc = 'The phpinfo()::allow_url_include is enabled.'
            v = Vuln('PHP allow_url_include: On', desc, severity.MEDIUM,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/allow_url_include] ###

        ### [display_errors] ###
        regex_str = 'display_errors</td><td class="v">(On|<i>no value</i>)</td>'
        display_errors = re.search(regex_str, response.get_body(), re.I)
        if display_errors:
            desc = 'The phpinfo()::display_errors is enabled.'
            v = Vuln('PHP display_errors: On', desc, severity.MEDIUM,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/display_errors] ###

        ### [expose_php] ###
        regex_str = 'expose_php</td><td class="v">(On|<i>no value</i>)</td>'
        expose_php = re.search(regex_str, response.get_body(), re.I)
        if expose_php:
            desc = 'The phpinfo()::expose_php is enabled.'
            v = Vuln('PHP expose_php: On', desc, severity.MEDIUM, response.id,
                     self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/expose_php] ###

        ### [lowest_privilege_test] ###
        regex_str = 'User/Group </td><td class="v">(.*?)\((\d.*?)\)/(\d.*?)</td>'
        lowest_privilege_test = re.search(regex_str, response.get_body(), re.I)
        lpt_flag = ''
        if lowest_privilege_test:
            lpt_uname = lowest_privilege_test.group(1)
            lpt_uid = lowest_privilege_test.group(2)
            lpt_uid = int(lpt_uid)
            lpt_gid = lowest_privilege_test.group(3)
            if lpt_uid < 99 or lpt_gid < 99 or \
            re.match('root|apache|daemon|bin|operator|adm', lpt_uname, re.I):

                desc = 'phpinfo()::PHP may be executing as a higher privileged'\
                       ' group. Username: %s, UserID: %s, GroupID: %s.'
                desc = desc % (lpt_uname, lpt_uid, lpt_gid)

                v = Vuln('PHP lowest_privilege_test:fail', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                lpt_flag = 'info'
                lpt_name = 'privilege:' + lpt_uname
                lpt_desc = 'phpinfo()::PHP is executing under '
                lpt_desc += 'username: '******', '
                lpt_desc += 'userID: ' + str(lpt_uid) + ', '
                lpt_desc += 'groupID: ' + lpt_gid
        ### [/lowest_privilege_test] ###

        ### [disable_functions] ###
        regex_str = 'disable_functions</td><td class="v">(.*?)</td>'
        disable_functions = re.search(regex_str, response.get_body(), re.I)
        if disable_functions:
            secure_df = 8
            df = disable_functions.group(1)
            dfe = df.split(',')
            if (len(dfe) < secure_df):
                desc = 'The phpinfo()::disable_functions are set to few.'
                v = Vuln('PHP disable_functions:few', desc, severity.MEDIUM,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/disable_functions] ###

        ### [curl_file_support] ###
        regex_str = '<h1 class="p">PHP Version (\d).(\d).(\d)</h1>'
        curl_file_support = re.search(regex_str, response.get_body(), re.I)
        if curl_file_support:
            php_major_ver = curl_file_support.group(1)
            php_minor_ver = curl_file_support.group(2)
            php_rev_ver = curl_file_support.group(3)

            current_ver = php_major_ver + '.' + php_minor_ver + \
                '' + php_rev_ver
            current_ver = float(current_ver)
            php_major_ver = int(php_major_ver)
            php_minor_ver = int(php_minor_ver)
            php_rev_ver = int(php_rev_ver)

            cv4check = float(4.44)
            cv5check = float(5.16)
            curl_vuln = 1

            if (php_major_ver == 4):
                if (current_ver >= cv4check):
                    curl_vuln = 0
            elif (php_major_ver == 5):
                if (current_ver >= cv5check):
                    curl_vuln = 0
            elif (php_major_ver >= 6):
                curl_vuln = 0
            else:
                curl_vuln = 0

            if (curl_vuln == 1):
                desc = 'The phpinfo()::cURL::file_support has a security hole'\
                       ' present in this version of PHP allows the cURL'\
                       ' functions to bypass safe_mode and open_basedir'\
                       ' restrictions.'
                v = Vuln('PHP curl_file_support:not_fixed', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/curl_file_support] ###

        ### [cgi_force_redirect] ###
        regex_str = 'cgi_force_redirect</td><td class="v">(.*?)</td>'
        cgi_force_redirect = re.search(regex_str, response.get_body(), re.I)
        if cgi_force_redirect:
            utd = cgi_force_redirect.group(1) + ''
            if (utd != 'On'):
                desc = 'The phpinfo()::CGI::force_redirect is disabled.'
                v = Vuln('PHP cgi_force_redirect: Off', desc, severity.MEDIUM,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/cgi_force_redirect] ###

        ### [session_cookie_httponly] ###
        regex_str = 'session\.cookie_httponly</td><td class="v">(Off|no|0)</td>'
        session_cookie_httponly = re.search(regex_str, response.get_body(),
                                            re.I)
        if session_cookie_httponly:
            desc = 'The phpinfo()::session.cookie_httponly is off.'
            v = Vuln('PHP session.cookie_httponly: Off', desc, severity.MEDIUM,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/session_cookie_httponly] ###

        ### [session_save_path] ###
        regex_str = 'session\.save_path</td><td class="v">(<i>no value</i>)</td>'
        session_save_path = re.search(regex_str, response.get_body(), re.I)
        if session_save_path:
            desc = 'The phpinfo()::session.save_path may be set to world-'\
                   'accessible directory.'
            v = Vuln('PHP session_save_path:Everyone', desc, severity.LOW,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/session_save_path] ###

        ### [session_use_trans] ###
        regex_str = 'session\.use_trans</td><td class="v">(On)</td>'
        session_use_trans = re.search(regex_str, response.get_body(), re.I)
        if session_use_trans:
            desc = 'The phpinfo()::session.use_trans is enabled. This makes'\
                   ' session hijacking easier.'
            v = Vuln('PHP session_use_trans: On', desc, severity.MEDIUM,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/session_use_trans] ###

        ### [default_charset] ###
        regex_str = 'default_charset</td><td class="v">(Off|no|0)</td>'
        default_charset = re.search(regex_str, response.get_body(), re.I)
        if default_charset:
            desc = 'The phpinfo()::default_charset is set to none. This'\
                   ' makes PHP scripts vulnerable to variable charset'\
                   ' encoding XSS.'
            v = Vuln('PHP default_charset: Off', desc, severity.MEDIUM,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/default_charset] ###

        ### [enable_dl] ###
        regex_str = 'enable_dl</td><td class="v">(On|Off)</td>'
        enable_dl = re.search(regex_str, response.get_body(), re.I)
        ed_flag = ''
        if enable_dl:
            rg = enable_dl.group(1)
            if (rg == 'On'):
                desc = 'The phpinfo()::enable_dl is on.'
                v = Vuln('PHP enable_dl: On', desc, severity.MEDIUM,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                ed_flag = 'info'
                ed_name = 'PHP enable_dl: Off'
                ed_desc = 'The phpinfo()::enable_dl is off.'
        ### [/enable_dl] ###

        ### [memory_limit] ###
        regex_str = 'memory_limit</td><td class="v">(\d.*?)</td>'
        memory_limit = re.search(regex_str, response.get_body(), re.I)
        if memory_limit:
            secure_ml = 10
            ml = memory_limit.group(1) + ''
            ml = ml.replace('M', '')
            if (ml > secure_ml):
                desc = 'The phpinfo()::memory_limit is set to higher value'\
                       ' (%s).' % memory_limit.group(1)
                v = Vuln('PHP memory_limit:high', desc, severity.MEDIUM,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/memory_limit] ###

        ### [post_max_size] ###
        regex_str = 'post_max_size</td><td class="v">(\d.*?)</td>'
        post_max_size = re.search(regex_str, response.get_body(),
                                  re.IGNORECASE)
        if post_max_size:
            secure_pms = 20
            pms = post_max_size.group(1) + ''
            pms = pms.replace('M', '')
            pms = int(pms)
            if (pms > secure_pms):
                desc = 'The phpinfo()::post_max_size is set to higher value'\
                       ' (%s).' % post_max_size.group(1)
                v = Vuln('PHP post_max_size:high', desc, severity.LOW,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/post_max_size] ###

        ### [upload_max_filesize] ###
        regex_str = 'upload_max_filesize</td><td class="v">(\d.*?)</td>'
        upload_max_filesize = re.search(regex_str, response.get_body(),
                                        re.IGNORECASE)
        if upload_max_filesize:
            secure_umf = 20
            umf = upload_max_filesize.group(1) + ''
            umf = umf.replace('M', '')
            umf = int(umf)
            if (umf > secure_umf):
                desc = 'The phpinfo()::upload_max_filesize is set to higher'\
                       ' value (%s).' % upload_max_filesize.group(1)
                v = Vuln('PHP upload_max_filesize:high', desc, severity.LOW,
                         response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/upload_max_filesize] ###

        ### [upload_tmp_dir] ###
        regex_str = 'upload_tmp_dir</td><td class="v">(<i>no value</i>)</td>'
        upload_tmp_dir = re.search(regex_str, response.get_body(), re.I)
        if upload_tmp_dir:
            desc = 'The phpinfo()::upload_tmp_dir may be set to world-'\
                   'accessible directory.'
            v = Vuln('PHP upload_tmp_dir:Everyone', desc, severity.LOW,
                     response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/upload_tmp_dir] ###

        ##### [/Vulnerable Settings] #####
        ##### [Useful Informative Settings] #####
        ### [privilege] ###
        if lpt_flag == 'info':
            i = Info(lpt_name, lpt_desc, response.id, self.get_name())
            i.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/privilege] ###

        ### [register_globals]###
        if rg_flag == 'info':
            i = Info(rg_name, rg_desc, response.id, self.get_name())
            i.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/register_globals]###

        ### [enable_dl]###
        if ed_flag == 'info':
            i = Info(ed_name, ed_desc, response.id, self.get_name())
            i.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/enable_dl]###

        ### [file_uploads] ###
        regex_str = 'file_uploads</td><td class="v">(On|<i>no value</i>)</td>'
        file_uploads = re.search(regex_str, response.get_body(), re.IGNORECASE)
        if file_uploads:
            desc = 'The phpinfo()::file_uploads is enabled.'
            i = Info('PHP file_uploads: On', desc, response.id,
                     self.get_name())
            i.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/file_uploads] ###

        ### [magic_quotes_gpc] ###
        regex_str = 'magic_quotes_gpc</td><td class="v">(On|Off)</td>'
        magic_quotes_gpc = re.search(regex_str, response.get_body(), re.I)
        if magic_quotes_gpc:
            mqg = magic_quotes_gpc.group(1)

            if (mqg == 'On'):
                desc = 'The phpinfo()::magic_quotes_gpc is on.'
                i = Info('PHP magic_quotes_gpc: On', desc, response.id,
                         self.get_name())

            else:
                desc = 'The phpinfo()::magic_quotes_gpc is off.'
                i = Info('PHP magic_quotes_gpc: Off', desc, response.id,
                         self.get_name())

            i.set_url(response.get_url())
            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())

        ### [/magic_quotes_gpc] ###

        ### [open_basedir] ###
        regex_str = 'open_basedir</td><td class="v">(.*?)</td>'
        open_basedir = re.search(regex_str, response.get_body(), re.I)

        if open_basedir:
            obd = open_basedir.group(1)

            if (obd == '<i>no value</i>'):
                desc = 'The phpinfo()::open_basedir is not set.'
                i = Info('PHP open_basedir:disabled', desc, response.id,
                         self.get_name())

            else:
                desc = 'The phpinfo()::open_basedir is set to %s.'
                desc = desc % open_basedir.group(1)
                i = Info('PHP open_basedir:enabled', desc, response.id,
                         self.get_name())

            i.set_url(response.get_url())

        kb.kb.append(self, 'phpinfo', i)
        om.out.information(i.get_desc())
        ### [/open_basedir] ###

        ### [session_hash_function] ###
        regex_str = 'session\.hash_function</td><td class="v">(.*?)</td>'
        session_hash_function = re.search(regex_str, response.get_body(), re.I)
        if session_hash_function:

            if session_hash_function.group(1) == 0\
            or session_hash_function.group(1) != 'no':
                desc = 'The phpinfo()::session.hash_function use md5 algorithm.'
                i = Info('PHP session.hash_function:md5', desc, response.id,
                         self.get_name())
            else:
                desc = 'The phpinfo()::session.hash_function use sha algorithm.'
                i = Info('PHP session.hash_function:sha', desc, response.id,
                         self.get_name())

            i.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
Example #39
0
                sysinfo = re.search(regex_str, response.get_body(), re.I)

                if (php_version and sysinfo):
                    desc = 'The phpinfo() file was found at: %s. The version'\
                           ' of PHP is: "%s" and the system information is:'\
                           ' "%s".'
                    desc = desc % (response.get_url(), php_version.group(2),
                                   sysinfo.group(1))

                    v = Vuln('phpinfo() file found', desc, severity.MEDIUM,
                             response.id, self.get_name())
                    v.set_url(response.get_url())

                    kb.kb.append(self, 'phpinfo', v)
                    om.out.vulnerability(v.get_desc(),
                                         severity=v.get_severity())

                    if (self._has_audited == 0):
                        self.audit_phpinfo(response)
                        self._has_audited = 1

    def audit_phpinfo(self, response):
        """
        Scan for insecure php settings
        :author: Aung Khant (aungkhant[at]yehg.net)
        :return none

        two divisions: vulnerable settings and useful informative settings

        """
Example #40
0
    def audit_phpinfo(self, response):
        """
        Scan for insecure php settings
        :author: Aung Khant (aungkhant[at]yehg.net)
        :return none

        two divisions: vulnerable settings and useful informative settings

        """

        ##### [Vulnerable Settings] #####

        ### [register_globals] ###
        regex_str = 'register_globals</td><td class="v">(On|Off)</td>'
        register_globals = re.search(regex_str, response.get_body(), re.I)
        rg_flag = ''
        if register_globals:
            rg = register_globals.group(1)
            if(rg == 'On'):
                desc = 'The phpinfo()::register_globals is on.'
                v = Vuln('PHP register_globals: On', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                rg_flag = 'info'
                rg_name = 'PHP register_globals: Off'
                rg_desc = 'The phpinfo()::register_globals is off.'

        ### [/register_globals] ###

        ### [allow_url_fopen] ###
        regex_str = 'allow_url_fopen</td><td class="v">(On|<i>no value</i>)</td>'
        allow_url_fopen = re.search(regex_str, response.get_body(), re.I)
        if allow_url_fopen:
            desc = 'The phpinfo()::allow_url_fopen is enabled.'
            v = Vuln('PHP allow_url_fopen: On', desc,
                     severity.MEDIUM, response.id, self.get_name())
            v.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/allow_url_fopen] ###

        ### [allow_url_include] ###
        regex_str = 'allow_url_include</td><td class="v">(On|<i>no value</i>)</td>'
        allow_url_include = re.search(regex_str, response.get_body(), re.I)
        if allow_url_include:
            desc = 'The phpinfo()::allow_url_include is enabled.'
            v = Vuln('PHP allow_url_include: On', desc,
                     severity.MEDIUM, response.id, self.get_name())
            v.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/allow_url_include] ###

        ### [display_errors] ###
        regex_str = 'display_errors</td><td class="v">(On|<i>no value</i>)</td>'
        display_errors = re.search(regex_str, response.get_body(), re.I)
        if display_errors:
            desc = 'The phpinfo()::display_errors is enabled.'
            v = Vuln('PHP display_errors: On', desc,
                     severity.MEDIUM, response.id, self.get_name())
            v.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/display_errors] ###

        ### [expose_php] ###
        regex_str = 'expose_php</td><td class="v">(On|<i>no value</i>)</td>'
        expose_php = re.search(regex_str, response.get_body(), re.I)
        if expose_php:
            desc = 'The phpinfo()::expose_php is enabled.'
            v = Vuln('PHP expose_php: On', desc,
                     severity.MEDIUM, response.id, self.get_name())
            v.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/expose_php] ###

        ### [lowest_privilege_test] ###
        regex_str = 'User/Group </td><td class="v">(.*?)\((\d.*?)\)/(\d.*?)</td>'
        lowest_privilege_test = re.search(regex_str, response.get_body(), re.I)
        lpt_flag = ''
        if lowest_privilege_test:
            lpt_uname = lowest_privilege_test.group(1)
            lpt_uid = lowest_privilege_test.group(2)
            lpt_uid = int(lpt_uid)
            lpt_gid = lowest_privilege_test.group(3)
            if lpt_uid < 99 or lpt_gid < 99 or \
            re.match('root|apache|daemon|bin|operator|adm', lpt_uname, re.I):

                desc = 'phpinfo()::PHP may be executing as a higher privileged'\
                       ' group. Username: %s, UserID: %s, GroupID: %s.' 
                desc = desc % (lpt_uname, lpt_uid, lpt_gid)
                
                v = Vuln('PHP lowest_privilege_test:fail', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                lpt_flag = 'info'
                lpt_name = 'privilege:' + lpt_uname
                lpt_desc = 'phpinfo()::PHP is executing under '
                lpt_desc += 'username: '******', '
                lpt_desc += 'userID: ' + str(lpt_uid) + ', '
                lpt_desc += 'groupID: ' + lpt_gid
        ### [/lowest_privilege_test] ###

        ### [disable_functions] ###
        regex_str = 'disable_functions</td><td class="v">(.*?)</td>'
        disable_functions = re.search(regex_str, response.get_body(), re.I)
        if disable_functions:
            secure_df = 8
            df = disable_functions.group(1)
            dfe = df.split(',')
            if(len(dfe) < secure_df):
                desc = 'The phpinfo()::disable_functions are set to few.'
                v = Vuln('PHP disable_functions:few', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/disable_functions] ###

        ### [curl_file_support] ###
        regex_str = '<h1 class="p">PHP Version (\d).(\d).(\d)</h1>'
        curl_file_support = re.search(regex_str, response.get_body(), re.I)
        if curl_file_support:
            php_major_ver = curl_file_support.group(1)
            php_minor_ver = curl_file_support.group(2)
            php_rev_ver = curl_file_support.group(3)

            current_ver = php_major_ver + '.' + php_minor_ver + \
                '' + php_rev_ver
            current_ver = float(current_ver)
            php_major_ver = int(php_major_ver)
            php_minor_ver = int(php_minor_ver)
            php_rev_ver = int(php_rev_ver)

            cv4check = float(4.44)
            cv5check = float(5.16)
            curl_vuln = 1

            if(php_major_ver == 4):
                if (current_ver >= cv4check):
                    curl_vuln = 0
            elif (php_major_ver == 5):
                if (current_ver >= cv5check):
                    curl_vuln = 0
            elif (php_major_ver >= 6):
                curl_vuln = 0
            else:
                curl_vuln = 0

            if(curl_vuln == 1):
                desc = 'The phpinfo()::cURL::file_support has a security hole'\
                       ' present in this version of PHP allows the cURL'\
                       ' functions to bypass safe_mode and open_basedir'\
                       ' restrictions.'
                v = Vuln('PHP curl_file_support:not_fixed', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/curl_file_support] ###

        ### [cgi_force_redirect] ###
        regex_str = 'cgi_force_redirect</td><td class="v">(.*?)</td>'
        cgi_force_redirect = re.search(regex_str, response.get_body(), re.I)
        if cgi_force_redirect:
            utd = cgi_force_redirect.group(1) + ''
            if(utd != 'On'):
                desc = 'The phpinfo()::CGI::force_redirect is disabled.'
                v = Vuln('PHP cgi_force_redirect: Off', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/cgi_force_redirect] ###

        ### [session_cookie_httponly] ###
        regex_str = 'session\.cookie_httponly</td><td class="v">(Off|no|0)</td>'
        session_cookie_httponly = re.search(regex_str, response.get_body(), re.I)
        if session_cookie_httponly:
            desc = 'The phpinfo()::session.cookie_httponly is off.'
            v = Vuln('PHP session.cookie_httponly: Off', desc,
                     severity.MEDIUM, response.id, self.get_name())
            v.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/session_cookie_httponly] ###

        ### [session_save_path] ###
        regex_str = 'session\.save_path</td><td class="v">(<i>no value</i>)</td>'
        session_save_path = re.search(regex_str, response.get_body(), re.I)
        if session_save_path:
            desc = 'The phpinfo()::session.save_path may be set to world-'\
                   'accessible directory.'
            v = Vuln('PHP session_save_path:Everyone', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/session_save_path] ###

        ### [session_use_trans] ###
        regex_str = 'session\.use_trans</td><td class="v">(On)</td>'
        session_use_trans = re.search(regex_str, response.get_body(), re.I)
        if session_use_trans:
            desc = 'The phpinfo()::session.use_trans is enabled. This makes'\
                   ' session hijacking easier.'
            v = Vuln('PHP session_use_trans: On', desc,
                     severity.MEDIUM, response.id, self.get_name())
            v.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/session_use_trans] ###

        ### [default_charset] ###
        regex_str = 'default_charset</td><td class="v">(Off|no|0)</td>'
        default_charset = re.search(regex_str, response.get_body(), re.I)
        if default_charset:
            desc = 'The phpinfo()::default_charset is set to none. This'\
                   ' makes PHP scripts vulnerable to variable charset'\
                   ' encoding XSS.'
            v = Vuln('PHP default_charset: Off', desc,
                     severity.MEDIUM, response.id, self.get_name())
            v.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/default_charset] ###

        ### [enable_dl] ###
        regex_str = 'enable_dl</td><td class="v">(On|Off)</td>'
        enable_dl = re.search(regex_str, response.get_body(), re.I)
        ed_flag = ''
        if enable_dl:
            rg = enable_dl.group(1)
            if(rg == 'On'):
                desc = 'The phpinfo()::enable_dl is on.'
                v = Vuln('PHP enable_dl: On', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
            else:
                ed_flag = 'info'
                ed_name = 'PHP enable_dl: Off'
                ed_desc = 'The phpinfo()::enable_dl is off.'
        ### [/enable_dl] ###

        ### [memory_limit] ###
        regex_str = 'memory_limit</td><td class="v">(\d.*?)</td>'
        memory_limit = re.search(regex_str, response.get_body(), re.I)
        if memory_limit:
            secure_ml = 10
            ml = memory_limit.group(1) + ''
            ml = ml.replace('M', '')
            if(ml > secure_ml):
                desc = 'The phpinfo()::memory_limit is set to higher value'\
                       ' (%s).' % memory_limit.group(1)
                v = Vuln('PHP memory_limit:high', desc,
                         severity.MEDIUM, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/memory_limit] ###

        ### [post_max_size] ###
        regex_str = 'post_max_size</td><td class="v">(\d.*?)</td>'
        post_max_size = re.search(
            regex_str, response.get_body(), re.IGNORECASE)
        if post_max_size:
            secure_pms = 20
            pms = post_max_size.group(1) + ''
            pms = pms.replace('M', '')
            pms = int(pms)
            if(pms > secure_pms):
                desc = 'The phpinfo()::post_max_size is set to higher value'\
                       ' (%s).' % post_max_size.group(1)
                v = Vuln('PHP post_max_size:high', desc,
                         severity.LOW, response.id, self.get_name())
                v.set_url(response.get_url())

                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/post_max_size] ###

        ### [upload_max_filesize] ###
        regex_str = 'upload_max_filesize</td><td class="v">(\d.*?)</td>'
        upload_max_filesize = re.search(
            regex_str, response.get_body(), re.IGNORECASE)
        if upload_max_filesize:
            secure_umf = 20
            umf = upload_max_filesize.group(1) + ''
            umf = umf.replace('M', '')
            umf = int(umf)
            if(umf > secure_umf):
                desc = 'The phpinfo()::upload_max_filesize is set to higher'\
                       ' value (%s).' % upload_max_filesize.group(1)
                v = Vuln('PHP upload_max_filesize:high', desc,
                         severity.LOW, response.id, self.get_name())
                v.set_url(response.get_url())
                
                kb.kb.append(self, 'phpinfo', v)
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/upload_max_filesize] ###

        ### [upload_tmp_dir] ###
        regex_str = 'upload_tmp_dir</td><td class="v">(<i>no value</i>)</td>'
        upload_tmp_dir = re.search(regex_str, response.get_body(), re.I)
        if upload_tmp_dir:
            desc = 'The phpinfo()::upload_tmp_dir may be set to world-'\
                   'accessible directory.'
            v = Vuln('PHP upload_tmp_dir:Everyone', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
        ### [/upload_tmp_dir] ###

        ##### [/Vulnerable Settings] #####
        ##### [Useful Informative Settings] #####
        ### [privilege] ###
        if lpt_flag == 'info':
            i = Info(lpt_name, lpt_desc, response.id, self.get_name())
            i.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/privilege] ###

        ### [register_globals]###
        if rg_flag == 'info':
            i = Info(rg_name, rg_desc, response.id, self.get_name())
            i.set_url(response.get_url())

            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/register_globals]###

        ### [enable_dl]###
        if ed_flag == 'info':
            i = Info(ed_name, ed_desc, response.id, self.get_name())            
            i.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/enable_dl]###

        ### [file_uploads] ###
        regex_str = 'file_uploads</td><td class="v">(On|<i>no value</i>)</td>'
        file_uploads = re.search(regex_str, response.get_body(), re.IGNORECASE)
        if file_uploads:
            desc = 'The phpinfo()::file_uploads is enabled.'
            i = Info('PHP file_uploads: On', desc, response.id, self.get_name())
            i.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
        ### [/file_uploads] ###

        ### [magic_quotes_gpc] ###
        regex_str = 'magic_quotes_gpc</td><td class="v">(On|Off)</td>'
        magic_quotes_gpc = re.search(regex_str, response.get_body(), re.I)
        if magic_quotes_gpc:
            mqg = magic_quotes_gpc.group(1)
            
            if (mqg == 'On'):
                desc = 'The phpinfo()::magic_quotes_gpc is on.'
                i = Info('PHP magic_quotes_gpc: On', desc, response.id,
                         self.get_name())
                
            else:
                desc = 'The phpinfo()::magic_quotes_gpc is off.'
                i = Info('PHP magic_quotes_gpc: Off', desc, response.id,
                         self.get_name())
                
            i.set_url(response.get_url())
            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())

        ### [/magic_quotes_gpc] ###

        ### [open_basedir] ###
        regex_str = 'open_basedir</td><td class="v">(.*?)</td>'
        open_basedir = re.search(regex_str, response.get_body(), re.I)

        if open_basedir:
            obd = open_basedir.group(1)

            if(obd == '<i>no value</i>'):
                desc = 'The phpinfo()::open_basedir is not set.'
                i = Info('PHP open_basedir:disabled', desc, response.id,
                         self.get_name())

            else:
                desc = 'The phpinfo()::open_basedir is set to %s.'
                desc = desc % open_basedir.group(1)
                i = Info('PHP open_basedir:enabled', desc, response.id,
                         self.get_name())
            
            i.set_url(response.get_url())

        kb.kb.append(self, 'phpinfo', i)
        om.out.information(i.get_desc())
        ### [/open_basedir] ###

        ### [session_hash_function] ###
        regex_str = 'session\.hash_function</td><td class="v">(.*?)</td>'
        session_hash_function = re.search(regex_str, response.get_body(), re.I)
        if session_hash_function:
            
            if session_hash_function.group(1) == 0\
            or session_hash_function.group(1) != 'no':
                desc = 'The phpinfo()::session.hash_function use md5 algorithm.'
                i = Info('PHP session.hash_function:md5', desc, response.id,
                         self.get_name())
            else:
                desc = 'The phpinfo()::session.hash_function use sha algorithm.'
                i = Info('PHP session.hash_function:sha', desc, response.id,
                         self.get_name())

            i.set_url(response.get_url())
            
            kb.kb.append(self, 'phpinfo', i)
            om.out.information(i.get_desc())
Example #41
0
                if (php_version and sysinfo):
                    desc = 'The phpinfo() file was found at: %s. The version'\
                           ' of PHP is: "%s" and the system information is:'\
                           ' "%s".'
                    desc = desc % (response.get_url(),
                                   php_version.group(2),
                                   sysinfo.group(1))
                    
                    v = Vuln('phpinfo() file found', desc, severity.MEDIUM,
                             response.id, self.get_name())
                    v.set_url(response.get_url())

                    kb.kb.append(self, 'phpinfo', v)
                    om.out.vulnerability(v.get_desc(),
                                         severity=v.get_severity())
                    
                    if (self._has_audited == 0):
                        self.audit_phpinfo(response)
                        self._has_audited = 1

    def audit_phpinfo(self, response):
        """
        Scan for insecure php settings
        :author: Aung Khant (aungkhant[at]yehg.net)
        :return none

        two divisions: vulnerable settings and useful informative settings

        """
Example #42
0
                  'using author.dll was there: %s' % e
            om.out.debug(msg)
        else:
            # The file we uploaded has the reversed filename as body
            if res.get_body() == rand_file[::-1] and not is_404(res):
                desc = 'An insecure configuration in the frontpage extensions'\
                       ' allows unauthenticated users to upload files to the'\
                       ' remote web server.'
                
                v = Vuln('Insecure Frontpage extensions configuration', desc,
                         severity.HIGH, [upload_id, res.id], self.get_name())

                v.set_url(target_url)
                v.set_method('POST')
                
                om.out.vulnerability(v.get_desc(), severity=v.get_severity())
                self.kb_append(self, 'frontpage', v)
            else:
                msg = 'The file that was uploaded using the POST method is'\
                      ' not present on the remote web server at "%s".'
                om.out.debug(msg % target_url)

    def get_plugin_deps(self):
        """
        :return: A list with the names of the plugins that should be run before the
        current one.
        """
        return ['infrastructure.frontpage_version']

    def get_long_desc(self):
        """
Example #43
0
    def _check_and_analyze(self, domain_path):
        """
        Check if a .listing filename exists in the domain_path.
        :return: None, everything is saved to the self.out_queue.
        """
        url = domain_path.url_join('.listing')

        response = self._uri_opener.GET(url, cache=True)

        if is_404(response):
            return

        parsed_url_set = set()
        users = set()
        groups = set()

        # Check if it's a .listing file
        extracted_info = self._extract_info_from_listing(response.get_body())
        for username, group, filename in extracted_info:
            if filename in ('.', '..'):
                continue

            parsed_url_set.add(domain_path.url_join(filename))
            users.add(username)
            groups.add(group)

        self.worker_pool.map(self.http_get_and_parse, parsed_url_set)

        if parsed_url_set:
            desc = ('A .listing file was found at: "%s". The contents'
                    ' of this file disclose filenames.')
            desc %= (response.get_url())

            v = Vuln('.listing file found', desc, severity.LOW, response.id,
                     self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'dot_listing', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())

            fr = FuzzableRequest(response.get_url())
            self.output_queue.put(fr)

        real_users = set([u for u in users if not u.isdigit()])
        real_groups = set([g for g in groups if not g.isdigit()])

        if real_users or real_groups:
            desc = (
                'A .listing file which leaks operating system user names'
                ' and groups was identified at %s. The leaked users are %s,'
                ' and the groups are %s. This information can be used'
                ' during a bruteforce attack of the Web application,'
                ' SSH or FTP services.')
            desc %= (response.get_url(), ', '.join(real_users),
                     ', '.join(real_groups))

            v = Vuln('Operating system username and group leak', desc,
                     severity.LOW, response.id, self.get_name())
            v.set_url(response.get_url())

            kb.kb.append(self, 'dot_listing', v)
            om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #44
0
    def _send_and_check(self, repo_url, repo_get_files, repo, domain_path):
        """
        Check if a repository index exists in the domain_path.

        :return: None, everything is saved to the self.out_queue.
        """
        # Here we use the new http_get instead of http_get_and_parse because
        # we want to check BAD_HTTP_CODES and the response body (see below)
        # before we send the response to the core
        http_response = self.http_get(repo_url,
                                      binary_response=True,
                                      respect_size_limit=False,
                                      grep=False)

        if is_404(http_response):
            return

        if http_response.get_code() in self.BAD_HTTP_CODES:
            return

        if not http_response.get_body():
            return

        try:
            filenames = repo_get_files(http_response.get_raw_body())
        except Exception as e:
            # We get here when the HTTP response is NOT a 404, but the response
            # body couldn't be properly parsed. This is usually because of a false
            # positive in the is_404 function, OR a new version-format of the file
            # to be parsed.
            #
            # Log in order to be able to improve the framework.
            args = (e, repo_get_files.__name__, repo_url)
            om.out.debug('Got a "%s" exception while running "%s" on "%s"' % args)
            return

        parsed_url_set = set()

        for filename in self._clean_filenames(filenames):
            test_url = domain_path.url_join(filename)
            if test_url in self._analyzed_filenames:
                continue

            parsed_url_set.add(test_url)
            self._analyzed_filenames.add(filename)

        if not parsed_url_set:
            return

        self.worker_pool.map(self.http_get_and_parse, parsed_url_set)

        # After performing the checks (404, redirects, body is not empty, body
        # can be parsed, body actually had filenames inside) send the URL to the
        # core
        fr = FuzzableRequest(repo_url, method='GET')
        self.output_queue.put(fr)

        # Now we send this finding to the report for manual analysis
        desc = ('A %s was found at: "%s"; this could indicate that a %s is'
                ' accessible. You might be able to download the Web'
                ' application source code.')
        desc %= (repo, http_response.get_url(), repo)

        v = Vuln('Source code repository', desc, severity.MEDIUM,
                 http_response.id, self.get_name())
        v.set_url(http_response.get_url())

        kb.kb.append(self, repo, v)
        om.out.vulnerability(v.get_desc(), severity=v.get_severity())
Example #45
0
    def _analyze_crossdomain_clientaccesspolicy(self, url, response, file_name):

        # https://github.com/andresriancho/w3af/issues/14491
        if file_name not in self.FILE_TAG_ATTR:
            return

        try:
            dom = xml.dom.minidom.parseString(response.get_body())
        except Exception:
            # Report this, it may be interesting for the final user
            # not a vulnerability per-se... but... it's information after all
            if 'allow-access-from' in response.get_body() or \
            'cross-domain-policy' in response.get_body() or \
            'cross-domain-access' in response.get_body():

                desc = 'The "%s" file at: "%s" is not a valid XML.'
                desc %= (file_name, response.get_url())

                i = Info('Invalid RIA settings file', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())

                kb.kb.append(self, 'info', i)
                om.out.information(i.get_desc())

            return

        tag, attribute = self.FILE_TAG_ATTR.get(file_name)
        url_list = dom.getElementsByTagName(tag)

        for url in url_list:
            url = url.getAttribute(attribute)

            if url == '*':
                desc = 'The "%s" file at "%s" allows flash / silverlight'\
                       ' access from any site.'
                desc %= (file_name, response.get_url())

                v = Vuln('Insecure RIA settings', desc, severity.LOW,
                         response.id, self.get_name())
                v.set_url(response.get_url())
                v.set_method('GET')

                kb.kb.append(self, 'vuln', v)
                om.out.vulnerability(v.get_desc(),
                                     severity=v.get_severity())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)

            else:
                desc = 'The "%s" file at "%s" allows flash / silverlight'\
                       ' access from "%s".'
                desc %= (file_name, response.get_url(), url)

                i = Info('Cross-domain allow ACL', desc, response.id,
                         self.get_name())
                i.set_url(response.get_url())
                i.set_method('GET')

                kb.kb.append(self, 'info', i)
                om.out.information(i.get_desc())

                fr = FuzzableRequest.from_http_response(response)
                self.output_queue.put(fr)