Skip to content
esetPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

2 watching

Forks

Repository files navigation

Table of Contents

MISP scripts

Collection of scripts to interact with ESET (https://eti.eset.com) MISP instance.

YARA extractor

Script to extract yara rules from MISP for a given event or ESET Threat Actor.

Usage:
python extract_yara_from_misp.py -e EVENT_ID
python extract_yara_from_misp.py -g "GROUP NAME"
python extract_yara_from_misp.py -a (extracts all yara rules)

Threat Actor's Region extractor

Script to extract Threat Actor's region from MISP for a given event.

Usage: python extract_threat_actor_country.py -e EVENT_ID

Examples of common queries

Examples.ipynb is a Jupyter Notebook (https://jupyter.org) is inspired from PyMISP doc and examples (https://github.com/MISP/PyMISP/tree/main/examples) and contains the complete setup and several example queries to help users get started with the ESET MISP instance.

ETI scripts

Examples of queries for interacting with ETI TAXII feeds (https://help.eset.com/eti_portal/en-US/taxii_feeds.html).

Complete examples can be found here:

GraphQL usage examples

The following sections provide example GraphQL queries and common investigation workflows.

Search for an indicator

Use the iocSearch query with any domain, URL, IPv4 address, or file hash (MD5 / SHA-1 / SHA-256). The indicator type is detected automatically, you don't need to tell it what you're searching for.

query ($conditions: String!) { iocSearch(conditions: $conditions) { __typename ... on IoCDomain { domain state first_seen last_seen } ... on IoCFile { sha1 sha256 threat first_seen } } }
{ "conditions": "%example.com" }

Example response:

{
  "data": {
    "iocSearch": [
      {
        "__typename": "IoCDomain",
        "domain": "example.com",
        "state": "malicious",
        "first_seen": "2026-05-01T12:00:00Z",
        "last_seen": "2026-07-10T08:30:00Z"
      }
    ]
  }
}

Check indicator reputation

Use iocReputationCheck to find out if indicators are currently blocked by ESET. Pass one list type per request, sha256, sha1, url, ip, or domain with up to 100 values.

query ($domain: [String!]) { iocReputationCheck(domain: $domain) { indicator_value blocked } }
{ "domain": ["example.com", "malicious-example.net"] }

Example response:

{
  "data": {
    "iocReputationCheck": [
      { "indicator_value": "example.com", "blocked": false },
      { "indicator_value": "malicious-example.net", "blocked": true }
    ]
  }
}

Only one of sha256, sha1, url, ip, or domain can be used per request mixing types will return a validation error.

IP range on octet-aligned prefix - not CIDR

Use iocSearch to find IP indicators in all relevant types.

query SubnetSweep($conditions: String!) {
  iocSearch(conditions: $conditions) {
    __typename
    ... on IoCIp     { ip port state confidence location }
    ... on IoCDomain { domain ip state countries { country count } }
    ... on IoCUrl    { url ip state threat }
    ... on IoCCnc    { cnc host ip threat state last_alive }
  }
}
{ "conditions": "1.2.3.%" }

Subdomain on suspicious domain

query DomainInfrastructureSweep($conditions: String!) {
  iocSearch(conditions: $conditions) {
    __typename
    ... on IoCDomain { domain ip state confidence last_seen countries { country count } }
    ... on IoCUrl    { url domain state threat first_seen }
    ... on IoCCnc    { cnc host threat state last_alive }
  }
}
{ "conditions": "%.malicious-example.com" }

Parallel multi-pattern wildcard hunt via aliases

query ActorInfrastructureHunt(
  $pattern1: String!
  $pattern2: String!
  $pattern3: String!
) {
  campaignA: iocSearch(conditions: $pattern1) {
    __typename
    ... on IoCDomain { domain state }
    ... on IoCUrl { url threat }
  }
  campaignB: iocSearch(conditions: $pattern2) {
    __typename
    ... on IoCDomain { domain state }
    ... on IoCUrl { url threat }
  }
  campaignC: iocSearch(conditions: $pattern3) {
    __typename
    ... on IoCCnc { cnc threat state }
  }
}
{
  "pattern1": "%-update-service.com",
  "pattern2": "secure-%.net",
  "pattern3": "%.dyndns-example.org"
}

Variable defaults

Driven by boolean variables, so one saved query can return a lean or a fully-enriched payload on demand, no separate "light" and "heavy" query to maintain.

query FlexibleSweep(
  $conditions: String! = "198.51.100.%"
  $withCountries: Boolean = false
  $withDetections: Boolean = false
) {
  iocSearch(conditions: $conditions) {
    __typename
    ... on IoCUrl {
      url
      state
      threat
      countries @include(if: $withCountries) { country count }
      opener_detection @include(if: $withDetections)
      downloaded_detection @include(if: $withDetections)
    }
    ... on IoCDomain {
      domain
      state
      countries @include(if: $withCountries) { country count }
    }
    ... on IoCCnc {
      cnc
      threat
      state
      prot_l4 @skip(if: true)
    }
  }
}
{ "conditions": "198.51.100.%", "withCountries": true, "withDetections": false }

Search for aggregated Command and Control server details based on Botnet SHA-1

  1. Create a query to iocSearchBotnet:

    query BotnetWithCncs($sha1: String!) {
      iocSearchBotnet(sha1: $sha1) {
        threat
        targets
        cncs { url tcp last_alive }
      }
    }
    {"sha1": "4c289f978c4c464da05cee4c33101ea7f5291d7b"}
  2. Add a post-response script:

    const botnets = res.body?.data?.iocSearchBotnet || [];
    const enriched = [];
    
    for (const botnet of botnets) {
      const detailsByCnc = new Map();
    
      for (const cnc of botnet.cncs || []) {
        const cncValue = cnc.url;
        if (!cncValue) continue;
    
        bru.setVar("pivotCnc", cncValue);
    
        try {
          const lookupResponse = await bru.runRequest("cnc-lookup");
    
          if (lookupResponse.status !== 200) {
            console.error("C&C lookup failed:", cncValue, lookupResponse.statusText);
            continue;
          }
    
          const graphqlResponse = lookupResponse.data ?? lookupResponse.body;
    
          if (graphqlResponse?.errors) {
            console.error("GraphQL C&C lookup failed:", cncValue, graphqlResponse.errors);
            continue;
          }
    
          const matches = graphqlResponse?.data?.iocSearchCnc || [];
    
          for (const match of matches) {
            if (match?.cnc) {
              detailsByCnc.set(match.cnc, match);
            }
          }
        } catch (error) {
          console.error("C&C lookup request failed:", cncValue, error.message);
        }
      }
    
      enriched.push({
        ...botnet,
        cnc_details: [...detailsByCnc.values()],
      });
    }
    bru.setVar("enrichedBotnets", JSON.stringify(enriched));
    console.log(enriched);
  3. Create a second query and name it cnc-lookup:

    fragment CncCore on IoCCnc {
      cnc
      host
      ip
      port
      state
      prot_l4
      prot_l7
    }
    
    query cnclookup($cnc: String!) {
      iocSearchCnc(cnc: $cnc) {
        ...CncCore
      }
    }
    {"cnc": "{{pivotCnc}}"}
  4. The expected result appears in the console:

    [
    0:{
        "threat":"Win32/Phorpiex.AS worm"
        "targets":[]
        "cncs":[
            0:{...}
            1:{...}
        ]
        "cnc_details":[
            0:{
                "cnc":"http://178.16.54.109/1"
                "host":"178.16.54.109"
                "ip":"178.16.54.109"
                "port":80
                "state":"Blocked"
                "prot_l4":"TCP"
                "prot_l7":"http"
                }
            1:{
                "cnc":"http://178.16.54.109/2"
                "host":"178.16.54.109"
                "ip":"178.16.54.109"
                "port":80
                "state":"Blocked"
                "prot_l4":"TCP"
                "prot_l7":"http"
            }
        ]
    }
    ]

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages