Network hunting: Writing YARA rules for Livehunt

Network hunting using YARA

Hunting network assets

In addition to hunting all scanned files in VirusTotal, you can also hunt for all scanned URLs, domains and IP addresses. For this now you need to choose between File, URL, Domain or IP when you create a new Livehunt ruleset.

Hunting types

The "vt" module is now expanded with a ".net" attribute that contains all metadata extracted from the URL, its Domain and the IP address where it’s hosted. It also has complementary attributes to easily reference specific IoCs characteristics without having to deal with data's internal representation. Instead of that, self-descriptive enums are provided.

The tables below summarize all “vt” module attributes.
The first table is focused on the main attributes:

  • The first column shows the entity type that the YARA rule match against
  • The second column shows the main attribute used in the rule
  • The third column shows other secondary attributes belonging to different entity types and complementary attributes that can be combined in the same YARA rule
  • The last column provides a brief description of the main attribute
Type of IoC/entity“vt” module attributeOther fields combinationDescription
URLvt.net.urlvt.net.domain
vt.net.ip
vt.FileType (complementary attributes)
URL characteristics and other IoCs relationships
Domainvt.net.domainvt.net.ip
vt.FileType (complementary attributes)
Domain characteristics and other IoCs relationships
IP Addressvt.net.ipvt.FileType (complementary attributes)IP addresses characteristics and other IoCs relationships
Files *staticvt.metadatavt.FileType and vt.behaviour + rest of complementary attributesFile metadata
Files *dynamicvt.behaviourvt.metadata + vt.FileType and the rest of complementary attributesFile characteristics extracted via sandbox execution and other IoCs relationships

The second table shows the complementary attributes, basically enums that can be used in combination with the previous attributes to deploy a functional rule.

Type of IoC/entity“vt” module attributeDescription
Files *staticvt.FileTypeEnum of available file types
Files *dynamicvt.BehaviourTraitEnum of behavior traits that can be found on a file behavior report after sandbox execution
Files *dynamicvt.BehaviourVerdictEnum of sandbox verdicts based on file behavior after sandbox execution
Files *dynamicvt.HttpEnum of HTTP methods
Files *dynamicvt.NetEnum of network protocols

⚠️ Please note that vt.net and vt.Net are different attributes. The first one represents network entities while the second one provides an abstraction layer of the internal representation of the network protocols.

Let’s walk through some examples:

Get all detected URLs under a specific domain first select "Create a new rule" and choose to match URL, these will produce URL notifications.

import "vt"

rule detectedPythonPackages {
meta:
  description = "URLs with detections matching files.pythonhosted.org domain"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.analysis_stats.malicious > 1 and
  vt.net.domain.raw == "files.pythonhosted.org"
}

Notice how is possible to combine vt.net.url and vt.net.domain, it works in a top down fashion:

  • URL matching rules will allow vt.net.url, vt.net.domain and vt.net.ip fields
  • Domain matching rules will allow vt.net.domain and vt.net.ip fields
  • IP matching rules will allow only vt.net.ip fields

In a similar way we can create another URL rule to monitor new URLs from the LilithBot campaign:

import "vt"

rule LilithBot {
meta:
  description = "URLs matching LilithBot C2C"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.raw matches /\/gate\/.{60}\/registerBot/ or
  vt.net.url.raw matches /\/gate\/.{60}\/getFile\?name=admin_settings_plugin\.json/ or
  vt.net.url.raw matches /\/gate\/.{60}\/uploadFile\?name/
}

The vt.net module contains the following metadata:

URL metadata

