예제 #1
0
    def _run_thread(self, path):
        """ makes a HTTP GET request to check if a file exists. to be used as
            a thread.

            :param directory:       the directory to search for files in
            :param word:            the file name to search for
            :return (list):         a list of found files
        """
        found_files = []

        # construct the url to be used in the GET request
        url = f'{self.main.get_host_url_base()}/'

        # make the GET request for the file
        resp = http_get_request(url + f'{path}', self.main.cookies)

        # check if the response code is a success code
        if (resp.status_code in self.main.success_codes):
            if self.main.options['verbose']:
                success(path, prepend='  ')

            found_files.append(path)

        # only return a list if files were actually found
        if found_files:
            return found_files
예제 #2
0
    def run_module(self):
        """ the entrypoint into the module.

            takes any found webpages and uses threads to extract params from
            the html.
        """
        info('Parsing HTML...')

        # get the list of found pages
        found_pages = self._get_previous_results('FileScanner')

        # if there are no found pages, theres no need to run this module
        if not found_pages:
            return

        # pass the found pages to threads
        with concurrent.futures.ProcessPoolExecutor() as executor:
            results = list(executor.map(self._run_thread, found_pages))

        # clean up the results from the threads
        final = []
        _ = [final.extend(p) for p in results if p]
        final = list(filter(None, final))

        # remove duplicate found parameters
        final = [i for n, i in enumerate(final) if i not in final[n + 1:]]

        if self.main.options['verbose']:
            for params in final:
                success(f'Found params: {params["action"]} '
                        f'({" ".join(params["params"])})', prepend='  ')

        self._save_scan_results(final, update_count=False)
예제 #3
0
    def _run_thread(self, form):
        """ search through form parameters to find anti-csrf tokens
        """
        if len(form) != 3:
            warning('Internal error, not enough form elements in CSRF')
            exit()

        # give the form data human friendly names
        method = form['method']
        page = form['action']
        params = form['params']

        # were only concerned with POST requests for CSRF
        if method == 'POST':

            # check if param names contain any anti-csrf token params
            if not any(csrf_name in params for csrf_name in self.csrf_fields):
                success(f'No anti-csrf tokens for: {page}/{",".join(params)}',
                        prepend='  ')
                return {
                    'method': method,
                    'page': page,
                    'parameter': params,
                    'payload': None
                }
예제 #4
0
    def reset_wordlist(self):
        conn = self.get_connection(self.db_paths['wordlist'])

        sql_statement = 'UPDATE wordlist SET count = 0 WHERE count > 0'
        self.execute_statement(conn, sql_statement)

        success('wordlist database has been reset successfully', prepend='  ')
예제 #5
0
    def show_previous_scans(self):
        """ Displays a list of past scans and allows user to select one.

            This method prints out a list of all the past scans saved in the
            'scans' database, along with their scan IDs. It prompts the user to
            enter the scan ID of the scan to be selected.

            Args:
                None

            Returns:
                the scan ID of the selected scan
        """
        info('Previous scans:')

        # store an instance of the 'scans' database
        scans_table = self.db.get_scan_db().table('scans')

        # get all the saved scans
        scans = scans_table.all()

        # loop through each scan
        for scan in scans:

            # print the scan details to stdout
            success(
                f'ID: {scan.doc_id},'
                f'Host: {scan["host"]}',
                f'Port: {scan["port"]}',
                f'Time: {scan["timestamp"]}', prepend='  ')

        # prompt the user to enter the scan ID of the scan to be selected
        # it will reject scan IDs which dont exist, and any input which is
        # not an int
        check = False
        while not check:
            try:
                choice = int(input('> '))

                if not self.db.scan_exists(choice):
                    warning(f'Scan ID: {choice} does not exist')
                else:
                    check = True
            except (ValueError):
                pass

        return choice
예제 #6
0
    def auto_crawl(self):
        """ recursively crawls all the links in a web application.

            Args:
                None

            Returns:
                None
        """
        # loop through all pages found so far
        loop_pages = self.found_pages
        for page in loop_pages:
            for link in self._parse_links(page):
                if link not in loop_pages:
                    success(f'Found page: {link}', prepend='  ')
                    loop_pages.append(link)

        self._save_scan_results(loop_pages, update_count=False)
예제 #7
0
    def _check_page_content(self, method, injection, param, page, page_text):
        assert(hasattr(self, "re_search_strings"))

        search_strings = self.re_search_strings

        if any([s in page_text for s in search_strings]):
            if not (page, param) in self.injectable_params:
                if self.main.options['verbose']:
                    success(f'Vulnerable parameter: {page} - {param} ({injection})',
                            prepend='  ')
                # self.injectable_params.append((page, param, injection))
                self.injectable_params.append({'method': method,
                                               'page': page,
                                               'parameter': param,
                                               'payload': injection})

            return True

        return False
