Esempio n. 1
0
        max_target_url = int(config['Common']['max_target_url'])
        max_target_byte = int(config['Common']['max_target_byte'])
        clipping_regex = config['Common']['clipping_regex']
        clipping_size = int(config['Common']['clipping_size'])
        if clipping_size <= 0:
            clipping_size = 10000
        clipping_buff = int(config['Common']['clipping_buff'])
        if clipping_buff <= 0:
            clipping_buff = 200
        clipping_mark = config['Common']['clipping_mark']
        if int(config['Common']['scramble']) == 1:
            is_scramble = True

    except Exception as e:
        msg = 'Reading config.ini is failure : {}'.format(e)
        utility.print_exception(e, msg)
        utility.write_log(40, msg)
        utility.write_log(20, '[Out] GyoiThon [{}].'.format(file_name))
        exit(1)

    # Show banner.
    show_banner(utility)

    # Create signature and train data.
    if opt_develop:
        creator = Creator(utility)
        creator.extract_file_structure(opt_develop_category, opt_develop_vendor, opt_develop_package)
        print(os.path.basename(__file__) + ' finish!!')
        utility.write_log(20, '[Out] GyoiThon [{}].'.format(file_name))
        sys.exit(0)
Esempio n. 2
0
    max_target_url = 0
    max_target_byte = 0
    is_scramble = False
    try:
        log_dir = config['Common']['log_path']
        log_path = os.path.join(full_path, log_dir)
        method_crawl = config['Common']['method_crawl']
        method_log = config['Common']['method_log']
        max_target_url = int(config['Common']['max_target_url'])
        max_target_byte = int(config['Common']['max_target_byte'])
        if int(config['Common']['scramble']) == 1:
            is_scramble = True

    except Exception as e:
        msg = 'Reading config.ini is failure : {}'.format(e)
        utility.print_exception(e, msg)
        utility.write_log(40, msg)
        utility.write_log(20, '[Out] GyoiThon [{}].'.format(file_name))
        exit(1)

    # Show banner.
    show_banner(utility)

    # Create instances.
    cloud_checker = CloudChecker(utility)
    version_checker = VersionChecker(utility)
    version_checker_ml = VersionCheckerML(utility)
    comment_checker = CommentChecker(utility)
    error_checker = ErrorChecker(utility)
    page_checker = PageChecker(utility)
    google_hack = GoogleCustomSearch(utility)
Esempio n. 3
0
class Msgrpc:
    def __init__(self, option=[]):
        self.utility = Utilty()
        self.host = option.get('host') or "127.0.0.1"
        self.port = option.get('port') or 55552
        self.uri = option.get('uri') or "/api/"
        self.ssl = option.get('ssl') or False
        self.authenticated = False
        self.token = False
        self.headers = {"Content-type": "binary/message-pack"}
        if self.ssl:
            self.client = http.client.HTTPSConnection(self.host, self.port)
        else:
            self.client = http.client.HTTPConnection(self.host, self.port)

    # Call RPC API.
    def call(self, meth, option):
        if meth != "auth.login":
            if not self.authenticated:
                self.utility.print_message(FAIL, 'MsfRPC: Not Authenticated')
                exit(1)

        if meth != "auth.login":
            option.insert(0, self.token)

        option.insert(0, meth)
        params = msgpack.packb(option)
        self.client.request("POST", self.uri, params, self.headers)
        resp = self.client.getresponse()
        return msgpack.unpackb(resp.read())

    # Log in to RPC Server.
    def login(self, user, password):
        ret = self.call('auth.login', [user, password])
        if ret.get(b'result') == b'success':
            self.authenticated = True
            self.token = ret.get(b'token')
            return True
        else:
            self.utility.print_message(FAIL, 'MsfRPC: Not Authenticated')
            exit(1)

    # Send Metasploit command.
    def send_command(self, console_id, command, visualization, sleep=0.1):
        _ = self.call('console.write', [console_id, command])
        time.sleep(sleep)
        ret = self.call('console.read', [console_id])
        if visualization:
            try:
                self.utility.print_message(
                    NONE, '{}'.format(ret.get(b'data').decode('utf-8')))
            except Exception as e:
                self.utility.print_exception(e, 'Send_command is exception.')
        return ret

    # Get all modules.
    def get_module_list(self, module_type):
        ret = {}
        if module_type == 'exploit':
            ret = self.call('module.exploits', [])
        elif module_type == 'auxiliary':
            ret = self.call('module.auxiliary', [])
        elif module_type == 'post':
            ret = self.call('module.post', [])
        elif module_type == 'payload':
            ret = self.call('module.payloads', [])
        elif module_type == 'encoder':
            ret = self.call('module.encoders', [])
        elif module_type == 'nop':
            ret = self.call('module.nops', [])
        byte_list = ret[b'modules']
        string_list = []
        for module in byte_list:
            string_list.append(module.decode('utf-8'))
        return string_list

    # Get module detail information.
    def get_module_info(self, module_type, module_name):
        return self.call('module.info', [module_type, module_name])

    # Get payload that compatible module.
    def get_compatible_payload_list(self, module_name):
        ret = self.call('module.compatible_payloads', [module_name])
        byte_list = ret[b'payloads']
        string_list = []
        for module in byte_list:
            string_list.append(module.decode('utf-8'))
        return string_list

    # Get payload that compatible target.
    def get_target_compatible_payload_list(self, module_name, target_num):
        ret = self.call('module.target_compatible_payloads',
                        [module_name, target_num])
        byte_list = ret[b'payloads']
        string_list = []
        for module in byte_list:
            string_list.append(module.decode('utf-8'))
        return string_list

    # Get module options.
    def get_module_options(self, module_type, module_name):
        return self.call('module.options', [module_type, module_name])

    # Execute module.
    def execute_module(self, module_type, module_name, options):
        ret = self.call('module.execute', [module_type, module_name, options])
        job_id = ret[b'job_id']
        uuid = ret[b'uuid'].decode('utf-8')
        return job_id, uuid

    # Get job list.
    def get_job_list(self):
        jobs = self.call('job.list', [])
        byte_list = jobs.keys()
        job_list = []
        for job_id in byte_list:
            job_list.append(int(job_id.decode('utf-8')))
        return job_list

    # Get job detail information.
    def get_job_info(self, job_id):
        return self.call('job.info', [job_id])

    # Stop job.
    def stop_job(self, job_id):
        return self.call('job.stop', [job_id])

    # Get session list.
    def get_session_list(self):
        return self.call('session.list', [])

    # Stop shell session.
    def stop_session(self, session_id):
        _ = self.call('session.stop', [str(session_id)])

    # Stop meterpreter session.
    def stop_meterpreter_session_kill(self, session_id):
        _ = self.call('session.meterpreter_session_kill', [str(session_id)])

    # Log out from RPC Server.
    def logout(self):
        ret = self.call('auth.logout', [self.token])
        if ret.get(b'result') == b'success':
            self.authenticated = False
            self.token = ''
            return True
        else:
            self.utility.print_message(FAIL, 'MsfRPC: Not Authenticated')
            exit(1)

    # Disconnection.
    def termination(self, console_id):
        # Kill a console.
        _ = self.call('console.session_kill', [console_id])
        # Log out
        _ = self.logout()