FieldTypeDescriptionExample
vt.net.url.rawstringThe URL in canonical form.vt.net.url.raw matches /.*\.php/
vt.net.url.pathstringPath part of the current URL.vt.net.url.path icontains "private/reviewsGallery/get-image-gallery-assets"
vt.net.url.querystringRaw URL query stringvt.net.url.query contains "dir="
vt.net.url.hostnamestringHostname part of the current URL.vt.net.url.hostname iendswith "google.com"
vt.net.url.new_urlboolWether the URL is observed for the first time or not.
vt.net.url.first_submission_dateintUNIX UTC timestamp for the URL's first submission date.vt.net.url.first_submission_date < 1672531200
vt.net.url.paramsdictParsed URL GET paramsfor any k, v in vt.net.url.params: ( k == "user" )
vt.net.url.portintThe port in which the URL is accessedvt.net.url.port > 8080 and vt.net.url.port < 8090
vt.net.url.trackersarray of structAll trackers found in the URLfor any tracker in vt.net.url.trackers: (
  tracker.name == "Google Tag Manager" and
  tracker.id == "G-Y8J4SNTNFY"
)
vt.net.url.trackers[x].namestringTracker name
vt.net.url.trackers[x].idstringTracker assigned unique ID
vt.net.url.trackers[x].urlstringURL the tracker is loaded fromfor any tracker in vt.net.url.trackers: ( tracker.url contains "google-analytics.com/analytics.js" )
vt.net.url.response_headersdictHeaders returned when making a request to the URLvt.net.url.response_headers["Server"] == "nginx"
vt.net.url.number_of_response_headersintAmount of response headersvt.net.url.number_of_response_headers == 10
vt.net.url.response_codeintHTTP status code seen when making a request to the URLvt.net.url.response_code == 429
vt.net.url.cookiesdictRequest cookiesfor any k, v in vt.net.url.cookies: ( k == "APPSESSID" ) and vt.net.url.cookies["APPSESSID"] contains "xxx"
vt.net.url.favicon.raw_md5stringMD5 hash of the URL's favicon. To find a property raw md5 search VT for its URL and check details. Retrieving raw_md5.vt.net.url.favicon.raw_md5 == "6cf6865d5e5cb8f65fe9c0ff93a7904d"
vt.net.url.favicon.dhashstringThe URL's favicon dhash. To find a property dhash search VT for its URL and check details. Retrieving dhash.vt.net.url.favicon.dhash == "924dccd4d46933cc"
vt.net.url.outgoing_linksarray of stringLinks included in the URL’s response pointing to URLs from other domains.for any link in vt.net.url.outgoing_links: ( link matches /.*www\.bankofamerica\.com.*/ )
vt.net.url.redirectsarray of stringList of redirecting URLs visited until reaching the final one.for any r in vt.net.url.redirects: ( not r contains vt.net.domain.domain)
vt.net.url.html_titlestringText found under the URL’s returned HTML <title> tag
vt.net.url.html_meta_tagsdictValues found under the meta tags in the returned HTMLfor any meta_tags in vt.net.url.html_meta_tags: ( meta_tags.key == "og:title" and for any value in meta_tags.values: ( value == "Amazon - Start a Career" ))
vt.net.url.tagsarray of stringTags defining interesting features of the URLfor any tag in vt.net.url.tags: ( tag == "opendir" or tag == "ip" )
vt.net.url.analysis_statsstructAnalysis Stats Struct infovt.net.url.analysis_stats.malicious > 1
vt.net.url.categoriesdictContent categories of its domain by enginefor any engine, value in vt.net.url.categories: (value == "known infection source")
vt.net.url.signaturesdictSignature returned by the engine.for any engine, value in vt.net.url.signatures: ( engine == "Kaspersky" and value icontains "pua" )
vt.net.url.downloaded_filestructMetadata from the latest file downloaded from the URL.
vt.net.url.downloaded_file.new_for_vtboolIndicates that the file has not been previously seen in VT.
vt.net.url.downloaded_file.new_for_urlboolIndicates that the file has not been previously seen being downloaded from that particular URL.
vt.net.url.downloaded_file.new_for_domainboolIndicates that the file has not been previously seen being downloaded from the URL’s domain.
vt.net.url.downloaded_file.new_for_ipboolIndicates that the file has not been previously seen being downloaded from the IP the URL resolves to.
vt.net.url.downloaded_file.sha256stringLatest downloaded file SHA256.
vt.net.url.downloaded_file.file_typeintLatest downloaded file's type (one of the types listed in the file types table).
vt.net.url.downloaded_file.analysis_statsstructLatest downloaded file analysis stats. Analysis Stats Struct info
vt.net.url.downloaded_file.signaturesdictSignature returned by the engine.
vt.net.url.communicating_filestructMetadata from the latest file that has made communications (behaviour) with this URL.
vt.net.url.communicating_file.new_for_vtboolFile has not been previously seen in VT.
vt.net.url.communicating_file.new_for_urlbool
vt.net.url.communicating_file.new_for_domainbool
vt.net.url.communicating_file.new_for_ipbool
vt.net.url.communicating_file.sha256stringLatest file (sha256) making communications with this URL.
vt.net.url.communicating_file.file_typeintLatest file type making communications with this URL (one of the types listed in the file types table).
vt.net.url.communicating_file.analysis_statsstructAnalysis Stats Struct info
vt.net.url.submitter.citystringCity from where the resource was submitted, referred to the last submission. All lowercases.
vt.net.url.submitter.countrystringCountry from where the resource was submitted, referred to the last submission. This is a two-letter ISO 3166 country code, in uppercase.

