Exemple #1
0
def main(url):
    apikey=fetchapikey()
    vt=VirusTotalPublicApi(apikey)
    response = vt.get_domain_report(url)
    if "error" in response.keys():
        apiresco="NaN"
        whoisres="NaN"
        subdomsi=[]
        resolute=[]
        whotulst=[]
        whoitime="WhoIs timestamp not found"
        dnsrecdt="DNS record date not found"
        scandate="Scan date not found"
        verbmesg="Please check your internet connection and the URL for typos and try again"
        reply = [apiresco, whoisres, subdomsi, resolute, whotulst, whoitime, dnsrecdt, scandate, verbmesg]
    else:
        apiresco=str(response["response_code"])
        whoisres=str(getwhoisres(response))
        whoitime=str(getwhoitime(response))
        dnsrecdt=str(getdnsrecdt(response))
        subdomsi=getsubdomsi(response)
        whotulst=getwhoisdat(response)
        resolute=getresolute(response)
        scandate=str(time.ctime(int(time.time())))
        verbmesg=response["results"]["verbose_msg"]
        reply=[apiresco,whoisres,subdomsi,resolute,whotulst,whoitime,dnsrecdt,scandate,verbmesg]
    return reply
    def test_get_domain_report(self):
        vt = PublicApi(API_KEY)

        try:
            print(json.dumps(vt.get_domain_report('www.wired.com'), sort_keys=False, indent=4))
        except Exception as e:
            self.fail(e)
Exemple #3
0
    def test_get_domain_report(self):
        vt = PublicApi(API_KEY)

        try:
            print json.dumps(vt.get_domain_report('www.wired.com'),
                             sort_keys=False,
                             indent=4)
        except Exception as e:
            self.fail(e)
Exemple #4
0
 def vt(self, domain, conf, verbose):
     print('## Searching subdomains in Virus Total')
     if conf["VirusTotal"]["type"] == "public":
         vt = PublicApi(conf["VirusTotal"]["key"])
     else:
         vt = PrivateApi(conf["VirusTotal"]["key"])
     res = vt.get_domain_report(domain)
     try:
         for d in res['results']['subdomains']:
             print(d)
     except KeyError:
         pass
Exemple #5
0
class VirusTotalChecker(AbstractUrlChecker):
    def __init__(self, api_key, *args, **kwargs):
        self.vt = VirusTotalPublicApi(api_key=api_key)

    @staticmethod
    def _get_site_voting(scans: dict) -> dict:
        res = {}
        for _, v in scans.items():
            key = v['result'].split(' ')[0]
            res[key] = res.get(key, 0) + 1

        return res

    @staticmethod
    def _get_site_risks(site_voting: dict):
        if site_voting is None:
            return None
        return SiteRiskValues.risk if any(
            site_voting.get(x, 0) > 0
            for x in BAD_SITES) else SiteRiskValues.safe

    @staticmethod
    def _get_site_classifications(categories):
        # TODO: @amihay current library doesn't return categories
        # use native Api
        return {}

    # TODO: handle other exception as well
    @retry(wait_exponential_multiplier=2,
           wait_exponential_max=1000,
           retry_on_exception=retry_if_api_limit)
    def _get_url_report(self, url, timeout):
        url_report = self.vt.get_url_report(this_url=url, timeout=timeout)
        if url_report['response_code'] == 204:  # api limier
            raise ApiLimitException()
        return url_report

    def _get(self, url, timeout=None, *args, **kwargs) -> UrlResult:
        url_report = self._get_url_report(url=url, timeout=timeout)
        domain_report = self.vt.get_domain_report(this_domain=url)
        site_voting = self._get_site_voting(
            url_report['results']
            ['scans']) if 'scans' in url_report['results'] else None
        site_classfications = self._get_site_classifications(domain_report)
        url_result = UrlResult(url=url,
                               site_voting=site_voting,
                               site_risk=self._get_site_risks(site_voting),
                               site_classification=site_classfications)
        return url_result