Esempio n. 4
0
class CreateReport:
    def __init__(self):
        self.util = Utilty()

        # Read config file.
        full_path = os.path.dirname(os.path.abspath(__file__))
        config = configparser.ConfigParser()
        try:
            config.read(os.path.join(full_path, 'config.ini'))
        except Exception as err:
            self.util.print_exception(err, 'File exists error')
            sys.exit(1)

        self.report_date_format = config['Report']['date_format']
        self.report_test_path = os.path.join(full_path,
                                             config['Report']['report_test'])
        self.report_test_file = os.path.join(
            self.report_test_path, config['Report']['report_test_file'])
        self.template_test = config['Report']['template_test']
        self.report_train_path = os.path.join(self.report_test_path,
                                              config['Report']['report_train'])
        self.report_train_file = os.path.join(
            self.report_train_path, config['Report']['report_train_file'])
        self.template_train = config['Report']['template_train']
        self.header_train = str(config['Report']['header_train']).split('@')
        self.header_test = str(config['Report']['header_test']).split('@')

    def create_report(self, mode='train', start_date=None):
        # Check mode.
        if mode not in ['train', 'test']:
            self.util.print_message(FAIL, 'Invalid mode: {}'.format(mode))
            exit(1)

        # Gather reporting items.
        if mode == 'train':
            self.util.print_message(NOTE, 'Creating training report.')
            csv_file_list = glob.glob(
                os.path.join(self.report_train_path, '*.csv'))

            # Create DataFrame.
            content_list = []
            for file in csv_file_list:
                df = pd.read_csv(file, names=self.header_train, sep=',')
                df['date'] = pd.to_datetime(df['date'])
                selected_df = df[(start_date < df['date'])]
                content_list.append(selected_df)

            if len(content_list) != 0:
                df_csv = pd.concat(content_list).drop_duplicates().sort_values(
                    by=['ip', 'port'], ascending=True).reset_index(drop=True,
                                                                   col_level=1)

                items = []
                for idx in range(len(df_csv)):
                    items.append({
                        'ip_addr':
                        df_csv.loc[idx, 'ip'],
                        'port':
                        df_csv.loc[idx, 'port'],
                        'prod_name':
                        df_csv.loc[idx, 'service'],
                        'vuln_name':
                        df_csv.loc[idx, 'vuln_name'],
                        'description':
                        df_csv.loc[idx, 'description'],
                        'type':
                        df_csv.loc[idx, 'type'],
                        'exploit':
                        df_csv.loc[idx, 'exploit'],
                        'target':
                        df_csv.loc[idx, 'target'],
                        'payload':
                        df_csv.loc[idx, 'payload'],
                        'ref':
                        str(df_csv.loc[idx, 'reference']).replace('@', '<br>')
                    })

                try:
                    # Setting template.
                    env = Environment(
                        loader=FileSystemLoader(self.report_train_path))
                    template = env.get_template(self.template_train)
                    pd.set_option('display.max_colwidth', -1)
                    html = template.render({
                        'title': 'Deep Exploit Scan Report',
                        'items': items
                    })

                    # Write report.
                    with codecs.open(self.report_train_file, 'w',
                                     'utf-8') as fout:
                        fout.write(html)
                except Exception as err:
                    self.util.print_exception(err, 'Creating report error.')
            else:
                self.util.print_message(WARNING,
                                        'Exploitation result is not found.')
            self.util.print_message(OK, 'Creating training report done.')
        else:
            self.util.print_message(NOTE, 'Creating testing report.')
            csv_file_list = glob.glob(
                os.path.join(self.report_test_path, '*.csv'))

            # Create DataFrame.
            content_list = []
            for file in csv_file_list:
                df = pd.read_csv(file, names=self.header_test, sep=',')
                df['date'] = pd.to_datetime(df['date'])
                selected_df = df[(start_date < df['date'])]
                content_list.append(selected_df)

            if len(content_list) != 0:
                df_csv = pd.concat(content_list).drop_duplicates().sort_values(
                    by=['ip', 'port'], ascending=True).reset_index(drop=True,
                                                                   col_level=1)

                items = []
                for idx in range(len(df_csv)):
                    items.append({
                        'ip_addr':
                        df_csv.loc[idx, 'ip'],
                        'port':
                        df_csv.loc[idx, 'port'],
                        'source_ip_addr':
                        df_csv.loc[idx, 'src_ip'],
                        'prod_name':
                        df_csv.loc[idx, 'service'],
                        'vuln_name':
                        df_csv.loc[idx, 'vuln_name'],
                        'description':
                        df_csv.loc[idx, 'description'],
                        'type':
                        df_csv.loc[idx, 'type'],
                        'exploit':
                        df_csv.loc[idx, 'exploit'],
                        'target':
                        df_csv.loc[idx, 'target'],
                        'payload':
                        df_csv.loc[idx, 'payload'],
                        'ref':
                        str(df_csv.loc[idx, 'reference']).replace('@', '<br>')
                    })

                try:
                    # Setting template.
                    env = Environment(
                        loader=FileSystemLoader(self.report_test_path))
                    template = env.get_template(self.template_test)
                    pd.set_option('display.max_colwidth', -1)
                    html = template.render({
                        'title': 'Deep Exploit Scan Report',
                        'items': items
                    })

                    # Write report.
                    with codecs.open(self.report_test_file, 'w',
                                     'utf-8') as fout:
                        fout.write(html)
                except Exception as err:
                    self.util.print_exception(err, 'Creating report error.')
            else:
                self.util.print_message(WARNING,
                                        'Exploitation result is not found.')
            self.util.print_message(OK, 'Creating testing report done.')
