Exemple #1
0
def main() -> None:
    """Main function"""
    # Look for default ini file in "/etc/actworkers.ini" and
    # ~/config/actworkers/actworkers.ini (or replace .config with
    # $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    # setup logging
    act.api.utils.setup_logging(args.loglevel, prefix='act-alienvault-otx')

    # check necessary configuration items for errors
    for item in [
            'config_path', 'otx_baseurl', 'otx_apikey', 'otx_path_lastretrived'
    ]:
        if item not in args:
            raise ConfigurationError(
                'Missing configuration item {}'.format(item))

    # initialise act api
    actapi = worker.init_act(args)

    # initialise otx api
    otxapi = AlienvaultOTXAPI(args)

    # create facts for indicators in each event
    for event in otxapi.get_subscribed():
        handle_facts(actapi, event)
Exemple #2
0
def main_log_error() -> None:
    "Main function. Log all exceptions to error"
    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)

    args = cli.handle_args(parseargs())
    actapi = worker.init_act(args)

    if not (args.act_baseurl and args.user_id):
        sys.stderr.write("Must specify --baseurl and --user-id\n")
        sys.exit(1)

    if not os.path.isfile(args.search_jobs):
        sys.stderr.write("File not found: {}\n".format(args.search_jobs))
        sys.exit(2)

    if not args.search_jobs:
        sys.stderr.write("Must specify config file with search jobs\n")
        sys.exit(2)

    try:
        for name, options in parse_search_jobs(args.search_jobs).items():
            process(actapi, args.output_path, name, options, args.workers)

    except Exception:
        error("Unhandled exception", exc_info=True)
        raise
Exemple #3
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())

    actapi = worker.init_act(args)

    if not args.apikey:
        cli.fatal("You must specify --apikey on command line or in config file")

    in_data = sys.stdin.read().strip()

    proxies = (
        {"http": args.proxy_string, "https": args.proxy_string}
        if args.proxy_string
        else None
    )

    vtapi = VirusTotalApi(args.apikey, proxies=proxies)

    if args.hexdigest:
        handle_hexdigest(actapi, vtapi, in_data, output_format=args.output_format)

    elif args.ip:
        handle_ip(actapi, vtapi, in_data, output_format=args.output_format)

    elif args.domain:
        handle_domain(actapi, vtapi, in_data, output_format=args.output_format)

    else:  # Type not specified, autodetect
        handle_ioc(actapi, vtapi, in_data, output_format=args.output_format)
Exemple #4
0
def main() -> None:
    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())
    actapi = worker.init_act(args)

    process(actapi, args.pdns_baseurl, args.apikey, args.timeout, args.proxy_string, args.output_format)
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    actapi = worker.init_act(args)

    # if not args.apikey:
    #    worker.fatal("You must specify --apikey on command line or in config file")

    proxies = {
        'http': args.proxy_string,
        'https': args.proxy_string
    } if args.proxy_string else None

    params = {
        'actapi': actapi,
        'user_agent': args.user_agent,
        'proxies': proxies,
        'verify_ssl': args.no_check_certificate,
        'output_format': args.output_format
    }

    if args.feed:
        handle_feed(**params)
    else:
        params['apikey'] = args.apikey
        for line in sys.stdin:
            params['hashdigest'] = line.strip()
            handle_hash(**params)
Exemple #6
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())

    actapi = worker.init_act(args)

    # if not args.apikey:
    #    cli.fatal("You must specify --apikey on command line or in config file")

    proxies = (
        {"http": args.proxy_string, "https": args.proxy_string}
        if args.proxy_string
        else None
    )

    params = {
        "actapi": actapi,
        "user_agent": args.user_agent,
        "proxies": proxies,
        "verify_ssl": args.no_check_certificate,
        "output_format": args.output_format,
    }

    if args.feed:
        handle_feed(**params)
    else:
        params["apikey"] = args.apikey
        for line in sys.stdin:
            params["hashdigest"] = line.strip()
            handle_hash(**params)