Exemple #6
0
def analyze_domain(domain):

    if domain in os.listdir(SCAN_RESULT_DIR):
        return

    print(domain)

    vt = VirusTotalPublicApi(API_KEY)

    domain_response = vt.get_domain_report(domain)

    if 'results' not in domain_response.keys():
        print('  - ERROR results not in domain_response keys')
        return True

    if domain_response['results']['verbose_msg'] == 'Domain not found':
        print('  - ERROR Domain not found')
        return True

    url_response = vt.get_url_report(domain)

    if 'results' not in url_response.keys():
        print('  - ERROR results not in url_response keys')
        return True


    if 'verbose_msg' in url_response['results'].keys() and url_response['results']['verbose_msg'] == 'Resource does not exist in the dataset': 
        vt.scan_url(domain)
        print('  - resource does not exist: asking scan')
        return False

        
    results = domain_response['results']

    if 'Websense ThreatSeeker category' in results.keys():
        url_response['Websense ThreatSeeker category'] = results['Websense ThreatSeeker category']

    if 'categories' in results.keys():
        url_response['categories'] = results['categories']

    if 'TrendMicro category' in results.keys():
        url_response['TrendMicro category'] = results['TrendMicro category']

    with open(os.path.join(SCAN_RESULT_DIR, domain), 'w') as data_file:
        data_file.write(json.dumps(url_response))

    return True
Exemple #7
0
def handle_domain(actapi: act.api.Act,
                  vtapi: VirusTotalApi,
                  domain: Text,
                  output_format: Text = "json") -> None:
    """Read IP address from stdin, query VirusTotal and
    output a JSON text readable by generic_uploaderr.py"""

    with no_ssl_verification():
        response = vtapi.get_domain_report(domain)

    try:
        results = response['results']
    except KeyError:
        logging.error("%s in handle_domain for %s", response, domain)
        sys.exit(1)

    if 'detected_urls' in results:
        for u in map(urllib.parse.urlparse,
                     [x['url'] for x in results['detected_urls']]):
            add_uri(actapi, 'fqdn', domain, list(u))
    if 'undetected_urls' in results:
        for u in map(urllib.parse.urlparse,
                     [x[0] for x in results['undetected_urls']]):
            add_uri(actapi, 'fqdn', domain, list(u))

    if 'resolutions' in results:
        for resolution in results['resolutions']:
            ip = resolution['ip_address']
            # To figure out what kind of IP address we have, let the ipaddress module
            # parse the string and test for instance type as the platform distinguishes
            # between IPv4 and IPv6 addresses.
            try:
                act.api.helpers.handle_fact(actapi.fact('resolvesTo').source(
                    'fqdn', domain).destination(*act.api.helpers.ip_obj(ip)),
                                            output_format=output_format)
            except ValueError:
                continue  # invalid address

    if 'detected_downloaded_samples' in results:
        for sample in results['detected_downloaded_samples']:
            my_uri = add_uri(actapi, 'fqdn', domain,
                             ['network', domain, '', '', '', ''])
            act.api.helpers.handle_fact(actapi.fact('at').source(
                'content', sample['sha256']).destination('uri', my_uri),
                                        output_format=output_format)
            act.api.helpers.handle_fact(actapi.fact('represents').source(
                'hash', sample['sha256']).destination('content',
                                                      sample['sha256']),
                                        output_format=output_format)
            handle_hexdigest(actapi,
                             vtapi,
                             sample['sha256'],
                             output_format=output_format)

    if 'detected_communicating_samples' in results:
        for sample in results['detected_communicating_samples']:
            my_uri = add_uri(actapi, 'fqdn', domain,
                             ['network', domain, '', '', '', ''])
            act.api.helpers.handle_fact(actapi.fact('connectsTo').source(
                'content', sample['sha256']).destination('uri', my_uri),
                                        output_format=output_format)
            act.api.helpers.handle_fact(actapi.fact('represents').source(
                'hash', sample['sha256']).destination('content',
                                                      sample['sha256']),
                                        output_format=output_format)
            handle_hexdigest(actapi,
                             vtapi,
                             sample['sha256'],
                             output_format=output_format)
Exemple #8
0
    # print("Urls: ",urls)

    # urls = re.findall('http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+', text)
    # print("Original string: ",text)
    # print("Urls: ",urls)