Esempio n. 5
0
        web_target_info = utility.run_spider(scheme, ip_list[idx],
                                             port_list[idx], path_list[idx])

        # Get HTTP responses.
        log_file = os.path.join(
            full_path + '/gyoithon/',
            'get_' + ip_list[idx] + '_' + str(port_list[idx]) + '_ip.log')
        create_webconf(ip_list[idx], port_list[idx], log_file)
        for target in web_target_info:
            for target_url in target[2]:
                # Check target url.
                parsed = None
                try:
                    parsed = util.parse_url(target_url)
                except Exception as err:
                    utility.print_exception(
                        err, 'Parsed error: {}'.format(target_url))
                    continue

                # Get HTTP response (header + body).
                response = ''
                http = urllib3.PoolManager(timeout=utility.http_timeout)
                try:
                    utility.print_message(
                        OK, '{}  {}'.format(
                            utility.get_current_date('%Y-%m-%d %H:%M:%S'),
                            target_url))
                    res = http.request('GET', target_url)
                    for header in res.headers.items():
                        response += header[0] + ': ' + header[1] + '\r\n'
                    response += '\r\n\r\n' + res.data.decode('utf-8')
Esempio n. 6
0
class DeepClassifier:
    def __init__(self):
        # Read config.ini.
        self.utility = Utilty()
        config = configparser.ConfigParser()
        self.full_path = os.path.dirname(os.path.abspath(__file__))
        self.root_path = os.path.join(self.full_path, '../')
        try:
            config.read(os.path.join(self.full_path, 'config.ini'))
        except FileExistsError as err:
            self.utility.print_exception(err,
                                         'File exists error: {0}'.format(err))
            sys.exit(1)
        self.category_type = config['Common']['category']
        self.train_path = os.path.join(self.full_path,
                                       config['GyoiClassifier']['train_path'])
        self.trained_path = os.path.join(
            self.full_path, config['GyoiClassifier']['trained_path'])
        self.train_os_in = os.path.join(
            self.train_path, config['GyoiClassifier']['train_os_in'])
        self.train_os_out = os.path.join(
            self.trained_path, config['GyoiClassifier']['train_os_out'])
        self.train_web_in = os.path.join(
            self.train_path, config['GyoiClassifier']['train_web_in'])
        self.train_web_out = os.path.join(
            self.trained_path, config['GyoiClassifier']['train_web_out'])
        self.train_framework_in = os.path.join(
            self.train_path, config['GyoiClassifier']['train_framework_in'])
        self.train_framework_out = os.path.join(
            self.trained_path, config['GyoiClassifier']['train_framework_out'])
        self.train_cms_in = os.path.join(
            self.train_path, config['GyoiClassifier']['train_cms_in'])
        self.train_cms_out = os.path.join(
            self.trained_path, config['GyoiClassifier']['train_cms_out'])
        self.wait_for_banner = float(
            config['GyoiClassifier']['wait_for_banner'])
        self.maximum_display_num = int(
            config['GyoiClassifier']['maximum_display_num'])
        self.summary_path = os.path.join(self.full_path,
                                         config['GyoiThon']['summary_path'])
        self.summary_file = os.path.join(self.summary_path,
                                         config['GyoiThon']['summary_file'])
        return

    # Analysis using ML.
    def analyzer(self,
                 target_ip='',
                 target_port=0,
                 target_vhost='',
                 silent=False,
                 target_url='',
                 target_response=''):
        self.utility.print_message(
            NOTE, 'Analyzing gathered HTTP response using Machine Learning.')
        identified_list = []
        target_info = ''
        target_log = ''
        analyzing_text = ''
        if target_response == '':
            # Get GyoiThon's summary.
            df_origin = pd.read_csv(self.summary_file,
                                    encoding='utf-8').fillna('')
            df_selected_summary = df_origin[
                (df_origin['ip'] == target_ip)
                & (df_origin['port'] == target_port) &
                (df_origin['vhost'] == target_vhost)]

            # Get log file (webconf.csv)
            logfile_path = os.path.join(self.root_path,
                                        df_selected_summary.at[0, 'log'])
            fin = codecs.open(logfile_path, 'r', encoding='utf-8')
            analyzing_text = fin.read()
            fin.close()
            target_info = target_vhost + '(' + target_ip + '):' + str(
                target_port)
            target_log = logfile_path
        else:
            target_info = target_url
            target_log = 'not use'
            analyzing_text = target_response

        # Output result (header)
        # If silent mode is True, hidden target information.
        if silent is True:
            self.utility.print_message(
                WARNING, 'target host : *** hidden for silent mode. ***')
            self.utility.print_message(
                WARNING, 'target url  : *** hidden for silent mode. ***')
            self.utility.print_message(
                WARNING, 'target log  : *** hidden for silent mode. ***')
        else:
            self.utility.print_message(WARNING,
                                       'target host : {}'.format(target_info))
            self.utility.print_message(WARNING,
                                       'target url  : {}'.format(target_url))
            self.utility.print_message(WARNING,
                                       'target log  : {}'.format(target_log))
        self.utility.print_message(OK, 'judge :')

        # Predict product name each category (OS, Middleware, CMS..).
        list_category = self.category_type.split('@')
        print('-' * 42)
        for category in list_category:
            # Learning.
            if category == 'os':
                nb = self.train(self.train_os_in, self.train_os_out)
            elif category == 'web server':
                nb = self.train(self.train_web_in, self.train_web_out)
            elif category == 'framework':
                nb = self.train(self.train_framework_in,
                                self.train_framework_out)
            elif category == 'cms':
                nb = self.train(self.train_cms_in, self.train_cms_out)
            else:
                self.utility.print_message(FAIL,
                                           'Choose category is not found.')
                exit(1)

            # Predict product name.
            product, prob, keyword_list, classified_list = nb.classify(
                analyzing_text)

            # Output result of prediction (body).
            # If no feature, result is unknown.
            if len(keyword_list) == 0:
                self.utility.print_message(NOTE,
                                           'category : {}'.format(category))
                self.utility.print_message(WARNING, 'product  : unknown')
                self.utility.print_message(WARNING, 'too low probability.')
            else:
                sorted_classified_list = sorted(classified_list,
                                                key=lambda x: x[1],
                                                reverse=True)
                self.utility.print_message(NOTE,
                                           'category : {}'.format(category))
                for idx, item in enumerate(sorted_classified_list):
                    add_flag = True
                    if idx >= self.maximum_display_num:
                        break
                    # Delete duplicated result.
                    reason_list = []
                    for reason in item[2]:
                        reason_list.append(list(set(reason)))
                    # # If no feature, reason is "too few features".
                    if len(item[2]) == 0:
                        reason_list = 'too few features..'
                        add_flag = False
                    self.utility.print_message(NOTE,
                                               'ranking {}'.format(idx + 1))
                    self.utility.print_message(
                        OK, 'product     : {}'.format(item[0]))
                    self.utility.print_message(
                        OK,
                        'probability : {}'.format(round(item[1] * 100.0, 4)))
                    self.utility.print_message(
                        OK, 'reason      : {}'.format(reason_list))
                    # Add product for Exploit.
                    identified_list.append(item[0])
            self.utility.print_message(NONE, '-' * 42)

        # Output result of prediction (footer).
        self.utility.print_message(
            NOTE, 'done {}'.format(os.path.basename(__file__)))

        return list(set(identified_list))

    # Execute learning / Get learned data.
    def train(self, in_file, out_file):
        # If existing learned data (pkl), load learned data.
        nb = None
        if os.path.exists(out_file):
            with open(out_file, 'rb') as f:
                nb = pickle.load(f)
        # If no learned data, execute learning.
        else:
            # Read learning data.
            nb = NaiveBayes()
            fin = codecs.open(in_file, 'r', 'utf-8')
            lines = fin.readlines()
            fin.close()
            items = []

            for line in lines:
                words = line[:-2]
                train_words = words.split('@')
                items.append(train_words[1])
                nb.train(train_words[1], train_words[0])

            # Save learned data to pkl file.
            with open(out_file, 'wb') as f:
                pickle.dump(nb, f)
        return nb