Exemple #7
0
def main() -> None:
    """program entry point"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    manifest_dir = args.manifest_dir

    actapi = worker.init_act(args)

    verify_manifest_dir(manifest_dir)
    misp_feeds_file = os.path.join(manifest_dir, "misp_feeds.txt")

    with open(misp_feeds_file) as f:
        for line in f:
            feed_data = handle_feed(manifest_dir, line.strip(),
                                    args.proxy_string, args.cert_file)
            for event in feed_data:
                n = 0
                e = 0

                act.api.helpers.handle_fact(actapi.fact("name",
                                                        event.info).source(
                                                            "report",
                                                            str(event.uuid)),
                                            output_format=args.output_format)

                n += 1

                try:
                    act.api.helpers.handle_fact(
                        actapi.fact("externalLink").source(
                            "uri",
                            "{0}/{1}.json".format(line.strip(),
                                                  event.uuid)).destination(
                                                      "report",
                                                      str(event.uuid)),
                        output_format=args.output_format)

                    n += 1
                except act.api.base.ResponseError as err:
                    e += 1
                    error("Error adding fact to platform", exc_info=True)

                for attribute in event.attributes:
                    if not attribute.act_type:
                        continue
                    try:
                        act.api.helpers.handle_fact(
                            actapi.fact("mentions").source(
                                "report", str(event.uuid)).destination(
                                    attribute.act_type, attribute.value),
                            output_format=args.output_format)
                        n += 1
                    except act.api.base.ResponseError as err:
                        e += 1
                        error("Error adding fact to platform", exc_info=True)
                info("{0} facts. {1} errors.".format(n, e))
Exemple #8
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())
    actapi = worker.init_act(args)

    if not args.country_codes:
        cli.fatal("You must specify --country-codes on command line or in config file")

    if not args.veris_prefix:
        cli.fatal("You must specify --veris-prefix")

    if not (args.veris_url or args.veris_file or args.stdin):
        cli.fatal("You must specify --veris-url, --veris-file or --stdin")

    args.veris_prefix = args.veris_prefix.upper()

    if not os.path.isfile(args.country_codes):
        cli.fatal(
            "Country/region file not found at specified location: {}".format(
                args.country_codes
            ),
            2,
        )

    args.threat_actor_variety = [
        variety.strip() for variety in args.threat_actor_variety.split(",")
    ]

    # Configuration object that will be passed around to functions
    config = {
        # act API
        "actapi": actapi,
        # Map of CC -> Country Name
        "cn_map": get_cn_map(args.country_codes),
        # Map of CC -> Country Name
        "campaign_map": get_campaigns(args.veris_prefix, args.veris_campaign)
        if args.veris_campaign
        else {},
        # Cache of url > sha256
        "db_cache": urlcache.URLCache(
            requests_common_kwargs={
                "proxies": {"http": args.proxy_string, "https": args.proxy_string},
                "timeout": args.http_timeout,
            }
        ),
        "proxies": {"http": args.proxy_string, "https": args.proxy_string}
        if args.proxy_string
        else None,
    }

    # Add all arguments from args to config
    config.update(vars(args))

    process(config)
Exemple #9
0
def main() -> None:
    """Main function"""
    # Look for default ini file in "/etc/actworkers.ini" and
    # ~/config/actworkers/actworkers.ini (or replace .config with
    # $XDG_CONFIG_DIR if set)
    args = worker.handle_args(worker.parseargs(WORKER_NAME))
    actapi = worker.init_act(args)

    process(actapi, args.output_format)
Exemple #10
0
def main_log_error() -> None:
    "Call main() and log all exceptions as errors"
    try:
        # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
        # (or replace .config with $XDG_CONFIG_DIR if set)
        args = worker.handle_args(worker.parseargs("Generic uploader"))
        actapi = worker.init_act(args)

        main(actapi)
    except Exception:
        error("Unhandled exception: {}".format(traceback.format_exc()))
        raise
Exemple #11
0
def main() -> None:
    "main function"

    # Look for default ini file in "/etc/actworkers.ini" and
    # ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)

    args = cli.handle_args(parseargs())

    if not args.argus_apikey:
        cli.fatal("You must specify --argus-apikey on command line or in config file")

    actapi = worker.init_act(args)
    process(actapi, args)
Exemple #12
0
def main() -> None:
    """Main function"""
    args = cli.handle_args(parseargs())
    actapi = worker.init_act(args)

    if not (args.act_baseurl and args.user_id):
        error("Worker must be configured with --act-baseurl and --userid")
        sys.exit(1)

    tools = search_tools(actapi, args.exclude_tools)
    aliases = get_aliases(actapi, list(tools.keys()))

    for tool1, tool2 in process(tools, aliases, args.threshold):
        handle_alias(actapi, tool1, tool2, args.submit, args.output_format)
Exemple #13
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())

    actapi = worker.init_act(args)

    if not args.country_codes:
        cli.fatal("You must specify --country-codes on command line or in config file")

    if not os.path.isfile(args.country_codes):
        cli.fatal(
            "Country/region file not found at specified location: {}".format(
                args.country_codes
            ),
            2,
        )

    # Get map of CC -> Country Name
    cn_map = get_cn_map(args.country_codes)

    db_cache = get_db_cache(CACHE_DIR)

    # Read IPs from stdin
    if args.stdin:
        in_data = sys.stdin.read().split("\n")
        handle_ip(
            actapi, cn_map, in_data, db_cache, args.proxy_string, args.output_format
        )

    # Bulk lookup
    elif args.bulk:
        all_ips = open(args.bulk, "r").readlines()
        batch_size = 50
        i = 0
        while i < len(all_ips):
            handle_ip(
                actapi,
                cn_map,
                (all_ips[i : i + batch_size]),
                db_cache,
                args.proxy_string,
                args.output_format,
            )
            i += batch_size
            time.sleep(1)

    db_cache.close()
Exemple #14
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    actapi = worker.init_act(args)

    # Add IOCs from reports to the ACT platform
    add_to_act(
        actapi,
        get_scio_report(),
        args.output_format,
    )
Exemple #15
0
def main_log_error() -> None:
    "Main function. Log all exceptions to error"
    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    actapi = worker.init_act(args)

    try:
        process(
            actapi,
            worker.fetch_json(args.country_region_url, args.proxy_string,
                              args.http_timeout), args.output_format)
    except Exception:
        error("Unhandled exception: {}".format(traceback.format_exc()))
        raise
Exemple #16
0
def main() -> None:
    """Main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())

    actapi = worker.init_act(args)

    proxies = ({
        "http": args.proxy_string,
        "https": args.proxy_string
    } if args.proxy_string else None)

    attack = Attck(proxies=proxies)

    types = [args.type] if args.type else MITRE_TYPES

    for mitre_type in types:
        if mitre_type not in MITRE_TYPES:
            error("Unknown mitre type: {}. Valid types: {}".format(
                mitre_type, ",".join(MITRE_TYPES)))
            sys.exit(2)

        cache = notify_cache(args.notifycache)

        model = getattr(attack, mitre_type)

        techniques_notify = add_techniques(actapi, model, args.output_format)
        groups_notify = add_groups(actapi, model, args.output_format)
        software_notify = add_software(actapi, model, args.output_format)

        # filter revoked objects from those allready notified
        notify = [
            notify
            for notify in techniques_notify + groups_notify + software_notify
            if notify.id not in cache
        ]

        if notify:
            notified = send_notification(notify, args.smtphost, args.sender,
                                         args.recipient, mitre_type)

            for object_id in notified:
                # Add object to cache, so we will not be notified on the same object on the next run
                add_to_cache(args.notifycache, object_id)