IP Metadata

FieldTypeDescriptionExample
vt.net.ip.rawThe URL in canonical form.
vt.net.ip.new_ip
vt.net.ip.whoisdictWhois record in key, value format.vt.net.ip.whois["Admin Country"] == "ES"
vt.net.ip.whois_rawstringWhole IP whois as a string for pattern matching.
vt.net.ip.new_whoisboolIP has an updated whois.
vt.net.ip.reverse_lookupstringDomain observed resolving to this IP address for first time. Creating a feed of domain IP resolutions.vt.net.ip.reverse_lookup equals "yourdomain.com"
vt.net.ip.jarmstringTLS fingerprint
vt.net.ip.https_certificate.thumbprint
vt.net.ip.https_certificate.subjectstructCertificate Subject info
vt.net.ip.https_certificate.validity.not_afterintTimestamp after which the certificate is no longer valid, in seconds since the Unix epochvt.net.ip.https_certificate.validity.not_after < 1672531200 // 2023–01-01
vt.net.ip.https_certificate.validity.not_beforeintTimestamp at which the certificate becomes valid, in seconds since the Unix epochvt.net.ip.https_certificate.validity.not_before < 946684800 // 2000-01-01
vt.net.ip.https_certificate.subject_alternative_namestring
vt.net.ip.https_certificate.signaturestring
vt.net.ip.https_certificate.serial_numberstring
vt.net.ip.https_certificate.issuerstructCertificate Subject info
vt.net.ip.analysis_statsstructAnalysis Stats Struct info
vt.net.ip.signaturesdictSignature returned by the engine.for any engine, value in vt.net.ip.signatures: ( engine == "Kaspersky" and value icontains "pua" )
vt.net.ip.downloaded_filestructMetadata from the latest file downloaded from the IP.
vt.net.ip.downloaded_file.new_for_vtboolSeen for the first time being downloaded in VT.
vt.net.ip.downloaded_file.new_for_ipboolSeen for the first time being downloaded from this IP. Notice that it may already be known in VT.
vt.net.ip.downloaded_file.sha256stringLatest downloaded file SHA256.
vt.net.ip.downloaded_file.file_typeintLatest downloaded file's type (one of the types listed in the file types table).
vt.net.ip.downloaded_file.analysis_statsstructAnalysis Stats Struct info
vt.net.ip.downloaded_file.signaturesdictSignature returned by the engine.
vt.net.ip.communicating_filestructMetadata from the latest file that has made communications (behavior) with this IP.
vt.net.ip.communicating_file.new_for_ipboolA communicating file is seen for the first time connected to this IP. Notice that it may already be known in VT.
vt.net.ip.communicating_file.new_for_vtbool
vt.net.ip.communicating_file.sha256stringLatest file sha256 that made communications with this IP.
vt.net.ip.communicating_file.file_typeintLatest file type (one of the types listed in the file types table) that made communications with this IP.
vt.net.ip.communicating_file.analysis_statsstructAnalysis Stats Struct info
vt.net.ip.communicating_file.signaturesdictSignature returned by the engine.
vt.net.ip.ip_as_ownerstringIP AS (Autonomous System) owner
vt.net.ip.ip_asnintAutonomous System Number
vt.net.ip.ip_countrystringIP Country
vt.net.ip.ip_as_intintIP dotless decimal number notationvt.net.ip.ip_as_int == 3941835776