Esempio n. 7
0
    utility.write_log(20, '[In] GyoiThon [{}].'.format(file_name))

    # Read config.ini.
    config = configparser.ConfigParser()
    config.read(os.path.join(full_path, 'config.ini'))

    # Common setting value.
    log_path = ''
    method_crawl = ''
    try:
        log_dir = config['Common']['log_path']
        log_path = os.path.join(full_path, log_dir)
        method_crawl = config['Common']['method_crawl']
    except Exception as e:
        msg = 'Reading config.ini is failure : {}'.format(e)
        utility.print_exception(e, msg)
        utility.write_log(40, msg)
        utility.write_log(20, '[Out] GyoiThon [{}].'.format(file_name))
        exit(1)

    # Show banner.
    show_banner(utility)

    # Create instances.
    cloud_checker = CloudChecker(utility)
    version_checker = VersionChecker(utility)
    comment_checker = CommentChecker(utility)
    error_checker = ErrorChecker(utility)
    page_checker = PageChecker(utility)
    google_hack = GoogleCustomSearch(utility)
    content_explorer = ContentExplorer(utility)
class CreateReport:
    def __init__(self):
        self.util = Utilty()

        # Read config file.
        full_path = os.path.dirname(os.path.abspath(__file__))
        config = configparser.ConfigParser()
        try:
            config.read(os.path.join(full_path, 'config.ini'))
        except Exception as err:
            self.util.print_exception(err, 'File exists error')
            sys.exit(1)

        self.report_path = os.path.join(full_path,
                                        config['Report']['report_path'])
        self.report_file = os.path.join(self.report_path,
                                        config['Report']['report_file'])
        self.template_file = config['Report']['template_file']
        self.header = str(config['Report']['header']).split('@')

    def create_report(self):
        self.util.print_message(NOTE, 'Creating report.')

        # Gather reporting items.
        csv_file_list = glob.glob(os.path.join(self.report_path, '*.csv'))

        # Create DataFrame.
        content_list = []
        for file in csv_file_list:
            content_list.append(pd.read_csv(file, names=self.header, sep=','))
        df_csv = pd.concat(content_list).drop_duplicates().sort_values(
            by=['ip', 'port'], ascending=True).reset_index(drop=True,
                                                           col_level=1)

        items = []
        for idx in range(len(df_csv)):
            items.append({
                'ip_addr':
                df_csv.loc[idx, 'ip'],
                'port':
                df_csv.loc[idx, 'port'],
                'prod_name':
                df_csv.loc[idx, 'service'],
                'vuln_name':
                df_csv.loc[idx, 'vuln_name'],
                'type':
                df_csv.loc[idx, 'type'],
                'description':
                df_csv.loc[idx, 'description'],
                'exploit':
                df_csv.loc[idx, 'exploit'],
                'target':
                df_csv.loc[idx, 'target'],
                'payload':
                df_csv.loc[idx, 'payload'],
                'ref':
                str(df_csv.loc[idx, 'reference']).replace('@', '<br>')
            })

        try:
            # Setting template.
            env = Environment(loader=FileSystemLoader(self.report_path))
            template = env.get_template(self.template_file)
            pd.set_option('display.max_colwidth', -1)
            html = template.render({
                'title': 'Deep Exploit Scan Report',
                'items': items
            })
            # Write report.
            with codecs.open(self.report_file, 'w', 'utf-8') as fout:
                fout.write(html)
        except Exception as err:
            self.util.print_exception(err, 'Creating report error.')
        self.util.print_message(OK, 'Created report.')