예제 #8
0
    def _run_thread(self, word):
        """ makes a HTTP GET request to check if a directory exists. to be used
            as a thread.

            :param word:        the directory to scan for
            :return (string):   the directory if found
        """
        # check for restricted paths
        if self.main.restrict_paths and word in self.main.restrict_paths:
            return None

        # GET request to the directory
        url = f'{self.main.get_host_url_base()}/{word}/'
        resp = http_get_request(url, self.main.cookies)

        # check if the response code is a success code
        if (resp.status_code in self.main.success_codes):
            if self.main.options['verbose']:
                success(word, prepend='  ')
            return word
예제 #9
0
    def _parse_robots(self):
        # construct url for robots.txt
        url = f'{self.main.get_host_url_base()}/robots.txt'
        resp = http_get_request(url, self.main.cookies)

        dir_paths = []
        file_paths = []

        # checking is robots.txt exists
        if resp.status_code == 200:
            success('robots.txt found', prepend='  ')
            info('parsing robots.txt', prepend='  ')
            lines = resp.text.split('\n')

            # if there are no lines then theres nothing to do
            if not lines:
                return

            # loop through every line in robots.txt
            for line in lines:
                if line.startswith('Allow:') or line.startswith('Disallow:'):
                    path = line.split(': ')[1]
                    success(f'Found path: {path}', prepend='    ')

                    if not path:
                        continue

                    if path[:-1] == '/':
                        dir_paths.append(path)
                    else:
                        file_paths.append(path)

        if dir_paths:
            table = self.main.db.get_scan_db().table('directories_discovered')

            table.insert({"scan_id": self.main.id, "results": dir_paths})

        if file_paths:
            table = self.main.db.get_scan_db().table('files_discovered')

            table.insert({"scan_id": self.main.id, "results": file_paths})
예제 #10
0
    def proxy_response_handle(self, resp, path):
        """ Parses a response from the proxy.

            Args:
                resp:   the response from proxy. from 'requests' module
                path:   the path to the webpage for the request

            Returns:
                None
        """
        if self.main.base_dir in path:
            path = path.replace(self.main.base_dir, '/')

        if resp.status_code in self.main.success_codes:
            # get rid of any GET parameters in the path
            if '?' in path:
                path = path.split('?')[0]

            # we dont want to find files in restricted paths
            if path not in self.main.restrict_paths:

                # we dont want files which weve already found
                if path not in self.manual_found_pages:
                    # get the filename
                    file = os.path.normpath(path).split(os.path.sep)[-1]

                    if '.' in file:
                        # get the file extension
                        ext = file.split('.')[-1]

                        # we dont want file types not in the extension list
                        if f'.{ext}' in self.main.file_extensions:
                            self.manual_found_pages.append(path)
                            success(f'Found new page: {path}', prepend='    ')
                    else:
                        self.manual_found_pages.append(path)
                        success(f'Found new page: {path}', prepend='    ')
예제 #11
0
    def reset_scans(self):
        scans = self.get_scan_db()
        scans.purge_tables()

        success('scans database has been reset successfully', prepend='  ')
예제 #12
0
    def _run_thread(self, param):
        """ Checks for blind SQL injections by injecting payloads into
            parameters and checking the timing of the response from the server.

            Args:
                param:  the parameter to inject payloads into

            Returns:
                dict containing information about vulnerable parameter,
                or None if not vulnerable
        """
        method = param['method']
        page = param['action']

        self.injections = []
        self.injectable_params = []
        inject_params = param['params']

        assert (hasattr(self, "attack_strings"))
        attack_strings = self.attack_strings

        if method == 'GET':
            url = self._construct_get_url(page, inject_params)

            for p in inject_params:
                for injection in attack_strings:
                    resp = http_get_request(url, self.main.cookies)
                    normal_time = resp.elapsed

                    final_url = url.replace(f'{p}=test', f'{p}={injection}')
                    resp = http_get_request(final_url, self.main.cookies)
                    test_time = resp.elapsed

                    check_time = test_time - normal_time
                    if check_time.total_seconds() >= 5.0:
                        if self.main.options['verbose']:
                            success(
                                f'Vulnerable parameter: {page} - {p} ({injection})',
                                prepend='  ')
                        # self.injectable_params.append((page, param, injection))
                        self.injectable_params.append({
                            'method': method,
                            'page': page,
                            'parameter': p,
                            'payload': injection
                        })
                        break

        elif method == 'POST':
            # construct the url to make the request to
            url = f'{self.main.get_host_url_base()}/{page}'

            for p in inject_params:
                params = self._construct_post_params(inject_params)

                for injection in attack_strings:
                    resp = http_post_request(url, params, self.main.cookies)
                    normal_time = resp.elapsed

                    params[p] = injection
                    resp = http_post_request(url, params, self.main.cookies)
                    test_time = resp.elapsed

                    check_time = test_time - normal_time
                    if check_time.total_seconds() >= 5.0:
                        if self.main.options['verbose']:
                            success(
                                f'Vulnerable parameter: {page} - {p} ({injection})',
                                prepend='  ')
                        # self.injectable_params.append((page, param, injection))
                        self.injectable_params.append({
                            'method': method,
                            'page': page,
                            'parameter': p,
                            'payload': injection
                        })
                        break

        return self.injectable_params