Domain metadata

FieldTypeDescriptionExample
vt.net.domain.rawstringDomain as a stringvt.net.domain.raw matches /virustotal/
vt.net.domain.rootstringRoot part of the domain, ie: sub2.sub.root.tld -> root.tldvt.net.domain.root == "example.com"
vt.net.domain.new_domainboolDomain is first seen in VT, not necessarily still exists.
vt.net.domain.first_resolutionboolDomain resolves to an IP for first time
vt.net.domain.new_resolutionboolDomain resolves to a different IP
vt.net.domain.whoisdictWhois record in key, value format.vt.net.domain.whois["Admin Country"] == "ES"
vt.net.domain.whois_rawstringWhole Domain whois as a string for pattern matching.
vt.net.domain.first_whoisboolDomain has whois for first time
vt.net.domain.new_whoisboolDomain has an updated whois
vt.net.domain.https_certificate.thumbprintstringHash of the certificatevt.net.domain.https_certificate.thumbprint == "5d079c6fad2ac214bbdbfcead1584475c3ff41a1"
vt.net.domain.https_certificate.subjectstructCertificate Subject info
vt.net.domain.https_certificate.validity.not_afterintTimestamp after which the certificate is no longer valid, in seconds since the Unix epochvt.net.domain.https_certificate.validity.not_after < 1672531200 // 2023–01-01
vt.net.domain.https_certificate.validity.not_beforeintTimestamp at which the certificate becomes valid, in seconds since the Unix epochvt.net.domain.https_certificate.validity.not_before < 946684800 // 2000-01-01
vt.net.domain.https_certificate.subject_alternative_namearray of stringsAdditional certified hostnamesfor any name in vt.net.domain.https_certificate.subject_alternative_name: name matches /virustotal/
vt.net.domain.https_certificate.signaturestringCertificate signaturevt.net.domain.https_certificate.signature matches /757abd2f/
vt.net.domain.https_certificate.serial_numberstringUnique identifier of the certificate, generated by the issuervt.net.domain.https_certificate.serial_number = "0bd240b87061dc31bda675382053bef9"
vt.net.domain.https_certificate.issuerstructCertificate Subject info
vt.net.domain.jarmstringTLS fingerprintvt.net.domain.jarm = "29d3fd00029d29d21c42d43d00041d188e8965256b2536432a9bd447ae607f"
vt.net.domain.dns_records[].valuestringDNS record resolution.for any record in vt.net.domain.dns_records: (record.value contains "sslserver")
vt.net.domain.dns_records[].typestringRecord typefor any record in vt.net.domain.dns_records: (record.type == "SOA")
vt.net.domain.dns_records[].dns_classstringClass (IN, CH or HS)for any record in vt.net.domain.dns_records: (record.dns_class == "CH")
vt.net.domain.dns_records[].ttlintTTL (in seconds)for any record in vt.net.domain.dns_records: (record.ttl < 2)
vt.net.domain.dns_records[].mnamestringPrimary name serverfor any record in vt.net.domain.dns_records: (record.mname matches /nameserver/)
vt.net.domain.dns_records[].rnamestringE-mail address of the administratorfor any record in vt.net.domain.dns_records: (record.rname matches /cloud.*host/)
vt.net.domain.dns_records[].priorityintPriorityfor any record in vt.net.domain.dns_records: (record.priority = 1)
vt.net.domain.dns_records[].serialintSerial numberfor any record in vt.net.domain.dns_records: (record.serial matches /^9999/)
vt.net.domain.dns_records[].retryintNumber of seconds after which secondary name servers should retry to request the serial number from the master if the master does not respondfor any record in vt.net.domain.dns_records: (record.retry < 100)
vt.net.domain.dns_records[].refreshintSeconds after which secondary name servers should query the master for the SOA record, to detect zone changesfor any record in vt.net.domain.dns_records: (record.refresh < 5000)
vt.net.domain.dns_records[].expireintSeconds after which secondary name servers should stop answering request for this zone if the master does not respondfor any record in vt.net.domain.dns_records: (record.expire < 500000)
vt.net.domain.dns_records[].minimumintIn seconds. Used in calculating the TTL for purposes of negative cachingfor any record in vt.net.domain.dns_records: (record.minimum == 3000)
vt.net.domain.favicon.raw_md5stringMD5 hash of the URL's favicon. To find a property raw md5 search VT for its URL and check details. Retrieving raw_md5.vt.net.domain.favicon.raw_md5 == "6cf6865d5e5cb8f65fe9c0ff93a7904d"
vt.net.domain.favicon.dhashstringThe URL's favicon dhash. To find a property dhash search VT for its URL and check details Retrieving dhash.vt.net.domain.favicon.dhash == "924dccd4d46933cc"
vt.net.domain.tagsarray of stringsfor any tag in vt.net.domain.tags: name == "dga"
vt.net.domain.analysis_statsstructAnalysis Stats Struct info
vt.net.domain.categoriesdictContent categories by enginefor any engine, value in vt.net.domain.categories: (value == "malware command and control")
vt.net.domain.popularity_ranks[].positionintPosition of the domain in a specific popularity rank. Low numbers (closer to 1) indicate that the domain is more popular.for any r in vt.net.domain.popularity_ranks: (r.position < 10)
vt.net.domain.popularity_ranks[].ingestion_timeintUNIX UTC timestamp at which the position in the rank was ingested.for any r in vt.net.domain.popularity_ranks: (r.ingestion_time > 1672531200) // 2023-01-01
vt.net.domain.popularity_ranks[].rankstringName of the popularity rank.for any r in vt.net.domain.popularity_ranks: (r.rank == "Example")
vt.net.domain.number_of_popularity_ranksintNumber of popularity ranks entries for the domain.vt.net.domain.number_of_popularity_ranks == 5
vt.net.domain.root_popularity_ranks[].positionintPosition of the root domain in a specific popularity rank. Low numbers (closer to 1) indicate that the domain is more popular.for any r in vt.net.domain.root_popularity_ranks: (r.position < 10)
vt.net.domain.root_popularity_ranks[].ingestion_timeintUNIX UTC timestamp at which the position in the rank was ingested.for any r in vt.net.domain.root_popularity_ranks: (r.ingestion_time > 1672531200) // 2023-01-01
vt.net.domain.root_popularity_ranks[].rankstringName of the popularity rank.for any r in vt.net.domain.root_popularity_ranks: (r.rank == "Example")
vt.net.domain.number_of_root_popularity_ranksintNumber of popularity ranks entries for the root domain.vt.net.domain.number_of_root_popularity_ranks == 5
vt.net.domain.signaturesdictDictionary where keys are antivirus names and values are malware signatures (in lowercase).vt.net.domain.signatures["Avira"] == "phishing"
vt.net.url.downloaded_filestructMetadata from the latest file downloaded from the domain.
vt.net.domain.downloaded_file.new_for_vtboolSeen for the first time being downloaded in VT.
vt.net.domain.downloaded_file.new_for_domainboolSeen for the first time being downloaded from this domain. Notice that it may already be known in VT.
vt.net.domain.downloaded_file.sha256stringLatest downloaded file SHA256.
vt.net.domain.downloaded_file.file_typeintLatest downloaded file's type (one of the types listed in the file types table).
vt.net.domain.downloaded_file.analysis_statsstructAnalysis Stats Struct info
vt.net.domain.downloaded_file.signaturesdictDictionary where keys are antivirus names and values are malware signatures (in lowercase).
vt.net.domain.communicating_filestructMetadata from the latest file that has made communications (behaviour) with this domain.
vt.net.domain.communicating_file.new_for_domainbool
vt.net.domain.communicating_file.new_for_vtbool
vt.net.domain.communicating_file.sha256stringLatest file sha256 that made communications with this domain.
vt.net.domain.communicating_file.file_typeintLatest file's type (one of the types listed in the file types table) that made communications with this domain.
vt.net.domain.communicating_file.analysis_statsstructAnalysis Stats Struct info
vt.net.domain.communicating_file.signaturesdictDictionary where keys are antivirus names and values are malware signatures (in lowercase).

File ITW field

FieldTypeDescriptionExample
vt.metadata.itwstructLatest ITW relation observed for the file. When VirusTotal opens a URL that downloads a file this struct will be filled with the information of the corresponding URL/Domain/IP and it will notify you accordingly.
vt.metadata.itw.urlstructRefers to URL information for the latest itw relation
vt.metadata.itw.domainstructRefers to Domain information for the latest itw relation
vt.metadata.itw.ipstructRefers to IP information for the latest itw relation

Analysis stats struct

FieldTypeDescriptionExample
analysis_stats.maliciousintAmount of engine returning malicious in the analysis.vt.net.domain.analysis_stats.malicious > 5
analysis_stats.suspiciousintAmount of engine returning suspicious in the analysis.vt.net.url.analysis_stats.suspicious > 10
analysis_stats.undetectedintAmount of engine returning undetected in the analysis.vt.net.ip.analysis_stats.undetected > 20
analysis_stats.harmlessintAmount of engine returning harmless in the analysis.vt.metadata.analysis_stats.harmless > 25
analysis_stats.timeoutintAmount of engine returning timeout in the analysis.vt.net.domain.analysis_stats.timeout > 1
analysis_stats.confirmed_timeoutintAmount of engine returning confirmed timeout in the analysis.vt.net.url.analysis_stats.confirmed_timeout > 1
analysis_stats.failureintAmount of engine that failed during the analysis process.vt.net.ip.analysis_stats.failure > 1
analysis_stats.type_unsupportedintAmount of engine that do not support the file/IoC type.vt.metadata.analysis_stats.type_unsupported > 1