Esempio n. 9
0
class ClassifierSignature:
    def __init__(self):
        self.full_path = os.path.dirname(os.path.abspath(__file__))
        self.signature_path = os.path.join(self.full_path, 'signature')
        self.util = Utilty()

    # Identify product name.
    def identify_product(self, categoy, response):
        prod_info_list = []
        file_name = 'signature_' + categoy + '.txt'
        try:
            # Judge product using pattern matching.
            with codecs.open(os.path.join(self.signature_path, file_name), 'r', 'utf-8') as fin:
                matching_patterns = fin.readlines()
                for pattern in matching_patterns:
                    items = pattern.replace('\r', '').replace('\n', '').split('@')
                    product = items[0].lower()
                    signature = items[2]
                    list_match = re.findall(signature, response, flags=re.IGNORECASE)
                    if len(list_match) != 0:
                        # Check version.
                        version_info = ''
                        for target_string in list_match:
                            version_info = self.extract_version(target_string).lower()
                            if version_info != '':
                                break

                        # Add product name and version.
                        if str(items[1]) != '':
                            prod_info_list.append(product + '@' + str(items[1]))
                        elif version_info != '':
                            prod_info_list.append(product + '@' + version_info)
                        else:
                            prod_info_list.append(product + '@-')
        except Exception as err:
            self.util.print_message(WARNING, '{}'.format(err))
        return prod_info_list

    # Extract version.
    def extract_version(self, target_string):
        # Regression list for cutting version.
        regex_list = [r'(\d{1,3}\.\d{1,3}\.\d{1,3}).*',
                      r'(\d{1,3}\.\d{1,3}).*',
                      r'(\d{1,3}).*',
                      r'(\d{1,3}\.\d{1,3}[a-z]\d{1,3}).*',
                      r'(\d{1,3}\.\d{1,3}\.\d[a-z]{1,3}).*',
                      r'(\d\.[xX|\*]).*']

        version_info = ''
        for regex_pattern in regex_list:
            version_list = re.findall(regex_pattern, target_string)
            if len(version_list) != 0:
                version_info = str(version_list[0])
                break
        return version_info

    # Classifier product name using signatures.
    def classifier_signature(self, target_info, client):
        product_list = []
        for target in target_info:
            for target_url in target[2]:
                # Check target url.
                parsed = None
                try:
                    parsed = util.parse_url(target_url)
                except Exception as err:
                    self.util.print_exception(err, 'Parsed error: {}'.format(target_url))
                    continue

                # Get HTTP response (header + body).
                response = ''
                http = urllib3.PoolManager(timeout=self.util.http_timeout)
                try:
                    client.keep_alive()
                    self.util.print_message(OK, '{}  {}'.format(self.util.get_current_date('%Y-%m-%d %H:%M:%S'),
                                                               target_url))
                    res = http.request('GET', target_url)
                    for header in res.headers.items():
                        response += header[0] + ': ' + header[1] + '\r\n'
                    response += '\r\n\r\n' + res.data.decode('utf-8')
                except Exception as err:
                    self.util.print_exception(err, 'Target URL: {}'.format(target_url))
                    continue

                for category in ['os', 'web', 'framework', 'cms']:
                    prod_info = self.identify_product(category, self.util.delete_ctrl_char(response))
                    for product in prod_info:
                        port_num = 80
                        path_item = os.path.split(parsed.path)
                        if parsed.port is not None:
                            port_num = parsed.port
                        if path_item[0].endswith('/') is False:
                            product_list.append(product + '@' + str(port_num) + '@' + path_item[0] + '/')
                        else:
                            product_list.append(product + '@' + str(port_num) + '@' + path_item[0])
                time.sleep(1.0)

        # Delete duplication.
        uniq_product = []
        tmp_list = []
        for item in list(set(product_list)):
            tmp_item = item.split('@')
            tmp = tmp_item[0] + tmp_item[2]
            if tmp not in tmp_list:
                tmp_list.append(tmp)
                uniq_product.append(item)
        return uniq_product