ParseHTMLIndicators

This script will extract indicators from given HTML and will handle bad top-level domains to avoid false positives caused by file extensions.

python · Common Scripts

Source

import re

import demistomock as demisto  # noqa: F401
import requests
from bs4 import BeautifulSoup
from CommonServerPython import *  # noqa: F401
from tld import get_tld


def strip_html_tags(page):
    # Parse the HTML content
    soup = BeautifulSoup(page.content, "html.parser")
    # Strip irrelevant tags
    for data in soup(["style", "script", "header", "head", "footer", "aside", "a"]):
        data.decompose()
    return " ".join(soup.stripped_strings)


def validate_domains(domains, unescape_domain, TLD_exclusion):
    # TLD exclusion and validation for domain indicators
    bad_domain_TLD = set()
    for indicator in domains:
        if unescape_domain and not (get_tld(indicator, fail_silently=True)):
            bad_domain_TLD.add(indicator)
            continue

        for tld in TLD_exclusion:
            if indicator.endswith(tld):
                bad_domain_TLD.add(indicator)
    return bad_domain_TLD


def main():
    # Retrieve demisto args
    args = demisto.args()
    blog_url = args.get("url")
    headers = {"user-agent": "PANW-XSOAR"}
    page = requests.get(blog_url, verify=False, headers=headers)  # nosec
    page.raise_for_status()

    exclusion_list = set(argToList(args.get("exclude_indicators")))
    TLD_exclusion = argToList(args.get("exclude_TLD"))
    unescape_domain = argToBoolean(args.get("unescape_domain"))

    # Allow domain regex replacement between "[.]" and "."
    domain_regex = r"([a-zA-Z0-9]+?\[?\.?\]?[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\[\.\][a-zA-Z]{2,}\[?\.?\]?[a-zA-Z]{0,})"
    if unescape_domain:
        domain_regex = domain_regex.replace(r"\[\.\]", r"\.")

    # Declare indicator regexs
    url_regex = r"([https|ftp|hxxps]+:[//|\\\\]+[\w\d:#@%/;$()~_\+-=\\\[\.\]&]*)"
    ip_regex = (
        r"(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(?:\[\.\]|\.)){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])"
    )
    cve_regex = r"(CVE-\d{4}-\d{4,7})"

    page_update = strip_html_tags(page)

    # Extract indicators using regex
    md5 = set(md5Regex.findall(page_update))
    sha1 = set(sha1Regex.findall(page_update))
    sha256 = set(sha256Regex.findall(page_update))
    domain = set(re.findall(domain_regex, page_update))
    url = set(re.findall(url_regex, page_update))
    ip = set(re.findall(ip_regex, page_update))
    cve = set(re.findall(cve_regex, page_update, flags=re.IGNORECASE))

    # Validate the domain indicators
    bad_domain_TLD = validate_domains(domain, unescape_domain, TLD_exclusion)

    # Combine all indicators
    blog_indicators = (md5 | sha1 | sha256 | domain | url | ip | cve) - exclusion_list - bad_domain_TLD

    return_results(
        CommandResults(
            readable_output="\n".join(blog_indicators),
            outputs={"http.parsedBlog.indicators": list(blog_indicators), "http.parsedBlog.sourceLink": blog_url},
        )
    )


if __name__ in ("__builtin__", "builtins", "__main__"):
    main()

README

This script will extract indicators from given HTML and will handle bad top-level domains to avoid false positives caused by file extensions.

Script Data


Name Description
Script Type python3
Tags  
Cortex XSOAR Version 5.5.0

Used In


This script is used in the following playbooks and scripts.

  • Kaseya VSA 0-day - REvil Ransomware Supply Chain Attack

Inputs


Argument Name Description
url The full URL of the blog
exclude_indicators The indicators to be excluded from the results.
exclude_TLD Top-Level-Domain to be excluded from domain indicators.
unescape_domain Whether to remove brackets [] from the domain regex extraction. Can result in higher false positives for file extensions.

Outputs


Path Description Type
http.parsedBlog.indicators The extracted indicators Unknown
http.parsedBlog.sourceLink The link for the source of the indicators Unknown