elif x == 4:
    # def(domain):
    url = raw_input("Enter the domain : ")
    pprint.pprint(threatcrowd.domain_report(url))

    print "**" * 80
    print "VIRUSTOTAL_REPORT " * 80

    vt = VirusTotalPublicApi(API_KEY_VT)
    response = vt.get_domain_report(url)
    print(json.dumps(response, sort_keys=False, indent=4))

    print " HYBRID_ANALYSIS " * 90
    hybrid = HybridAnalysisConnector().action_quick_scan_url(url)
    pprint.pprint(hybrid)

elif x == 5:
    # def (virus_name):
    av = raw_input("Enter the Virus Name : ")
    pprint.pprint(threatcrowd.antivirus_report(av))

else:
    print("Invalid input Please give a valid Input")

# import requests, json
    def _virustotal_function(self, event, *args, **kwargs):
        """Function: perform different scans on the following types:
            ip addresses
            hash - this will attempt to find an existing file report on the hash
            domain
            url - this will attempt to find an existing file report on the url. If none exist, a new scan is queued
            file - this will start a new scan for the file and queue for a report later.
        """
        try:
            validateFields(('incident_id', 'vt_type'), kwargs)  # required

            # Init RequestsCommon with app.config options
            rc = RequestsCommon(opts=self.opts, function_opts=self.options)

            # Create a VirusTotal instance with the API Token and any proxies gathered by RequestsCommon
            vt = VirusTotal(self.options['api_token'], rc.get_proxies())

            # Get the function parameters:
            incident_id = kwargs.get("incident_id")  # number
            artifact_id = kwargs.get("artifact_id")  # number
            attachment_id = kwargs.get("attachment_id")  # number
            vt_type = kwargs.get("vt_type")  # text
            vt_data = kwargs.get("vt_data")  # text

            self.log = logging.getLogger(__name__)
            self.log.info("incident_id: %s", incident_id)
            self.log.info("artifact_id: %s", artifact_id)
            self.log.info("attachment_id: %s", attachment_id)
            self.log.info("vt_type: %s", vt_type)
            self.log.info("vt_data: %s", vt_data)

            yield StatusMessage("starting...")

            # determine next steps based on the API call to make
            if vt_type.lower() == 'file':
                entity = get_input_entity(get_resilient_client(self.resilient),
                                          incident_id, attachment_id,
                                          artifact_id)
                # Create a temporary file to write the binary data to.
                with tempfile.NamedTemporaryFile(
                        'w+b', delete=False) as temp_file_binary:
                    # Write binary data to a temporary file. Make sure to close the file here...this
                    # code must work on Windows and on Windows the file cannot be opened a second time
                    # While open.  Floss will open the file again to read the data, so close before
                    # calling Floss.
                    temp_file_binary.write(entity["data"])
                    temp_file_binary.close()
                    try:
                        response = vt.scan_file(temp_file_binary.name,
                                                filename=entity["name"])
                    except Exception as err:
                        raise err
                    finally:
                        os.unlink(temp_file_binary.name)

                file_result = self.return_response(response,
                                                   vt.get_file_report,
                                                   time.time())

                ## was a sha-256 returned? try an existing report first
                if file_result.get("sha256"):
                    response = vt.get_file_report(file_result.get("sha256"))
                    report_result = self.return_response(
                        response, None, time.time())

                    if report_result.get(
                            "response_code") and report_result.get(
                                "response_code") == 1:
                        result = report_result
                    else:
                        result = file_result

            elif vt_type.lower() == 'url':
                # attempt to see if a report already exists
                response = vt.get_url_report(vt_data)
                result = self.return_response(response, None, time.time())

                # check if result is not found, meaning no report exists
                if result['response_code'] == RC_NOT_FOUND:
                    response = vt.scan_url(vt_data)
                    result = self.return_response(response, vt.get_url_report,
                                                  time.time())

            elif vt_type.lower() == 'ip':
                response = vt.get_ip_report(vt_data)
                result = self.return_response(response, None, time.time())

            elif vt_type.lower() == 'domain':
                response = vt.get_domain_report(vt_data)
                result = self.return_response(response, None, time.time())

            elif vt_type.lower() == 'hash':
                response = vt.get_file_report(vt_data)
                result = self.return_response(response, None, time.time())

            else:
                raise ValueError(
                    "Unknown type field: {}. Check workflow pre-processor script."
                    .format(vt_type))

            results = {"scan": result}

            self.log.debug("scan: {}".format(results))

            # Produce a FunctionResult with the results
            yield FunctionResult(results)
        except Exception:
            yield FunctionError()