Exemple #17
0
def test_args_origin_id(monkeypatch: _pytest.monkeypatch.MonkeyPatch) -> None:
    """test argument origin-id"""

    origin_id = "00000000-0000-0000-0000-000000000001"

    monkeypatch.setattr(sys, "argv",
                        ["./test-worker.py", "--origin-id", origin_id])

    args = cli.handle_args(worker.parseargs("Test worker"))
    actapi = worker.init_act(args)

    assert actapi.config.origin_id == origin_id

    fact = (actapi.fact("mentions").source("report", "xyz").destination(
        "fqdn", "test.com"))

    assert fact.origin.id == origin_id
Exemple #18
0
def main() -> None:
    """ Main function """

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    actapi = worker.init_act(args)

    if args.type:
        types = [args.type]
    else:
        types = list(MITRE_URLS.keys())

    for mitre_type in types:
        url = MITRE_URLS.get(mitre_type.lower())

        if not url:
            error("Unknown mitre type: {}. Valid types: {}".format(
                mitre_type, ",".join(MITRE_URLS.keys())))
            sys.exit(2)

        cache = notify_cache(args.notifycache)

        # Get attack dataset as Stix Memory Store
        attack = get_attack(url, args.proxy_string, args.http_timeout)

        techniques_notify = add_techniques(actapi, attack, args.output_format)
        groups_notify = add_groups(actapi, attack, args.output_format)
        software_notify = add_software(actapi, attack, args.output_format)

        # filter revoked objects from those allready notified
        notify = [
            notify
            for notify in techniques_notify + groups_notify + software_notify
            if notify.id not in cache
        ]

        if notify:
            notified = send_notification(notify, args.smtphost, args.sender,
                                         args.recipient, url)

            for object_id in notified:
                # Add object to cache, so we will not be notified on the same object on the next run
                add_to_cache(args.notifycache, object_id)
