Examples of network hunting using Livehunt

Examples of network hunting using Livehunt

Uncover new artifacts and infrastructure related to a known campaign

New Files downloaded from URLs with a pattern

Matches: FILE

import "vt"

rule NewFileDownloadedFromUrlMatchingExpression {
meta:
  description = "New Files downloaded from URLs with a pattern"
  author = "virustotal"
  target_entity = "file"
condition:
  vt.metadata.new_file and
  vt.metadata.itw.url.raw matches /example[.]com\/foo\/.*/
}

⚠️ Finetuned alternatives to regexps matching:

  • vt.metadata.itw.url.raw icontains "example.com/foo"
  • vt.metadata.itw.domain.root == "example.com" and vt.metadata.itw.url.path istartswith "/foo" (for every domain or subdomain of example.com including itself)
  • vt.metadata.itw.domain.raw iendswith ".example.com" and vt.metadata.itw.url.path istartswith "/foo" (for only example.com subdomains)

New PE files downloaded from URLs with a pattern

Matches: FILE

import "vt"

rule NewExesDownloadedFromSomeURLPattern {
meta:
  description = "New PE files downloaded from URLs with a pattern"
  author = "virustotal"
  target_entity = "file"
condition:
  vt.metadata.new_file and
  vt.metadata.itw.url.raw matches /example.com\/foo\/.*/ and
  vt.metadata.file_type == vt.FileType.PE_EXE
}

URLs matching a pattern that downloads a PE file for first time

Matches: URL

import "vt"

rule UrlsMatchingExpressionDownloadingNewFiles {
meta:
  description = "URLs matching a pattern that downloads a PE file for first time"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.downloaded_file.new_for_url and
  vt.net.url.raw matches /example[.]com\/foo\/.*/ and
  vt.net.url.downloaded_file.file_type == vt.FileType.PE_EXE
}

⚠️ Notice that vt.net.url.downloaded_file.new_for_url matches once the file
haven't been previously downloaded from that particular URL, it may already be
known in VT.

New URLs serving certain hash

Matches: URL

import "vt"

rule NewURLsServingThisFile {
meta:
  description = "New URLs serving certain hash"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.new_url and
  vt.net.url.downloaded_file.sha256 == "<sha256>"
}

New URL with a pattern serving a new file

Matches: URL

import "vt"

rule NewURLsServingANewFile {
meta:
  description = "New URL with a pattern serving a new file"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.new_url and
  vt.net.url.downloaded_file.new_for_vt and  // For VT
  vt.net.url.raw icontains "example.com/foo/"
}

URLs matching a string in its content and served for first time

Matches: URL

⚠️ The content will be new for that particular URL, alternatively you can use vt.net.url.downloaded_file.new_for_vt to check if it's first time seen in the whole VT collection.

import "vt"

rule URLsMatchingContent {
meta:
  description = "URLs matching a string in its content and served for first time"
  author = "virustotal"
  target_entity = "url"
strings:
  $cmdlet_str = "CmdletBinding" nocase
condition:
  vt.net.url.downloaded_file.new_for_url and
  $cmdlet_str
}

New URLs matching certain strings in its content

Matches: URL

import "vt"

rule NewURLsServingFileContentMatchingConditions {
meta:
  description = "New URLs matching certain strings in its content"
  author = "virustotal"
  target_entity = "url"
strings:
  $foo = "foo"
  $bar = "bar"
condition:
  vt.net.url.new_url and
  all of them
}

New Domains having communicating files detected

Matches: DOMAIN

⚠️ vt.net.domain.communicating_file.* refers to a File behavioural analysis that reported this Domain (or URL domain) as part of its indicators.

import "vt"

rule NewCommunicatingDomainForDetectedFiles {
meta:
  description = "New Domains having communicating files detected"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.new_domain and
  // communicating_file.* refers to a File behavioural analysis that reported this Domain (or URL domain).
  vt.net.domain.communicating_file.analysis_stats.malicious > 2
}

New Domains having a specific communicating file

Matches: DOMAIN

⚠️ vt.net.domain.communicating_file.* refers to a File behavioural analysis that reported this Domain (or URL domain) as part of its indicators.

import "vt"

rule NewCommunicatingDomainForSpecificFile {
meta:
  description = "New Domains having a specific communicating file"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.new_domain and
  // communicating_file.* refers to a File behavioural analysis that reported this Domain (or URL domain).
  vt.net.domain.communicating_file.sha256 == "<sha256>"
}

New Domains reported for a subsequent File behaviour analyses

Matches: DOMAIN

import "vt"

rule EveryCommunicatingDomainForSpecificFile {
meta:
  description = "New Domains reported for a subsequent File behaviour analyses"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.communicating_file.sha256 == "<sha256>"
}

⚠️ Fixing communicating_file to a certain hash means that once VT receives a new behavioural report over that file you will be notified.

New Domains observed in behaviour analyses of files with detections

Matches: DOMAIN

import "vt"

rule CommunicatingDomainForDetectedFiles {
meta:
  description = "New Domains observed in behaviour analyses of files with detections"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.new_domain and
  vt.net.domain.communicating_file.analysis_stats.malicious >= 2
}

Domains observed from detected samples behaviours

Matches: DOMAIN

import "vt"

rule DomainsContactedByADetectedFile {
meta:
  description = "Domains observed from detected samples behaviours"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.communicating_file.analysis_stats.malicious >= 2
}

IP addresses observed from detected samples behaviours

Matches: IP

import "vt"

rule IpsContactedByADetectedFile {
meta:
  description = "IP addresses observed from detected samples behaviours"
  author = "virustotal"
  target_entity = "ip_address"
condition:
  vt.net.ip.communicating_file.analysis_stats.malicious >= 2
}

New URLs under a specific domain

Matches: URL

import "vt"

rule newURLsUnderDomain {
meta:
  description = "New URLs under a specific domain"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.new_url
  and vt.net.domain.raw == "example.com"
}

New URLs in subdomains

Matches: URL

import "vt"

rule newURLsInSubDomains {
meta:
  description = "New URLs in subdomains"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.new_url
  and vt.net.domain.raw endswith ".example.com"
}

Root domain appearing in a sample behavior for first time

Matches: DOMAIN

import "vt"

rule newDomainRelationshipForIOC {
meta:
  description = "Root domain appearing in a sample behavior for first time"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.root == "example.com" and
  vt.net.domain.communicating_file.new_for_domain
}

IP addresses range appearing in a sample behavior for first time

Matches: IP

import "vt"

rule newIPRelationshipForIOC {
meta:
  description = "IP addresses range appearing in a sample behavior for first time"
  author = "virustotal"
  target_entity = "ip_address"
condition:
  vt.net.ip.communicating_file.new_for_ip and
  vt.net.ip.ip_as_int >= 3941835776 and vt.net.ip.ip_as_int < 3941836800 // 234.243.166.33/22
}

Unearth malicious infrastructure being used by certain malware toolkits

URLs with pattern and a set of query params

Matches: URL
⚠️ URL matching can be fine-tuned, for example: vt.net.domain.root == "example.com" and vt.net.url.path istartswith "/foo"

import "vt"

rule paramsOverURL {
meta:
  description = "URLs with pattern and a set of query params"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.raw matches /example[.]com/ and
  for any key, value in vt.net.url.params: (
    key == "foo" and
    value icontains "bar"
  )
}

URL subdomains matching certain GET params

Matches: URL

import "vt"

rule paramsOverSubDomain {
meta:
  description = "URL subdomains matching certain GET params"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.domain.root == "example.com" and
  // vt.net.domain.raw != "example.com" and  // enable to skip naked domain matches
  for any key, value in vt.net.url.params: (
    key == "foo" and
    value icontains"bar"
  )
}

New Files serverd from a domain matching certain JARM

Matches: FILE

import "vt"

rule NewDownloadedFilesJarmMatching {
meta:
  description = "New Files serverd from a domain matching certain JARM"
  author = "virustotal"
  target_entity = "file"
condition:
  vt.metadata.new_file and
  vt.metadata.itw.domain.jarm == "00112233445566778899AABBCCDDEEFF"
}

New domains with a specific JARM

Matches: DOMAIN

import "vt"

rule NewDomainJarmMatching {
meta:
  description = "New domains with a specific JARM"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.new_domain and
  vt.net.domain.jarm == "00112233445566778899AABBCCDDEEFF"
}

IP addresses with SSL/TLS serving with a specific JARM

Matches: IP

import "vt"

rule IPJarmMatching {
meta:
  description = "IP addresses with SSL/TLS serving with a specific JARM"
  author = "virustotal"
  target_entity = "ip_address"
condition:
  vt.net.ip.jarm == "00112233445566778899AABBCCDDEEFF"
}

New URLs with certain SSL certificate subject

Matches: URL

import "vt"

rule sslCertificateAttributeMatching {
meta:
  description = "New URLs with certain SSL certificate subject"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.new_url and
  vt.net.domain.https_certificate.subject.common_name == "*.example.com"
}

URLs with a certain set and amount of HTTP headers

Matches: URL

import "vt"

rule missingAndContainedHTTPHeaders {
meta:
  description = "URLs with a certain set and amount of HTTP headers"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.number_of_response_headers == 4 and
  for all name, value in vt.net.url.response_headers : (
    name != "Content-Encoding"
  ) and
  for any name, value in vt.net.url.response_headers : (
    name == "Foo" and value == "Bar"
  )
}

URLs with a certain cookie name

Matches: URL

import "vt"

rule cookieWithName {
meta:
  description = "URLs with a certain cookie name"
  author = "virustotal"
  target_entity = "url"
condition:
  for any name, value in vt.net.url.cookies : (
    name == "SuspiciousCookie"
  )
}

New URLs serving content strings and URLscanner detections

Matches: URL

import "vt"

rule MatchHTTPResponseContentAndAnalysis {
meta:
  description = "New URLs serving content strings and URLscanner detections"
  author = "virustotal"
  target_entity = "url"
strings:
  $html = "<HTML "
  $bar = "bar"
condition:
  vt.net.url.new_url
  and vt.net.url.analysis_stats.malicious > 1
  and $html at 0 and $bar
}

New URLs with URLscanner detections matching potentially malicious HTML/JS strings

Matches: URL

import "vt"

rule MatchEmbeddedJavascriptContent {
meta:
  description = "New URLs with URLscanner detections matching potentially malicious HTML/JS strings"
  author = "virustotal"
  target_entity = "url"
strings:
  $html = "<HTML " nocase
  $js_script = "script" nocase
  $js_unescape = "unescape" nocase
  $js_parseint = "parseint" nocase
  $js_fromcharcode = "fromcharcode" nocase
condition:
  vt.net.url.new_url and
  vt.net.url.analysis_stats.malicious > 1 and
  $html at 0 and $js_script and
  ($js_unescape or $js_parseint or $js_fromcharcode)
}

URLs serving strings seen in VT for first time

Matches: URL

import "vt"

rule MatchHTTPResponseContentFirstSeen {
meta:
  description = "URLs serving strings seen in VT for first time"
  author = "virustotal"
  target_entity = "url"
strings:
  $securestring_str = "ConvertFrom-SecureString" nocase
condition:
  vt.net.url.downloaded_file.new_for_vt and
  $securestring_str
}

URLs serving potential PowerShell content

Matches: URL

⚠️ Useful for filetypes that are not automatically submmited to VT (list).

import "vt"

rule MatchPowerShellContent {
meta:
  description = "URLs serving potential PowerShell content"
  author = "virustotal"
  target_entity = "url"
strings:
  $mz_header = { 4d 5a 90 }
  $cmdlet_str = "CmdletBinding" nocase
  $securestring_str = "ConvertFrom-SecureString" nocase

condition:
  not ($mz_header at 0) and
  ($cmdlet_str or $securestring_str)
}

URLs serving new potential PowerShell content

Matches: URL

⚠️ Useful for filetypes that are not automatically submmited to VT (list).

import "vt"

rule MatchNewServedPowerShellContent {
meta:
  description = "URLs serving new potential PowerShell content"
  author = "virustotal"
  target_entity = "url"
strings:
  $mz_header = { 4d 5a 90 }
  $cmdlet_str = "CmdletBinding" nocase
  $securestring_str = "ConvertFrom-SecureString" nocase

condition:
  vt.net.url.downloaded_file.new_for_url and
  not ($mz_header at 0) and
  ($cmdlet_str or $securestring_str)
}

Domains with certain DNS records

Matches: DOMAIN

import "vt"

rule dnsRecord {
meta:
  description = "Domains with certain DNS records"
  author = "virustotal"
  target_entity = "domain"
condition:
  for any record in vt.net.domain.dns_records : (
    record.type == "TXT" and
    record.value istartswith "v=spf1 include:"
  )
}

Track specific threat actors and their newly created infrastructure

URLs with a certain set of HTML meta tags

Matches: URL

import "vt"

rule htmlMetaTags {
meta:
  description = "URLs with a certain set of HTML meta tags"
  author = "virustotal"
  target_entity = "url"
condition:
  for any entry in vt.net.url.html_meta_tags : (
    entry.key == "generator" and
    for any value in entry.values : (
      value startswith "Foo"
    ) and
    for any value in entry.values : (
      value startswith "Bar"
    )
  )
}

URLs with a combination of tracker and tracker id

Matches: URL

import "vt"