Exemple #10
0
def handle_domain(
    actapi: act.api.Act,
    vtapi: VirusTotalApi,
    domain: Text,
    output_format: Text = "json",
) -> None:
    """Read IP address from stdin, query VirusTotal and
    output a JSON text readable by generic_uploaderr.py"""

    with no_ssl_verification():
        response = vtapi.get_domain_report(domain)

    try:
        results = response["results"]
    except KeyError:
        logging.error("%s in handle_domain for %s", response, domain)
        sys.exit(1)

    if "detected_urls" in results:
        for u in map(urllib.parse.urlparse,
                     [x["url"] for x in results["detected_urls"]]):
            add_uri(actapi, "fqdn", domain, list(u))
    if "undetected_urls" in results:
        for u in map(urllib.parse.urlparse,
                     [x[0] for x in results["undetected_urls"]]):
            add_uri(actapi, "fqdn", domain, list(u))

    if "resolutions" in results:
        for resolution in results["resolutions"]:
            ip = resolution["ip_address"]
            # To figure out what kind of IP address we have, let the ipaddress module
            # parse the string and test for instance type as the platform distinguishes
            # between IPv4 and IPv6 addresses.
            try:
                act.api.helpers.handle_fact(
                    actapi.fact("resolvesTo").source(
                        "fqdn",
                        domain).destination(*act.api.helpers.ip_obj(ip)),
                    output_format=output_format,
                )
            except ValueError:
                continue  # invalid address

    if "detected_downloaded_samples" in results:
        for sample in results["detected_downloaded_samples"]:
            my_uri = add_uri(actapi, "fqdn", domain,
                             ["network", domain, "", "", "", ""])
            act.api.helpers.handle_fact(
                actapi.fact("at").source("content",
                                         sample["sha256"]).destination(
                                             "uri", my_uri),
                output_format=output_format,
            )
            act.api.helpers.handle_fact(
                actapi.fact("represents").source("hash",
                                                 sample["sha256"]).destination(
                                                     "content",
                                                     sample["sha256"]),
                output_format=output_format,
            )
            handle_hexdigest(actapi,
                             vtapi,
                             sample["sha256"],
                             output_format=output_format)

    if "detected_communicating_samples" in results:
        for sample in results["detected_communicating_samples"]:
            my_uri = add_uri(actapi, "fqdn", domain,
                             ["network", domain, "", "", "", ""])
            act.api.helpers.handle_fact(
                actapi.fact("connectsTo").source("content",
                                                 sample["sha256"]).destination(
                                                     "uri", my_uri),
                output_format=output_format,
            )
            act.api.helpers.handle_fact(
                actapi.fact("represents").source("hash",
                                                 sample["sha256"]).destination(
                                                     "content",
                                                     sample["sha256"]),
                output_format=output_format,
            )
            handle_hexdigest(actapi,
                             vtapi,
                             sample["sha256"],
                             output_format=output_format)