HTTPs Certificate Subject struct

FieldTypeDescriptionExample
https_certificate.subject.common_namestringCommon name, also known as the Fully Qualified Domain Name (FQDN), of the subject that is certified.vt.net.ip.https_certificate.subject.common_name matches /virustotal/
https_certificate.subject.countrystringTwo-letter country code that identifies the country of the subject that is certified.vt.net.domain.https_certificate.subject.country == "US"
https_certificate.subject.organizationstringThe organization to which the certificate has been issued.vt.net.ip.https_certificate.subject.organization matches /VirusTotal/
https_certificate.subject.organizational_unitstringAdditional information about the certified organization.vt.net.domain.https_certificate.subject.organizational_unit matches /Domain Control/
https_certificate.subject.localitystringThe city where the certified organization is located.vt.net.ip.https_certificate.subject.locality == "Madrid"
https_certificate.subject.statestringThe state where the certified organization is located.vt.net.domain.https_certificate.subject.state == "Washington"

Network range helper

In order to match complex IP range matches you can use the next javascript function:

function cidrToInt(yara_fn, raw_cidr) {
    cidr = raw_cidr.split('/');
    ip = cidr[0].split('.').reduce(function(ipInt, octet) { return (ipInt<<8) + parseInt(octet, 10)}, 0) >>> 0;
    base = Math.pow(2, 32 - cidr[1])
    start = Math.floor(ip / base) * base;
    end = Math.pow(2, 32 - cidr[1]) + start;
    return (yara_fn + " >= " + start + " and " + yara_fn + " < " + end + " // " + raw_cidr);
}

// Examples:
// Matching with a net rule (URL, Domain, IP):
console.log(cidrToInt("vt.net.ip.ip_as_int", "234.243.166.33/22"));