Exemple #19
0
def main_log_error() -> None:
    "Call main() and log all exceptions as errors"
    try:
        # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
        # (or replace .config with $XDG_CONFIG_DIR if set)
        args = cli.handle_args(parseargs())
        actapi = worker.init_act(args)

        uploader(
            actapi,
            sys.stdin,
            args.timing,
            args.allow_default_origin,
            args.no_exit_on_error,
        )
    except Exception:
        error("Unhandled exception: {}".format(traceback.format_exc()))
        raise
Exemple #20
0
def main() -> None:
    """Main function"""
    args = cli.handle_args(parseargs())
    actapi = worker.init_act(args)
    ta_cards = worker.fetch_json(
        args.thaicert_url, args.proxy_string, args.http_timeout
    )
    process(actapi, ta_cards["values"])

    vocab = worker.fetch_json(STIX_VOCAB, args.proxy_string, args.http_timeout)
    add_sectors(actapi, ta_cards["values"], vocab)

    countries = worker.fetch_json(COUNTRY_REGIONS, args.proxy_string, args.http_timeout)
    countries = [country["name"].lower() for country in countries]
    add_countries(actapi, ta_cards["values"], countries)

    tools = worker.fetch_json(THAICERT_TOOLS_URL, args.proxy_string, args.http_timeout)
    add_tools(actapi, ta_cards["values"], tools["values"])
Exemple #21
0
def test_args_origin_name(
        monkeypatch: _pytest.monkeypatch.MonkeyPatch) -> None:
    """ test argument origin-name """

    origin_name = "test-origin"

    monkeypatch.setattr(sys, "argv",
                        ["./test-worker.py", "--origin-name", origin_name])

    args = worker.handle_args(worker.parseargs("Test worker"))
    actapi = worker.init_act(args)

    assert actapi.config.origin_name == origin_name

    fact = actapi.fact("mentions") \
        .source("report", "xyz")\
        .destination("fqdn", "test.com")

    assert fact.origin.name == origin_name
def main() -> None:
    """Main function"""
    # Look for default ini file in "/etc/actworkers.ini" and
    # ~/config/actworkers/actworkers.ini (or replace .config with
    # $XDG_CONFIG_DIR if set)
    args = parseargs()

    try:
        shorteners = [x.strip() for x in args.url_shorteners.split(",")]
    except AttributeError:
        worker.fatal("Empty list of shorteners?")

    actapi = worker.init_act(args)

    proxies = {
        'http': args.proxy_string,
        'https': args.proxy_string
    } if args.proxy_string else None

    process(actapi, shorteners, args.user_agent, proxies, args.output_format)
Exemple #23
0
def main() -> None:
    "main function"
    try:
        # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
        # (or replace .config with $XDG_CONFIG_DIR if set)
        args = worker.handle_args(parseargs())

        if not (args.act_baseurl and args.user_id):
            fatal("--act-baseurl and --user-id must be specified")

        if not (args.list or args.add or args.delete):
            fatal("Specify either --list, --add or --delete")

        if (args.delete) and not (args.origin_id):
            fatal("Specify --origin-id to delete an origin")

        actapi = worker.init_act(args)
        origin_handler(actapi, args)
    except Exception:
        error("Unhandled exception: {}".format(traceback.format_exc()))
        raise
Exemple #24
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())

    actapi = worker.init_act(args)

    fact_type_definition_path = (pathlib.Path(
        args.fact_type_definition).expanduser().resolve())

    if not fact_type_definition_path.is_file():
        print(f"{fact_type_definition_path} is not a file.")
        sys.exit(1)

    with fact_type_definition_path.open() as typedef:
        graph = graph_from_type_def(typedef, args.avoid, args.include,
                                    args.avoid_cost)

    start_type, start_value = args.start
    end_type, end_value = args.end

    start, end = find_start_and_end_nodes(graph, start_type, end_type)

    if not start:
        print(f"{start_type} is not an object type")
        sys.exit(1)

    if not end:
        print(f"{end_type} is not an object type")
        sys.exit(1)

    res = dijkstra(graph, start, end)

    chain = fact_chain_from_path_result(actapi, res, start, end, start_value,
                                        end_value)

    for fact in chain:
        handle_fact(fact, output_format=args.output_format)
Exemple #25
0
def main() -> None:
    """program entry point"""

    # Look for default ini file in "/etc/actworkers.ini" and
    # ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())

    if not args.feed_uri:
        cli.fatal("--feed-uri not specified")

    if args.dump_dir and not args.dump_dir.is_dir():
        os.makedirs(args.dump_dir)

    proxies = ({
        "http": args.proxy_string,
        "https": args.proxy_string
    } if args.proxy_string else None)

    actapi = worker.init_act(args)

    try:
        # Get "updated" from last successful run
        last_run_filename = get_last_run_filename(args.feed_cache,
                                                  args.feed_uri)

        with pid.PidFile(force_tmpdir=True, pidname="act_feed.pid"):
            handle_feed(
                last_run_filename,
                args.feed_uri,
                actapi,
                args.dump_dir,
                proxies,
                args.cert_file,
                args.no_exit_on_error,
            )

    except pid.base.PidFileAlreadyLockedError:
        error("pid file found - feed is already running")