rule newURLsUsingSpecificTracker {
meta:
  description = "URLs with a combination of tracker and tracker id"
  author = "virustotal"
  target_entity = "url"
condition:
  for any tracker in vt.net.url.trackers : (
    tracker.name == "Google Analytics" and
    tracker.id == "Foo"
  )
}

Domains matching Whois key/values

Matches: DOMAIN

⚠️ This will notify new and updated Whois records.

import "vt"

rule WhoisProperties {
meta:
  description = "Domains matching Whois key/values"
  author = "virustotal"
  target_entity = "domain"
condition:
  for any key, value in vt.net.domain.whois : (
    key == "Foo" and
    value == "Bar"
  )
}

Domains serving HTTPS with certain a certificate thumbprint

Matches: DOMAIN

⚠️ To match other HTTPS certificate fields check cert struct.

import "vt"

rule httpsCertificate {
  meta:
  description = "Domains serving HTTPS with certain a certificate thumbprint"
  author = "virustotal"
  target_entity = "domain"
vt.net.domain.https_certificate.thumbprint == "AABBCCDD"
}

Identify supply chain risk, mainly phishing, against my identity provider or specific companies

URLs containing certain HTML title and serving a favicon dhash

Matches: URL

⚠️ To obtain a dhash check: obtaining a domain favicon dhash.

import "vt"

rule URLsWithMyFavIcon {
meta:
  description = "URLs containing certain HTML title and serving a favicon dhash"
  author = "virustotal"
  target_entity = "url"
condition:
  (vt.net.url.html_title contains "Example Bank" or
   vt.net.url.favicon.dhash == "5a923260c3c8708f") and

  not vt.net.url.raw istartswith "https://www.example-bank.com/"
}

URLs matching string in its URL excluding the canonical URL

Matches: URL

import "vt"

rule URLHostingPhishing {
meta:
  description = "URLs matching string in its URL excluding the canonical URL"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.raw contains "example-bank" and
  vt.net.domain.root != "example-bank.com"
}

⚠️ Notice how vt.net.domain.root condition excludes the root domain and all its possible subdomains.


Attack surface/infrastructure management

Files with positives downloaded from a certain IP range

Matches: FILE

⚠️ To convert an IP range to Integer match you can check: generating IP integer range.

import "vt"

rule maliciousFilesFromMyIPRange {
meta:
  description = "Files with positives downloaded from a certain IP range"
  author = "virustotal"
  target_entity = "file"
condition:
  vt.metadata.analysis_stats.malicious > 1 and
  vt.metadata.itw.ip.ip_as_int >= 3941835776 and vt.metadata.itw.ip.ip_as_int < 3941836800 // 234.243.166.33/22
}

Files with positives downloaded from a certain URLs

Matches: FILE

import "vt"

rule maliciousFilesFromMyURLs {
meta:
  description = "Files with positives downloaded from a certain URLs"
  author = "virustotal"
  target_entity = "file"
condition:
  vt.metadata.analysis_stats.malicious > 1 and
  vt.metadata.itw.url.raw matches /mydomain[.]com/
}

IP addresses marked as malicious in an IP range

Matches: IP

⚠️ To convert an IP range to Integer match you can check: generating IP integer range.

import "vt"

rule IPMarkedAsMaliciousFromMyIPRange {
meta:
  description = "IP addresses marked as malicious in an IP range"
  author = "virustotal"
  target_entity = "ip_address"
condition:
  vt.net.ip.analysis_stats.malicious > 1 and
  vt.net.ip.ip_as_int >= 3941835776 and vt.net.ip.ip_as_int < 3941836800 // 234.243.166.33/22
}

IP addresses serving malicious files

Matches: IP

Useful to monitor your own infrastructure.

import "vt"

rule IPServesMaliciousFile {
meta:
  description = "IP addresses serving malicious files"
  author = "virustotal"
  target_entity = "ip_address"
condition:
  vt.net.ip.raw matches /ˆ11\.22\.33\./ and
  vt.net.ip.downloaded_file.analysis_stats.malicious > 2
}

Domain serving malicious files

Matches: DOMAIN

Useful to monitor your own infrastructure.

import "vt"

rule DomainServesMaliciousFile {
meta:
  description = "Domain serving malicious files"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.raw iendswith "drive.google.com" and
  vt.net.domain.downloaded_file.analysis_stats.malicious > 2
}

False positives related to your internet-exposed assets

Files with positives downloaded from a certain Domain

Matches: DOMAIN

import "vt"

rule falsePositivesFromMyDomain {
meta:
  description = "Files with positives downloaded from a certain Domain"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.domain.raw == "example.com" and
  vt.net.domain.analysis_stats.malicious > 0
}