// Matching with a File rule:
console.log(cidrToInt("vt.metadata.itw.ip.ip_as_int", "234.243.166.33/22"));

Net output: vt.net.ip.ip_as_int >= 3941835776 and vt.net.ip.ip_as_int < 3941836800 // 234.243.166.33/22
File output: vt.metadata.itw.ip.ip_as_int >= 3941835776 and vt.metadata.itw.ip.ip_as_int < 3941836800 // 234.243.166.33/22

Filetypes automatically analysed

There is only some filetypes that are automatically submitted for a file analysis after URL is received:

GZIP.Z compressedPDFCertificates7ZIPBZIP
ISO9660Chrome extensionsDMGMicrosoft CabinetEXEZIP
RARWinZipAndroid dex filesApple Disk ImageELFDMG
Java bytecodeMachoDOCs

These filetypes applies to vt.net.url.downloaded_file. attributes, in case you want to scan other filetypes you should write a content rule ("strings") and once the match is done the hash will be visible in VT and you will have the possibility to submit it for a file analysis.

FAQ

How do I match certain content or sized response:

In Nethunt the content of the response is treated as a file (HTTP headers, etc are not included), you can use that content/file to make matches like in traditional matching yaras. Some examples:

  • Matching some strings:
import "vt"

rule html_content {
meta:
  description = "URLs matching certain strings in content"
  author = "virustotal"
  target_entity = "url"
strings:
  $mystring = "some&html"
condition:
  $mystring and $mystring at 400
}
  • Matching empty response:
import "vt"

rule empty_content {
meta:
  description = "URLs matching empty content"
  author = "virustotal"
  target_entity = "url"
condition:
  filesize == 0
}

How do I match URLs in certain ASN number/IP range, etc:

You are able to mix different net modules in a single rule and match over a single net type, for example:

  • Notify new URLs whos domain resolve its IP address of a certain ASN in a certain IP range
import "vt"

rule urls_in_asn {
meta:
  description = "New URLs whos domain resolve to certain ASN"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.new_url and
  vt.net.ip.ip_asn == 74838
}
  • Notify new URLs whos domain resolve in a certain IP range (IP range helper):
import "vt"

rule urls_in_iprange {
meta:
  description = "New URLs whos domain resolve to my IP range"
  author = "virustotal"
  target_entity = "url"
condition:
  vt.net.url.new_url and
  vt.net.ip.ip_as_int >= 3941835776 and vt.net.ip.ip_as_int < 3941836800 // 234.243.166.33/22
}

How do I obtain a domain favicon hashes:

You need to search for the domain URL in VirusTotal, go to https://www.virustotal.com/gui/search, and write your domain url, ie: http://google.com , then go to details tab and at the end you will find a "Favicon" header, there you can see both dhash and raw mad5 hashes.

import "vt"

rule urls_with_dhash {
meta:
  description = "Domains with similar favicons"
  author = "virustotal"
  target_entity = "domain"
condition:
  vt.net.url.favicon.dhash == "f0cc929ab296cc71" or
  vt.net.url.favicon.raw_md5 == "30e26a059b7b858731e172c431d55bb4"
}

How do I obtain domains with self signed certificates:

You can use the "self-signed" tag for that, to be notified you could use for example:

import "vt"

rule selfsigned_certificate_domains {
meta:
  description = "Domains with self signed certificates"
  author = "virustotal"
  target_entity = "domain"
condition:
  for any tag in vt.net.domain.tags: (
    tag == "self-signed"
  )
}

How do I obtain a feed of IP resolutions for a certain domain:

It's currently not possible to combine domain matching attributes in IP rules, to overcome this limitation exists the vt.net.ip.reverse_lookup attribute, it can be used like this:

import "vt"

rule ip_resolutions_for_domain {
meta:
  description = "IP resolutions for a certain domain"
  author = "virustotal"
  target_entity = "ip_address"
condition:
  vt.net.ip.reverse_lookup == "somedomain.com"
}