Exemple #26
0
def run() -> None:
    args = cli.handle_args(parseargs())
    actapi = worker.init_act(args)

    if not args.apikey or not args.secret:
        cli.fatal(
            "You must specify --apikey and --secret on command line or in config file"
        )

    proxies = ({
        "http": args.proxy_string,
        "https": args.proxy_string
    } if args.proxy_string else None)

    for in_data in sys.stdin:
        in_data = in_data.strip()

        if args.hexdigest or HASH_RE.search(in_data):
            handle_hexdigest(
                actapi,
                in_data,
                args.apikey,
                args.secret,
                proxies,
                output_format=args.output_format,
            )

        elif args.domain:
            handle_domain(
                actapi,
                in_data,
                args.apikey,
                args.secret,
                proxies,
                output_format=args.output_format,
            )
Exemple #27
0
def main() -> None:
    """ Main function """

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    actapi = worker.init_act(args)

    if not args.ta:
        sys.stderr.write(
            "You must specify Threat Actor with --ta <THREAT ACTOR>\n")
        sys.exit(1)

    # Normalize and lookup country/technique/sectors
    # Print error with suggested match if not found
    ok = True

    try:
        args.target_countries = [
            country_lookup(args, country) for country in args.target_countries
        ]
    except (VocabularyException, FileNotFoundError,
            worker.UnsupportedScheme) as e:
        sys.stderr.write(str(e))
        ok = False

    try:
        args.techniques = [technique_lookup(tech) for tech in args.techniques]
    except VocabularyException as e:
        sys.stderr.write(str(e))
        ok = False

    try:
        if args.ta_located_in:
            args.ta_located_in = country_lookup(args, args.ta_located_in)
    except VocabularyException as e:
        sys.stderr.write(str(e))
        ok = False

    try:
        args.sectors = [sector_lookup(args, sector) for sector in args.sectors]
    except VocabularyException as e:
        sys.stderr.write(str(e))
        ok = False

    if not ok:
        sys.exit(1)

    if args.target_countries:
        add_ta_target_country(actapi, args.output_format, args.ta,
                              args.target_countries)

    if args.campaign:
        add_ta_campaign(actapi, args.output_format, args.ta, args.campaign)

    if args.tools:
        add_ta_tools(actapi, args.output_format, args.ta, args.tools)

    if args.techniques:
        add_ta_techniques(actapi, args.output_format, args.ta, args.techniques)

    if args.sectors:
        add_ta_sectors(actapi, args.output_format, args.ta, args.sectors)

    if args.ta_located_in:
        add_ta_located_in(actapi, args.output_format, args.ta,
                          args.ta_located_in)
Exemple #28
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = worker.handle_args(parseargs())

    actapi = worker.init_act(args)

    if not (args.privatekey and args.publickey):
        worker.fatal("You must specify --privatekey and --publickey on command line or in config file")

    proxies = {
        'http': args.proxy_string,
        'https': args.proxy_string
    } if args.proxy_string else None

    iSightHandler = ISightAPIRequestHandler(args.root, args.privatekey, args.publickey)
    data = iSightHandler.indicators(days=args.days, proxies=proxies)

    if 'success' not in data or not data['success']:
        logging.error("Unable to download from isight API [%s]", data['message'] if 'message' in data else "NA")
        return

    timestamp = int(time.time())
    ### DEBUG -- dump json to disc for each run
    if args.debugdir:
        with open(os.path.join(args.debugdir, "error-{0}.json".format(timestamp)), "w") as f:
            json.dump(data, f)

    for i, dp in enumerate(data['message']):
        ### --- Handle mentions facts
        # Create report ID from the url (same approach as for feeds) and title to this ID.
        reportID = hashlib.sha256(dp['webLink'].encode('utf8')).hexdigest()
        handle_fact(actapi.fact('name', dp['title']).source('report', reportID))
        for obj in OBJECT_MAP:  # run through all fields that we want to mention
            if obj in dp and dp[obj]:  # if the report contains data in the field
                factType = OBJECT_MAP[obj](dp[obj])  # translate to ACT fact type
                handle_fact(actapi.fact('mentions')  # and create fact from field
                            .source('report', reportID)
                            .destination(factType, dp[obj].lower()))
        if dp['url']:
            handle_fact(actapi.fact('mentions')
                        .source('report', reportID)
                        .destination('uri', dp['url']))
            try:
                handle_uri(actapi, dp['url'])
            except act.api.base.ValidationError as err:
                logging.error("%s while storing url from mentions [%s]", err, dp['url'])
        ### --- IP -> malwareFamily
        if dp['malwareFamily'] and dp['ip']:
            chain = act.api.fact.fact_chain(
                actapi.fact('connectsTo')
                .source('content', '*')
                .destination('uri', '*'),
                actapi.fact('componentOf')
                .source('ipv4', dp['ip'])
                .destination('uri', '*'),
                actapi.fact('classifiedAs')
                .source('content', '*')
                .destination('tool', dp['malwareFamily'].lower()))
            for fact in chain:
                handle_fact(fact)
        ### --- URL -> malwareFamily
        elif dp['networkType'] == 'url' and dp['malwareFamily']:
            try:
                handle_uri(actapi, dp['url'])
            except act.api.base.ValidationError as err:
                logging.error("%s while storing url from mentions [%s]", err, dp['url'])

            chain = act.api.fact.fact_chain(
                actapi.fact('connectsTo')
                .source('content', '*')
                .destination('uri', dp['url']),
                actapi.fact('classifiedAs')
                .source('content', '*')
                .destination('tool', dp['malwareFamily'].lower()))
            for fact in chain:
                handle_fact(fact)
        ### --- FQDN -> malwareFamily
        elif dp['networkType'] == 'network' and dp['domain'] and dp['malwareFamily']:
            chain = act.api.fact.fact_chain(
                actapi.fact('connectsTo')
                .source('content', '*')
                .destination('uri', '*'),
                actapi.fact('componentOf')
                .source('fqdn', dp['domain'])
                .destination('uri', '*'),
                actapi.fact('classifiedAs')
                .source('content', '*')
                .destination('tool', dp['malwareFamily'].lower()))
            for fact in chain:
                handle_fact(fact)
        ### --- hash -> malwareFamily
        elif dp['fileType'] and dp['malwareFamily'] and (dp['sha1'] or dp['sha256'] or dp['md5']):
            for digest_type in ['md5', 'sha1', 'sha256']:
                ### In some cases the iSight api does not return a sha256 hashdigest
                ### so we need to make a chain through a placeholder content
                if not dp['sha256']:
                    if dp[digest_type]:
                        chain = act.api.fact.fact_chain(
                            actapi.fact('represents')
                            .source('hash', dp[digest_type])
                            .destination('content', '*'),
                            actapi.fact('classifiedAs')
                            .source('content', '*')
                            .destination('tool', dp['malwareFamily']))
                        for fact in chain:
                            handle_fact(fact)
                else:  ## There is a sha256, so we do _not_ need a chain
                    if dp[digest_type]:
                        handle_fact(actapi.fact('classifiedAs')
                                    .source('content', dp['sha256'])
                                    .destination('tool', dp['malwareFamily']))
                        handle_fact(actapi.fact('represents')
                                    .source('hash', dp[digest_type])
                                    .destination('content', dp['sha256']))
        ### -- Hash --> actor
        elif dp['fileType'] and dp['actor'] and (dp['sha1'] or dp['sha256'] or dp['md5']):
            for digest_type in ['md5', 'sha1', 'sha256']:
                ### In some cases the iSight api does not return a sha256 hashdigest
                ### so we need to make a chain through a placeholder content
                if not dp['sha256']:
                    if dp[digest_type]:
                        chain = act.api.fact.fact_chain(
                            actapi.fact('represents')
                            .source('hash', dp[digest_type])
                            .destination('content', '*'),
                            actapi.fact('observedIn')
                            .source('content', '*')
                            .destination('event', '*'),
                            actapi.fact('attributedTo')
                            .source('event', '*')
                            .destination('incident', '*'),
                            actapi.fact('attributedTo')
                            .source('incident', '*')
                            .destination('threatActor', dp['actor']))
                        for fact in chain:
                            handle_fact(fact)
                else:  ## There is a sha256, so we do _not_ need a chain between all the way from hexdigest
                    if dp[digest_type]:
                        handle_fact(actapi.fact('represents')
                                    .source('hash', dp[digest_type])
                                    .destination('content', dp['sha256']))
                        chain = act.api.fact.fact_chain(
                            actapi.fact('observedIn')
                            .source('content', dp['sha256'])
                            .destination('event', '*'),
                            actapi.fact('attributedTo')
                            .source('event', '*')
                            .destination('incident', '*'),
                            actapi.fact('attributedTo')
                            .source('incident', '*')
                            .destination('threatActor', dp['actor']))
                        for fact in chain:
                            handle_fact(fact)
        ### We do have a sha256 of a file (but possibly nothing else). Add the content to hexdigest facts
        elif dp['fileType'] and dp['sha256']:
            for digest in ['sha1', 'md5', 'sha256']:
                if dp[digest]:
                    handle_fact(actapi.fact('represents')
                                .source('hash', dp[digest])
                                .destination('content', dp['sha256']))
            if args.debugdir:
                fields = [k for k, v in dp.items() if v and k not in ['reportId', 'title', 'ThreatScape',
                                                                      'audience', 'intelligenceType',
                                                                      'publishDate', 'reportLink', 'webLink']]
                logging.error("[%s] Extra fields while handeling index[%s] '%s'", timestamp, i, ", ".join(fields))


        ### -- DEBUG!
        else:
            if args.debugdir:
                fields = [k for k, v in dp.items() if v and k not in ['reportId', 'title', 'ThreatScape',
                                                                      'audience', 'intelligenceType',
                                                                      'publishDate', 'reportLink', 'webLink']]
                logging.error("[%s] Unable to handle index[%s] with fields '%s'", timestamp, i, ", ".join(fields))