Exemple #11
0
class VirusTotalAnalyzer(Analyzer):

    def __init__(self):
        Analyzer.__init__(self)
        self.service = self.get_param('config.service', None, 'Service parameter is missing')
        self.virustotal_key = self.get_param('config.key', None, 'Missing VirusTotal API key')
        self.polling_interval = self.get_param('config.polling_interval', 60)
        self.proxies = self.get_param('config.proxy', None)
        self.vt = VirusTotalPublicApi(self.virustotal_key, self.proxies)

    def wait_file_report(self, id):
        results = self.check_response(self.vt.get_file_report(id))
        code = results.get('response_code', None)
        if code == 1:
            self.report(results)
        else:
            time.sleep(self.polling_interval)
            self.wait_file_report(id)

    def wait_url_report(self, id):
        results = self.check_response(self.vt.get_url_report(id))
        code = results.get('response_code', None)
        if code == 1 and (results.get('scan_id') == id):
            self.report(results)
        else:
            time.sleep(self.polling_interval)
            self.wait_url_report(id)

    def check_response(self, response):
        if type(response) is not dict:
            self.error('Bad response : ' + str(response))
        status = response.get('response_code', -1)
        if status == 204:
            self.error('VirusTotal api rate limit exceeded (Status 204).')
        if status != 200:
            self.error('Bad status : ' + str(status))
        results = response.get('results', {})
        if 'Missing IP address' in results.get('verbose_msg', ''):
            results['verbose_msg'] = 'IP address not available in VirusTotal'
        return results

        # 0 => not found
        # -2 => in queue
        # 1 => ready

    def read_scan_response(self, response, func):
        results = self.check_response(response)
        code = results.get('response_code', None)
        scan_id = results.get('scan_id', None)
        if code == 1 and scan_id is not None:
            func(scan_id)
        else:
            self.error('Scan not found')

    def summary(self, raw):
        taxonomies = []
        level = "info"
        namespace = "VT"
        predicate = "GetReport"
        value = "0"

        if self.service == "scan":
            predicate = "Scan"

        result = {
            "has_result": True
        }

        if raw["response_code"] != 1:
            result["has_result"] = False

        result["positives"] = raw.get("positives", 0)
        result["total"] = raw.get("total", 0)

        if "scan_date" in raw:
            result["scan_date"] = raw["scan_date"]

        if self.service == "get":
            if "scans" in raw:
                result["scans"] = len(raw["scans"])
                value = "{}/{}".format(result["positives"], result["total"])
                if result["positives"] == 0:
                    level = "safe"
                elif result["positives"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"

            if "resolutions" in raw:
                result["resolutions"] = len(raw["resolutions"])
                value = "{} resolution(s)".format(result["resolutions"])
                if result["resolutions"] == 0:
                    level = "safe"
                elif result["resolutions"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"
            if "detected_urls" in raw:
                result["detected_urls"] = len(raw["detected_urls"])
                value = "{} detected_url(s)".format(result["detected_urls"])
                if result["detected_urls"] == 0:
                    level = "safe"
                elif result["detected_urls"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"

            if "detected_downloaded_samples" in raw:
                result["detected_downloaded_samples"] = len(
                    raw["detected_downloaded_samples"])

        if self.service == "scan":
            if "scans" in raw:
                result["scans"] = len(raw["scans"])
                value = "{}/{}".format(result["positives"], result["total"])
                if result["positives"] == 0:
                    level = "safe"
                elif result["positives"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"

        taxonomies.append(self.build_taxonomy(level, namespace, predicate, value))
        return {"taxonomies": taxonomies}

    def run(self):
        if self.service == 'scan':
            if self.data_type == 'file':
                filename = self.get_param('filename', 'noname.ext')
                filepath = self.get_param('file', None, 'File is missing')
                self.read_scan_response(
                    self.vt.scan_file(filepath, from_disk=True, filename=filename),
                    self.wait_file_report
                )
            elif self.data_type == 'url':
                data = self.get_param('data', None, 'Data is missing')
                self.read_scan_response(
                    self.vt.scan_url(data), self.wait_url_report)
            else:
                self.error('Invalid data type')
        elif self.service == 'get':
            if self.data_type == 'domain':
                data = self.get_param('data', None, 'Data is missing')
                self.report(self.check_response(
                    self.vt.get_domain_report(data)))
            elif self.data_type == 'fqdn':
                data = self.get_param('data', None, 'Data is missing')
                self.report(self.check_response(
                    self.vt.get_domain_report(data)))
            elif self.data_type == 'ip':
                data = self.get_param('data', None, 'Data is missing')
                self.report(self.check_response(self.vt.get_ip_report(data)))
            elif self.data_type == 'file':
                hashes = self.get_param('attachment.hashes', None)
                if hashes is None:
                    filepath = self.get_param('file', None, 'File is missing')
                    hash = hashlib.sha256(open(filepath, 'rb').read()).hexdigest()
                else:
                    # find SHA256 hash
                    hash = next(h for h in hashes if len(h) == 64)

                self.report(self.check_response(self.vt.get_file_report(hash)))
            elif self.data_type == 'hash':
                data = self.get_param('data', None, 'Data is missing')
                self.report(self.check_response(self.vt.get_file_report(data)))
            elif self.data_type == 'url':
                data = self.get_param('data', None, 'Data is missing')
                self.report(self.check_response(self.vt.get_url_report(data)))
            else:
                self.error('Invalid data type')
        else:
            self.error('Invalid service')
Exemple #12
0
class VirusTotalAnalyzer(Analyzer):
    def __init__(self):
        Analyzer.__init__(self)
        self.service = self.get_param("config.service", None,
                                      "Service parameter is missing")
        self.virustotal_key = self.get_param("config.key", None,
                                             "Missing VirusTotal API key")
        self.polling_interval = self.get_param("config.polling_interval", 60)
        self.rescan_hash_older_than_days = self.get_param(
            "config.rescan_hash_older_than_days", None)
        self.highlighted_antivirus = self.get_param(
            "config.highlighted_antivirus", None)
        self.download_sample = self.get_param("config.download_sample", False)
        self.download_sample_if_highlighted = self.get_param(
            "config.download_sample_if_highlighted", False)
        self.obs_path = None
        self.proxies = self.get_param("config.proxy", None)
        if (self.download_sample or self.download_sample_if_highlighted
                or self.service == "download"):
            self.vt_pay = PrivateApi(self.virustotal_key, self.proxies)
        self.vt = PublicApi(self.virustotal_key, self.proxies)

    def get_file(self, hash):
        self.obs_path = "{}/{}".format(tempfile.gettempdir(), hash)
        response = self.vt_pay.get_file(hash)
        if response.get("response_code", None) == 200:
            with open(self.obs_path, "wb") as f:
                f.write(response["results"])
            kind = filetype.guess(self.obs_path)
            if kind and kind.extension != None:
                os.rename(self.obs_path,
                          "{}.{}".format(self.obs_path, kind.extension))
                self.obs_path = "{}.{}".format(self.obs_path, kind.extension)

    def wait_file_report(self, id):
        results = self.check_response(self.vt.get_file_report(id))
        code = results.get("response_code", None)
        if code == 1:
            if self.data_type == "hash" and (
                    self.download_sample or
                (self.download_sample_if_highlighted
                 and self.highlighted_antivirus and any([
                     results.get("scans", {}).get(av, {}).get(
                         "detected", None) == False
                     for av in self.highlighted_antivirus
                 ]))):
                self.get_file(self.get_param("data", None, "Data is missing"))
            self.report(results)
        else:
            time.sleep(self.polling_interval)
            self.wait_file_report(id)

    def wait_url_report(self, id):
        results = self.check_response(self.vt.get_url_report(id))
        code = results.get("response_code", None)
        if code == 1 and (results.get("scan_id") == id):
            self.report(results)
        else:
            time.sleep(self.polling_interval)
            self.wait_url_report(id)

    def check_response(self, response):
        if type(response) is not dict:
            self.error("Bad response : " + str(response))
        status = response.get("response_code", -1)
        if status == 204:
            self.error("VirusTotal api rate limit exceeded (Status 204).")
        if status != 200:
            self.error("Bad status : " + str(status))
        results = response.get("results", {})
        if "Missing IP address" in results.get("verbose_msg", ""):
            results["verbose_msg"] = "IP address not available in VirusTotal"
        return results

        # 0 => not found
        # -2 => in queue
        # 1 => ready

    def read_scan_response(self, response, func):
        results = self.check_response(response)
        code = results.get("response_code", None)
        scan_id = results.get("scan_id", None)
        if code == 1 and scan_id is not None:
            func(scan_id)
        else:
            self.error("Scan not found")

    def artifacts(self, raw):
        artifacts = []
        if self.obs_path:
            tags = []
            # This will work only in scan/rescan workflow, not in download only
            if self.highlighted_antivirus:
                for av in self.highlighted_antivirus:
                    detected = raw.get("scans",
                                       {}).get(av, {}).get("detected", None)
                    if detected == False:
                        tags.append("to_{}".format(av))
            artifacts.append(
                self.build_artifact("file", self.obs_path, tags=tags))
        return artifacts

    def summary(self, raw):
        taxonomies = []
        level = "info"
        namespace = "VT"
        predicate = "GetReport"
        value = "0"

        if self.service == "scan":
            predicate = "Scan"
        elif self.service == "rescan":
            predicate = "Rescan"
        elif self.service == "download":
            return {"taxonomies": taxonomies}

        result = {"has_result": True}

        if raw["response_code"] != 1:
            result["has_result"] = False

        result["positives"] = raw.get("positives", 0)
        result["total"] = raw.get("total", 0)

        if "scan_date" in raw:
            result["scan_date"] = raw["scan_date"]

        if self.service == "get":
            if "scans" in raw:
                result["scans"] = len(raw["scans"])
                value = "{}/{}".format(result["positives"], result["total"])
                if result["positives"] == 0:
                    level = "safe"
                elif result["positives"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"

            if "resolutions" in raw:
                result["resolutions"] = len(raw["resolutions"])
                value = "{} resolution(s)".format(result["resolutions"])
                if result["resolutions"] == 0:
                    level = "safe"
                elif result["resolutions"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"

            if "detected_urls" in raw:
                result["detected_urls"] = len(raw["detected_urls"])
                value = "{} detected_url(s)".format(result["detected_urls"])
                if result["detected_urls"] == 0:
                    level = "safe"
                elif result["detected_urls"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"

            if "detected_downloaded_samples" in raw:
                result["detected_downloaded_samples"] = len(
                    raw["detected_downloaded_samples"])

        if self.service in ["scan", "rescan"]:
            if "scans" in raw:
                result["scans"] = len(raw["scans"])
                value = "{}/{}".format(result["positives"], result["total"])
                if result["positives"] == 0:
                    level = "safe"
                elif result["positives"] < 5:
                    level = "suspicious"
                else:
                    level = "malicious"

        taxonomies.append(
            self.build_taxonomy(level, namespace, predicate, value))

        if self.highlighted_antivirus:
            for av in self.highlighted_antivirus:
                detected = raw.get("scans", {}).get(av,
                                                    {}).get("detected", None)
                if detected == False:
                    taxonomies.append(
                        self.build_taxonomy("info", namespace, av,
                                            "Not detected!"))

        return {"taxonomies": taxonomies}

    def run(self):
        if self.service == "scan":
            if self.data_type == "file":
                filename = self.get_param("filename", "noname.ext")
                filepath = self.get_param("file", None, "File is missing")
                self.read_scan_response(
                    self.vt.scan_file(filepath,
                                      from_disk=True,
                                      filename=filename),
                    self.wait_file_report,
                )
            elif self.data_type == "url":
                data = self.get_param("data", None, "Data is missing")
                self.read_scan_response(self.vt.scan_url(data),
                                        self.wait_url_report)
            else:
                self.error("Invalid data type")

        elif self.service == "rescan":
            if self.data_type == "hash":
                data = self.get_param("data", None, "Data is missing")
                self.read_scan_response(self.vt.rescan_file(data),
                                        self.wait_file_report)
            else:
                self.error("Invalid data type")

        elif self.service == "download":
            if self.data_type == "hash":
                data = self.get_param("data", None, "Data is missing")
                self.get_file(data)
                self.report({"message": "file downloaded"})

        elif self.service == "get":
            if self.data_type == "domain":
                data = self.get_param("data", None, "Data is missing")
                results = self.check_response(self.vt.get_domain_report(data))

            elif self.data_type == "fqdn":
                data = self.get_param("data", None, "Data is missing")
                results = self.check_response(self.vt.get_domain_report(data))

            elif self.data_type == "ip":
                data = self.get_param("data", None, "Data is missing")
                results = self.check_response(self.vt.get_ip_report(data))

            elif self.data_type == "file":
                hashes = self.get_param("attachment.hashes", None)
                if hashes is None:
                    filepath = self.get_param("file", None, "File is missing")
                    hash = hashlib.sha256(open(filepath,
                                               "rb").read()).hexdigest()
                else:
                    hash = next(h for h in hashes if len(h) == 64)
                results = self.check_response(self.vt.get_file_report(hash))

            elif self.data_type == "hash":
                data = self.get_param("data", None, "Data is missing")
                results = self.check_response(self.vt.get_file_report(data))

            elif self.data_type == "url":
                data = self.get_param("data", None, "Data is missing")
                results = self.check_response(self.vt.get_url_report(data))
            else:
                self.error("Invalid data type")

            # if aged and enabled rescan
            if self.data_type == "hash" and self.rescan_hash_older_than_days:
                if (datetime.strptime(results["scan_date"],
                                      "%Y-%m-%d %H:%M:%S") - datetime.now()
                    ).days > self.rescan_hash_older_than_days:
                    self.read_scan_response(self.vt.rescan_file(data),
                                            self.wait_file_report)

            # download if hash, dangerous and not seen by av
            if (self.data_type == "hash"
                    and (results.get("response_code", None) == 1)
                    and (results.get("positives", 0) >= 5)
                    and (self.download_sample or
                         (self.download_sample_if_highlighted
                          and self.highlighted_antivirus and any([
                              results.get("scans", {}).get(av, {}).get(
                                  "detected", None) == False
                              for av in self.highlighted_antivirus
                          ])))):
                self.get_file(data)
            self.report(results)

        else:
            self.error("Invalid service")
Exemple #13
0
class VT(object):
    """
    Class to hold VirusTotal items.
    """

    #
    # FUNCTIONS
    #
    """
    Sets up a VirusTotal object with the public api.
    """
    def __init__(self, vtpublicapi):
        self.vtpublicapi = vtpublicapi
        self.vt = VirusTotalPublicApi(self.vtpublicapi)

    def add_headers(self, inputheaders):
        """
        Adds appropriate headers to input list.
        """
        inputheaders.append('VirusTotal Detected URLs')
        inputheaders.append('VirusTotal Detected Communicating Samples')
        inputheaders.append('VirusTotal Detected Downloaded Samples')
        inputheaders.append('VirusTotal Link')

    def add_row(self, host, inputrow):
        """
        Adds the pulled data to the input row.
        """

        vtdetectedurls = vtdetectedcommunicatingsamples = \
            vtdetecteddownloadedsamples = vturl = ''

        if libs.network.IsIPv4(host):
            vtresponse = self.vt.get_ip_report(host)
            while "response_code" not in vtresponse or \
                    (vtresponse["response_code"] != 200 and
                     vtresponse["response_code"] != 403):
                time.sleep(60)  # Sleep for the API throttling
                vtresponse = self.vt.get_ip_report(host)
            if "results" not in vtresponse:
                vtdetectedurls = "INVALID API KEY"
            elif "detected_urls" in vtresponse["results"]:
                vtdetectedurls = str(
                    len(vtresponse["results"]["detected_urls"]))
            else:
                vtdetectedurls = str(0)
            if "results" not in vtresponse:
                vtdetectedcommunicatingsamples = "INVALID API KEY"
            elif "detected_communicating_samples" in vtresponse["results"]:
                vtdetectedcommunicatingsamples = str(
                    len(vtresponse["results"]["detected_"
                                              "communicating_"
                                              "samples"]))
            else:
                vtdetectedcommunicatingsamples = str(0)
            vturl = "https://www.virustotal.com/en/ip-address/{}/information/"\
                    .format(host)
        else:
            vtresponse = self.vt.get_domain_report(host)
            while "response_code" not in vtresponse or \
                    (vtresponse["response_code"] != 200 and
                     vtresponse["response_code"] != 403):
                time.sleep(60)  # Sleep for the API throttling
                vtresponse = self.vt.get_domain_report(host)
            if "results" not in vtresponse:
                vtdetectedurls = "INVALID API KEY"
            elif "detected_urls" in vtresponse["results"]:
                vtdetectedurls = str(
                    len(vtresponse["results"]["detected_urls"]))
            else:
                vtdetectedurls = str(0)
            if "results" not in vtresponse:
                vtdetectedcommunicatingsamples = "INVALID API KEY"
            elif "detected_communicating_samples" in vtresponse["results"]:
                vtdetectedcommunicatingsamples = str(
                    len(vtresponse["results"]["detected_"
                                              "communicating_"
                                              "samples"]))
            else:
                vtdetectedcommunicatingsamples = str(0)
            if "results" not in vtresponse:
                vtdetecteddownloadedsamples = "INVALID API KEY"
            elif "detected_downloaded_samples" in vtresponse["results"]:
                vtdetecteddownloadedsamples = str(
                    len(vtresponse["results"]["detected_"
                                              "downloaded_"
                                              "samples"]))
            else:
                vtdetecteddownloadedsamples = str(0)
            vturl = "https://www.virustotal.com/en/domain/{}/information/"\
                    .format(host)

        inputrow.append(vtdetectedurls)
        inputrow.append(vtdetectedcommunicatingsamples)
        inputrow.append(vtdetecteddownloadedsamples)
        inputrow.append(vturl)