Exemple #29
0
def main() -> None:
    """Main function"""
    args = cli.handle_args(worker.parseargs("IP Filter"))
    worker.init_act(args)
    process()
Exemple #30
0
def main() -> None:
    """main function"""

    # Look for default ini file in "/etc/actworkers.ini" and ~/config/actworkers/actworkers.ini
    # (or replace .config with $XDG_CONFIG_DIR if set)
    args = cli.handle_args(parseargs())

    actapi = worker.init_act(args)

    if not (args.privatekey and args.publickey):
        cli.fatal(
            "You must specify --privatekey and --publickey on command line or in config file"
        )

    proxies = (
        {"http": args.proxy_string, "https": args.proxy_string}
        if args.proxy_string
        else None
    )

    iSightHandler = ISightAPIRequestHandler(args.root, args.privatekey, args.publickey)
    data = iSightHandler.indicators(days=args.days, proxies=proxies)

    if "success" not in data or not data["success"]:
        logging.error(
            "Unable to download from isight API [%s]",
            data["message"] if "message" in data else "NA",
        )
        return

    timestamp = int(time.time())
    ### DEBUG -- dump json to disc for each run
    if args.debugdir:
        with open(
            os.path.join(args.debugdir, "error-{0}.json".format(timestamp)), "w"
        ) as f:
            json.dump(data, f)

    for i, dp in enumerate(data["message"]):
        ### --- Handle mentions facts
        # Create report ID from the url (same approach as for feeds) and title to this ID.
        reportID = hashlib.sha256(dp["webLink"].encode("utf8")).hexdigest()
        handle_fact(actapi.fact("name", dp["title"]).source("report", reportID))
        for obj in OBJECT_MAP:  # run through all fields that we want to mention
            if obj in dp and dp[obj]:  # if the report contains data in the field
                factType = OBJECT_MAP[obj](dp[obj])  # translate to ACT fact type
                handle_fact(
                    actapi.fact("mentions")  # and create fact from field
                    .source("report", reportID)
                    .destination(factType, dp[obj].lower())
                )
        if dp["url"]:
            handle_fact(
                actapi.fact("mentions")
                .source("report", reportID)
                .destination("uri", dp["url"])
            )
            handle_uri(actapi, dp["url"])
        ### --- IP -> malwareFamily
        if dp["malwareFamily"] and dp["ip"]:
            handle_facts(
                act.api.fact.fact_chain(
                    actapi.fact("connectsTo")
                    .source("content", "*")
                    .destination("uri", "*"),
                    actapi.fact("componentOf")
                    .source("ipv4", dp["ip"])
                    .destination("uri", "*"),
                    actapi.fact("classifiedAs")
                    .source("content", "*")
                    .destination("tool", dp["malwareFamily"]),
                )
            )
        ### --- URL -> malwareFamily
        elif dp["networkType"] == "url" and dp["malwareFamily"]:
            handle_uri(actapi, dp["url"])
            handle_facts(
                act.api.fact.fact_chain(
                    actapi.fact("connectsTo")
                    .source("content", "*")
                    .destination("uri", dp["url"]),
                    actapi.fact("classifiedAs")
                    .source("content", "*")
                    .destination("tool", dp["malwareFamily"]),
                )
            )
        ### --- FQDN -> malwareFamily
        elif dp["networkType"] == "network" and dp["domain"] and dp["malwareFamily"]:
            handle_facts(
                act.api.fact.fact_chain(
                    actapi.fact("connectsTo")
                    .source("content", "*")
                    .destination("uri", "*"),
                    actapi.fact("componentOf")
                    .source("fqdn", dp["domain"])
                    .destination("uri", "*"),
                    actapi.fact("classifiedAs")
                    .source("content", "*")
                    .destination("tool", dp["malwareFamily"]),
                )
            )
        ### --- hash -> malwareFamily
        elif (
            dp["fileType"]
            and dp["malwareFamily"]
            and (dp["sha1"] or dp["sha256"] or dp["md5"])
        ):
            for digest_type in ["md5", "sha1", "sha256"]:
                ### In some cases the iSight api does not return a sha256 hashdigest
                ### so we need to make a chain through a placeholder content
                if not dp["sha256"]:
                    if dp[digest_type]:
                        handle_facts(
                            act.api.fact.fact_chain(
                                actapi.fact("represents")
                                .source("hash", dp[digest_type])
                                .destination("content", "*"),
                                actapi.fact("classifiedAs")
                                .source("content", "*")
                                .destination("tool", dp["malwareFamily"]),
                            )
                        )
                else:  ## There is a sha256, so we do _not_ need a chain
                    if dp[digest_type]:
                        handle_fact(
                            actapi.fact("classifiedAs")
                            .source("content", dp["sha256"])
                            .destination("tool", dp["malwareFamily"])
                        )

                        handle_fact(
                            actapi.fact("represents")
                            .source("hash", dp[digest_type])
                            .destination("content", dp["sha256"])
                        )

        ### -- Hash --> actor
        elif (
            dp["fileType"] and dp["actor"] and (dp["sha1"] or dp["sha256"] or dp["md5"])
        ):
            for digest_type in ["md5", "sha1", "sha256"]:
                ### In some cases the iSight api does not return a sha256 hashdigest
                ### so we need to make a chain through a placeholder content
                if not dp["sha256"]:
                    if dp[digest_type]:
                        handle_facts(
                            act.api.fact.fact_chain(
                                actapi.fact("represents")
                                .source("hash", dp[digest_type])
                                .destination("content", "*"),
                                actapi.fact("observedIn")
                                .source("content", "*")
                                .destination("incident", "*"),
                                actapi.fact("attributedTo")
                                .source("incident", "*")
                                .destination("threatActor", dp["actor"]),
                            )
                        )
                else:  ## There is a sha256, so we do _not_ need a chain between all the way from hexdigest
                    if dp[digest_type]:
                        handle_fact(
                            actapi.fact("represents")
                            .source("hash", dp[digest_type])
                            .destination("content", dp["sha256"])
                        )

                        handle_facts(
                            act.api.fact.fact_chain(
                                actapi.fact("observedIn")
                                .source("content", dp["sha256"])
                                .destination("incident", "*"),
                                actapi.fact("attributedTo")
                                .source("incident", "*")
                                .destination("threatActor", dp["actor"]),
                            )
                        )
        ### We do have a sha256 of a file (but possibly nothing else). Add the content to hexdigest facts
        elif dp["fileType"] and dp["sha256"]:
            for digest in ["sha1", "md5", "sha256"]:
                if dp[digest]:
                    handle_fact(
                        actapi.fact("represents")
                        .source("hash", dp[digest])
                        .destination("content", dp["sha256"])
                    )
            if args.debugdir:
                fields = [
                    k
                    for k, v in dp.items()
                    if v
                    and k
                    not in [
                        "reportId",
                        "title",
                        "ThreatScape",
                        "audience",
                        "intelligenceType",
                        "publishDate",
                        "reportLink",
                        "webLink",
                    ]
                ]
                logging.error(
                    "[%s] Extra fields while handeling index[%s] '%s'",
                    timestamp,
                    i,
                    ", ".join(fields),
                )

        ### -- DEBUG!
        else:
            if args.debugdir:
                fields = [
                    k
                    for k, v in dp.items()
                    if v
                    and k
                    not in [
                        "reportId",
                        "title",
                        "ThreatScape",
                        "audience",
                        "intelligenceType",
                        "publishDate",
                        "reportLink",
                        "webLink",
                    ]
                ]
                logging.error(
                    "[%s] Unable to handle index[%s] with fields '%s'",
                    timestamp,
                    i,
                    ", ".join(fields),
                )