Attackers Hijack Trusted RMM Tools to Create Invisible, Permanent Backdoors
The post Attackers Hijack Trusted RMM Tools to Create Invisible, Permanent Backdoors appeared first on Daily CyberSecurity.
Discover 10 practical ChatGPT prompts SOC analysts can use to speed up triage, analyze threats, improve documentation, and enhance incident response workflows.
The post 10 ChatGPT AI Prompts L1 SOC Analysts Can Use in Their Daily Work appeared first on TechRepublic.
behash:"4acaac53c8340a8c236c91e68244e6cb"
/api/v3/files/09a8b930c8b79e7c313e5e741e1d59c39ae91bc1f10cdefa68b47bf77519be57/execution_parents
signature:"Peastaking plenipotence ductileness chilopodous codicillary."
signature:"© 2026 Eosinophil LLC"
exports:15Mmm95ml1RbfjH1VUyelYFCf exports:2dlSKEtPzvo1mHDN4FYgv
behash:5ddb604194329c1f182d7ba74f6f5946
import "pe"
rule win_dll_sideload_eosinophil_infostealer_jan26
{
meta:
author = "VirusTotal"
description = "Detects malicious DLLs (CoreMessaging.dll) from an infostealer campaign impersonating Malwarebytes, Logitech, and others via DLL sideloading."
reference = "https://blog.virustotal.com/2026/01/malicious-infostealer-january-26.html"
date = "2026-01-16"
behash = "4acaac53c8340a8c236c91e68244e6cb"
target_entity = "file"
hash = "606baa263e87d32a64a9b191fc7e96ca066708b2f003bde35391908d3311a463"
condition:
(uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and pe.is_dll()) and
pe.exports("15Mmm95ml1RbfjH1VUyelYFCf") and pe.exports("2dlSKEtPzvo1mHDN4FYgv")
}
| sha256 | description |
|---|---|
| 6773af31bd7891852c3d8170085dd4bf2d68ea24a165e4b604d777bd083caeaa | malwarebytes-windows-github-io-X.X.X.zip |
| 4294d6e8f1a63b88c473fce71b665bbc713e3ee88d95f286e058f1a37d4162be | malwarebytes-windows-github-io-X.X.X.zip |
| 5591156d120934f19f2bb92d9f9b1b32cb022134befef9b63c2191460be36899 | malwarebytes-windows-github-io-X.X.X.zip |
| 42d53bf0ed5880616aa995cad357d27e102fb66b2fca89b17f92709b38706706 | malwarebytes-windows-github-io-X.X.X.zip |
| 5aa6f4a57fb86759bbcc9fc6c61b5f74c0ca74604a22084f9e0310840aa73664 | malwarebytes-windows-github-io-X.X.X.zip |
| 84021dcfad522a75bf00a07e6b5cb4e17063bd715a877ed01ba5d1631cd3ad71 | malwarebytes-windows-github-io-X.X.X.zip |
| ca8467ae9527ed908e9478c3f0891c52c0266577ca59e4c80a029c256c1d4fce | malwarebytes-windows-github-io-X.X.X.zip |
| 9619331ef9ff6b2d40e77a67ec86fc81b050eeb96c4b5f735eb9472c54da6735 | malwarebytes-windows-github-io-X.X.X.zip |
| a2842c7cfaadfba90b29e0b9873a592dd5dbea0ef78883d240baf3ee2d5670c5 | malwarebytes-windows-github-io-X.X.X.zip |
| 4705fd47bf0617b60baef8401c47d21afb3796666092ce40fbb7fe51782ae280 | malwarebytes-windows-github-io-X.X.X.zip |
| 580d37fc9d9cc95dc615d41fa2272f8e86c9b4da2988a336a8b3a3f90f4363c2 | malwarebytes-windows-github-io-X.X.X.zip |
| d47fd17d1d82ea61d850ccc2af3bee54adce6975d762fb4dee8f4006692c5ef7 | malwarebytes-windows-github-io-X.X.X.zip |
| 606baa263e87d32a64a9b191fc7e96ca066708b2f003bde35391908d3311a463 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| fd855aa20467708d004d4aab5203dd5ecdf4db2b3cb2ed7e83c27368368f02bb | CoreMessaging.dll DLL loaded by DLL SideLoading |
| a0687834ce9cb8a40b2bb30b18322298aff74147771896787609afad9016f4ea | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 4235732440506e626fd4d0fffad85700a8fcf3e83ba5c5bc8e19ada508a6498e | CoreMessaging.dll DLL loaded by DLL SideLoading |
| cd1fe2762acf3fb0784b17e23e1751ca9e81a6c0518c6be4729e2bc369040ca5 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f798c24a688d7858efd6efeaa8641822ad269feeb3a74962c2f7c523cf8563ff | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 0698a2c6401059a3979d931b84d2d4b011d38566f20558ee7950a8bf475a6959 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 1b3bee041f2fffcb9c216522afa67791d4c658f257705e0feccc7573489ec06f | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 231c05f4db4027c131259d1acf940e87e15261bb8cb443c7521294512154379b | CoreMessaging.dll DLL loaded by DLL SideLoading |
| ec2e30d8e5cacecdf26c713e3ee3a45ebc512059a64ba4062b20ca8bec2eb9e7 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 58bd2e6932270921028ab54e5ff4b0dbd1bf67424d4a5d83883c429cadeef662 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 57ed35e6d2f2d0c9bbc3f17ce2c94946cc857809f4ab5c53d7cb04a4e48c8b14 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| cfcf3d248100228905ad1e8c5849bf44757dd490a0b323a10938449946eabeee | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f02be238d14f8e248ad9516a896da7f49933adc7b36db7f52a7e12d1c2ddc6af | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f60802c7bec15da6d84d03aad3457e76c5760e4556db7c2212f08e3301dc0d92 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 02dc9217f870790b96e1069acd381ae58c2335b15af32310f38198b5ee10b158 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f9549e382faf0033b12298b4fd7cd10e86c680fe93f7af99291b75fd3d0c9842 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 92f4d95938789a69e0343b98240109934c0502f73d8b6c04e8ee856f606015c8 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 66fba00b3496d61ca43ec3eae02527eb5222892186c8223b9802060a932a5a7a | CoreMessaging.dll DLL loaded by DLL SideLoading |
| e5dd464a2c90a8c965db655906d0dc84a9ac84701a13267d3d0c89a3c97e1e9b | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 35211074b59417dd5a205618fed3402d4ac9ca419374ff2d7349e70a3a462a15 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 6863b4906e0bd4961369b8784b968b443f745869dbe19c6d97e2287837849385 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| a83c478f075a3623da5684c52993293d38ecaa17f4a1ddca10f95335865ef1e2 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 43e2936e4a97d9bc43b423841b137fde1dd5b2f291abf20d3ba57b8f198d9fab | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f001ae3318ba29a3b663d72b5375d10da5207163c6b2746cfae9e46a37d975cf | CoreMessaging.dll DLL loaded by DLL SideLoading |
| c67403d3b6e7750222f20fa97daa3c05a9a8cce39db16455e196cd81d087b54d | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 5ee9d4636b01fd3a35bd8e3dce86a8c114d8b0aa6b68b1d26ace7ef0f85b438a | Payload dropped by one of the malicious DLLs |
| e84b0dadb0b6be9b00a063ed82c8ddba06a2bd13f07d510d14e6fd73cd613fba | Payload dropped by one of the malicious DLLs |
behash:"4acaac53c8340a8c236c91e68244e6cb"
/api/v3/files/09a8b930c8b79e7c313e5e741e1d59c39ae91bc1f10cdefa68b47bf77519be57/execution_parents
signature:"Peastaking plenipotence ductileness chilopodous codicillary."
signature:"© 2026 Eosinophil LLC"
exports:15Mmm95ml1RbfjH1VUyelYFCf exports:2dlSKEtPzvo1mHDN4FYgv
behash:5ddb604194329c1f182d7ba74f6f5946
import "pe"
rule win_dll_sideload_eosinophil_infostealer_jan26
{
meta:
author = "VirusTotal"
description = "Detects malicious DLLs (CoreMessaging.dll) from an infostealer campaign impersonating Malwarebytes, Logitech, and others via DLL sideloading."
reference = "https://blog.virustotal.com/2026/01/malicious-infostealer-january-26.html"
date = "2026-01-16"
behash = "4acaac53c8340a8c236c91e68244e6cb"
target_entity = "file"
hash = "606baa263e87d32a64a9b191fc7e96ca066708b2f003bde35391908d3311a463"
condition:
(uint16(0) == 0x5A4D and uint32(uint32(0x3C)) == 0x00004550 and pe.is_dll()) and
pe.exports("15Mmm95ml1RbfjH1VUyelYFCf") and pe.exports("2dlSKEtPzvo1mHDN4FYgv")
}
| sha256 | description |
|---|---|
| 6773af31bd7891852c3d8170085dd4bf2d68ea24a165e4b604d777bd083caeaa | malwarebytes-windows-github-io-X.X.X.zip |
| 4294d6e8f1a63b88c473fce71b665bbc713e3ee88d95f286e058f1a37d4162be | malwarebytes-windows-github-io-X.X.X.zip |
| 5591156d120934f19f2bb92d9f9b1b32cb022134befef9b63c2191460be36899 | malwarebytes-windows-github-io-X.X.X.zip |
| 42d53bf0ed5880616aa995cad357d27e102fb66b2fca89b17f92709b38706706 | malwarebytes-windows-github-io-X.X.X.zip |
| 5aa6f4a57fb86759bbcc9fc6c61b5f74c0ca74604a22084f9e0310840aa73664 | malwarebytes-windows-github-io-X.X.X.zip |
| 84021dcfad522a75bf00a07e6b5cb4e17063bd715a877ed01ba5d1631cd3ad71 | malwarebytes-windows-github-io-X.X.X.zip |
| ca8467ae9527ed908e9478c3f0891c52c0266577ca59e4c80a029c256c1d4fce | malwarebytes-windows-github-io-X.X.X.zip |
| 9619331ef9ff6b2d40e77a67ec86fc81b050eeb96c4b5f735eb9472c54da6735 | malwarebytes-windows-github-io-X.X.X.zip |
| a2842c7cfaadfba90b29e0b9873a592dd5dbea0ef78883d240baf3ee2d5670c5 | malwarebytes-windows-github-io-X.X.X.zip |
| 4705fd47bf0617b60baef8401c47d21afb3796666092ce40fbb7fe51782ae280 | malwarebytes-windows-github-io-X.X.X.zip |
| 580d37fc9d9cc95dc615d41fa2272f8e86c9b4da2988a336a8b3a3f90f4363c2 | malwarebytes-windows-github-io-X.X.X.zip |
| d47fd17d1d82ea61d850ccc2af3bee54adce6975d762fb4dee8f4006692c5ef7 | malwarebytes-windows-github-io-X.X.X.zip |
| 606baa263e87d32a64a9b191fc7e96ca066708b2f003bde35391908d3311a463 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| fd855aa20467708d004d4aab5203dd5ecdf4db2b3cb2ed7e83c27368368f02bb | CoreMessaging.dll DLL loaded by DLL SideLoading |
| a0687834ce9cb8a40b2bb30b18322298aff74147771896787609afad9016f4ea | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 4235732440506e626fd4d0fffad85700a8fcf3e83ba5c5bc8e19ada508a6498e | CoreMessaging.dll DLL loaded by DLL SideLoading |
| cd1fe2762acf3fb0784b17e23e1751ca9e81a6c0518c6be4729e2bc369040ca5 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f798c24a688d7858efd6efeaa8641822ad269feeb3a74962c2f7c523cf8563ff | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 0698a2c6401059a3979d931b84d2d4b011d38566f20558ee7950a8bf475a6959 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 1b3bee041f2fffcb9c216522afa67791d4c658f257705e0feccc7573489ec06f | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 231c05f4db4027c131259d1acf940e87e15261bb8cb443c7521294512154379b | CoreMessaging.dll DLL loaded by DLL SideLoading |
| ec2e30d8e5cacecdf26c713e3ee3a45ebc512059a64ba4062b20ca8bec2eb9e7 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 58bd2e6932270921028ab54e5ff4b0dbd1bf67424d4a5d83883c429cadeef662 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 57ed35e6d2f2d0c9bbc3f17ce2c94946cc857809f4ab5c53d7cb04a4e48c8b14 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| cfcf3d248100228905ad1e8c5849bf44757dd490a0b323a10938449946eabeee | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f02be238d14f8e248ad9516a896da7f49933adc7b36db7f52a7e12d1c2ddc6af | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f60802c7bec15da6d84d03aad3457e76c5760e4556db7c2212f08e3301dc0d92 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 02dc9217f870790b96e1069acd381ae58c2335b15af32310f38198b5ee10b158 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f9549e382faf0033b12298b4fd7cd10e86c680fe93f7af99291b75fd3d0c9842 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 92f4d95938789a69e0343b98240109934c0502f73d8b6c04e8ee856f606015c8 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 66fba00b3496d61ca43ec3eae02527eb5222892186c8223b9802060a932a5a7a | CoreMessaging.dll DLL loaded by DLL SideLoading |
| e5dd464a2c90a8c965db655906d0dc84a9ac84701a13267d3d0c89a3c97e1e9b | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 35211074b59417dd5a205618fed3402d4ac9ca419374ff2d7349e70a3a462a15 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 6863b4906e0bd4961369b8784b968b443f745869dbe19c6d97e2287837849385 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| a83c478f075a3623da5684c52993293d38ecaa17f4a1ddca10f95335865ef1e2 | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 43e2936e4a97d9bc43b423841b137fde1dd5b2f291abf20d3ba57b8f198d9fab | CoreMessaging.dll DLL loaded by DLL SideLoading |
| f001ae3318ba29a3b663d72b5375d10da5207163c6b2746cfae9e46a37d975cf | CoreMessaging.dll DLL loaded by DLL SideLoading |
| c67403d3b6e7750222f20fa97daa3c05a9a8cce39db16455e196cd81d087b54d | CoreMessaging.dll DLL loaded by DLL SideLoading |
| 5ee9d4636b01fd3a35bd8e3dce86a8c114d8b0aa6b68b1d26ace7ef0f85b438a | Payload dropped by one of the malicious DLLs |
| e84b0dadb0b6be9b00a063ed82c8ddba06a2bd13f07d510d14e6fd73cd613fba | Payload dropped by one of the malicious DLLs |

As security researchers, we actively monitor the latest CVEs and their publicly available exploits to create signatures. Beyond CVEs, we also hunt for malware on platforms such as MalwareBazaar, which enhances our visibility into attacks occurring across networks.

Tracking threat actor infrastructure has become increasingly complex. Modern adversaries rotate domains, reuse hosting, and replicate infrastructure templates across operations, making it difficult to connect isolated indicators to broader activity. Checking an IP, a domain, or a certificate in isolation can often return little of value when adversaries hide behind short-lived domains and churned TLS certificates.
As a result, analysts can struggle to see how infrastructure evolves over time or to identify shared traits like favicon hashes, header patterns, or registration overlaps that can link related assets.
To help address this, SentinelLABS is sharing a Synapse Rapid Power-Up for Validin. Developed in-house by SentinelLABS engineers, the sentinelone-validin power-up provides commands to query for and model DNS records, HTTP crawl data, TLS certificates, and WHOIS information, enabling analysts to quickly search, pivot through, and investigate network infrastructure for time-aware, cross-source analysis.
In this post, we explore two real-world case studies to demonstrate how an analyst can use the power-up to discover and expand their knowledge of threats.
When Microsoft published indicators for LaundryBear (aka Void Blizzard), a Russian APT targeting NATO and Ukraine, the threat report included just three domains. Using the power-up’s HTTP body hash pivots, we can expand this seed set to over 30 related domains, revealing the full scope of the campaign’s infrastructure.
We begin with the s1.validin.enrich command, which serves as a unified entry point for all Validin data sources. Rather than running separate commands for DNS history, HTTP crawls, certificates, and WHOIS records, this single command executes comprehensive enrichment across all four datasets simultaneously.
The resulting node graph immediately reveals initial pivot opportunities—shared nameservers in DNS records, certificate SAN relationships, registration timing patterns, and HTTP fingerprint clusters—providing multiple investigative paths forward.
This rapid reconnaissance phase surfaces the most promising leads before committing to expensive deep pivots, helping analysts choose the optimal next step based on what patterns emerge from the enriched graph.
// Tag the published spear-phishing domain [inet:fqdn=<phising domain> +#research.laundrybear.seed] // enrich the initial domain inet:fqdn#research.laundrybear.seed | s1.validin.enrich --wildcard // display all unique fqdns related to this seed inet:fqdn#research.laundrybear.seed -> inet:fqdn | uniq

The Validin crawler (Crawlr) is a purpose-built, large-scale web crawler operated by Validin that continuously scans internet infrastructure. Querying Validin through the sentinelone-validin power-up provides access to pre-existing crawl observations, allowing instant analysis without active scanning.
The crawler data for our seed domains was already downloaded during the initial s1.validin.enrich command. This created inet:http:request nodes in Synapse containing multiple HTTP fingerprints stored as custom properties: body hashes (SHA1), favicon hashes (MD5), certificate fingerprints, banner hashes, and CSS class hashes.
Each fingerprint type serves as a pivot point: body hashes reveal identical content, favicon hashes expose shared branding, certificate fingerprints uncover SSL infrastructure, and class hashes detect configuration patterns. Together, these pivots transform the initial three seed domains into a comprehensive infrastructure map.
The query starts with our tagged seed domains, pivots to any related FQDNs discovered during enrichment, follows URL relationships, and lands on the actual HTTP request nodes captured by Validin’s crawler. Each inet:http:request node serves as a rich pivot point connecting to multiple content fingerprints and infrastructure properties.
// List all http requests to all the subdomains inet:fqdn#research.laundrybear.seed -> inet:fqdn -> inet:url -> inet:http:request


Validin’s Laundry Bear Infrastructure analysis identified synchronized HTTP responses across threat actor infrastructure. We can reach the same discovery using Storm’s HTTP pivot with statistical output.
When executing inet:http:request, the command prints detailed occurrence statistics to the Storm console: how many times each HTTP fingerprint from the input http response (body SHA1, favicon MD5, banner hashes, certificate fingerprints, header patterns) appears in Validin’s database. For example, a body hash might appear on 21 IPs and 55 hostnames, a favicon hash might match 18 IPs and 52 hostnames, while a certificate fingerprint on 15 IPs and 48 hostnames.
The size of these counts is the critical indicator. High counts in the thousands indicate benign infrastructure like CDNs and can be dismissed from consideration. Very low counts (1-5) suggest isolated infrastructure. However, when a particular hash appears in the Validin crawler database with a moderate count (15-55 hosts with the same hash fingerprint in this case), it can indicate synchronized infrastructure provisioning: the exact pattern that characterized Laundry Bear’s coordinated buildout. In short, the --dry-run flag transforms expensive full-graph pivots into rapid statistical reconnaissance.
// Collect all the hash:sha1 indicators gathered in the previous step and perform a "dry run" with the s1.validin http.pivot to check statistics inet:fqdn#research.laundrybear.seed -> inet:fqdn -> inet:url -> inet:http:request -> hash:sha1 | uniq | s1.validin.http.pivot --dry-run

After identifying promising body hash pivots through --dry-run statistics, we need to materialize the actual infrastructure and summarize the results. Consider this command:
// materialize and summarize apex domains form single pivot hash:sha1=38c47d338a9c5ab7ccef7413edb7b2112bdfc56f | s1.validin.http.pivot --yield // pivot to apex domains | +inet:fqdn -> inet:fqdn +:iszone=true | uniq

Omitting the --dry-run flag is critical here; removing the flag allows the Storm command to create and persist all discovered nodes in the Cortex. The full infrastructure graph (HTTP requests, certificates, DNS records) is ingested, making it available for future pivots and correlation with other intelligence sources. The final filtering and deduplication produces a concise summary: “This body hash appears across N distinct apex domains”, transforming raw occurrence statistics into actionable threat intelligence.
Results:
Note that the query here identifies ten domains in total, two more than reported in Validin’s analysis of the LaundryBear infrastructure. The extra context here comes from our additional use of the official synapse-psl power-up, which ingests and maintains the Mozilla Public Suffix List and ensures that inet:fqdn:zone correctly identifies true organizational boundaries.
Once we’ve identified related infrastructure through hash pivots, we need to tag these findings for tracking and future analysis. Storm provides inline tagging capabilities that mark nodes during the pivot workflow by appending this snippet at the end of a query that produces output to be tagged.
// Tagging ... [+#research.laundrybear.infra]
This workflow expanded three published indicators to 55 domains and 21 IP addresses through body hash pivots, revealing the campaign’s infrastructure scope.
FreeDrain, an industrial-scale cryptocurrency phishing network, used 38,000+ lure pages across gitbook.io, webflow.io, and github.io. The campaign templated infrastructure with reused favicons, redirector domains, and phishing pages hosted on Azure and AWS S3—an ideal scenario for demonstrating the power-up’s capabilities.
During the initial investigation, SentinelLABS identified a set of redirect domains used by FreeDrain operators to funnel victims from legitimate hosting platforms to attacker-controlled phishing infrastructure. These domains were tagged as #research.freedrain.href in our Cortex. To understand the operational infrastructure behind these redirectors in Synapse, we can enrich them through Validin’s WHOIS data:
// Enrich the domains with whois data inet:fqdn#research.freedrain.href | s1.validin.whois
This enrichment ingests historical WHOIS records for each redirect domain, creating inet:whois:rec nodes with registration dates, expiration information, and critically, registrar relationships.
When exploring the enriched graph in Synapse’s UI, several nodes immediately stand out (highlighted in yellow in our default workspace setup), indicating CNO (Computer Network Operations) tags from previous investigations.

The highlighting reveals that the shared registrar is already tagged as #cno.infra.dns.bulk, a designation in our environment for DNS registrars known to facilitate bulk domain registrations used in threat operations.
This isn’t a coincidental infrastructure overlap: we’ve immediately connected FreeDrain to a known malicious service provider that’s appeared in previous campaigns. The pre-existing #cno. tag transforms this from a simple infrastructure observation into a high-confidence attribution signal: FreeDrain operators are using the same operational resources as other documented threat actors.
Before pivoting broadly, we can survey the registrar landscape within our FreeDrain redirect domain pool to understand infrastructure diversity:
inet:fqdn#research.freedrain.href | s1.validin.whois --yield | :registrar -> * | uniq

To isolate the domains registered through this bulk provider, we can filter directly by registrar name:
inet:fqdn#research.freedrain.href -> inet:whois:rec | +:registrar='<registrar name>'
The FreeDrain case demonstrates how Validin’s WHOIS enrichment can transform large-scale phishing investigations. Starting with a handful of tagged redirect domains, a single enrichment command and two pivot queries exposed the full operational infrastructure—hundreds of domains provisioned through bulk registrars.
This is possible due to Synapse’s ability to correlate new campaign data with historical intelligence: the pre-existing #cno.infra.dns.bulk tags immediately identified FreeDrain’s infrastructure as part of a known malicious service ecosystem, providing attribution context that wouldn’t exist in isolated analysis.
The sentinelone-validin power-up allows us to enrich a domain and pivot to find details, not only about its current registration but the history of the records. With the –wildcard option, Validin returns the DNS records for all related subdomains.
// Enrich the domain with its registration information, and also include subdomains [inet:fqdn=<target domain>] | s1.validin.dns --wildcard

Certificates often include multiple domains in Subject Alternative Name (SAN) fields, revealing infrastructure relationships. The following query can help us to quickly find all certificates issued for a domain and its subdomains:
// Find all domains that share certificates with our target inet:fqdn=<target domain> | s1.validin.certs --wildcard --yield

The sentinelone-validin power-up is able to ingest historical WHOIS registration data, creating several node types that enable temporal analysis of infrastructure:
inet:whois:rec – WHOIS records with registration dates (:created), expiration (:expires), last update (:updated), and registrar informationinet:whois:rar – Registrar entities referenced by WHOIS recordsinet:whois:recns – Nameserver associations for each domain registrationinet:whois:contact – Contact records for domain roles (registrant, admin, tech, billing) including name, organization, email, phone, and postal address detailsMultiple historical records are created per domain, allowing analysts to track changes in infrastructure over time. For example, domains registered on the same day can indicate batch infrastructure provisioning. A query such as:
inet:fqdn=<target domain> | s1.validin.whois
returns all relevant WHOIS records for the target domain, allowing the analyst to pivot to other domains, registrars, or contacts that share temporal or structural relations.
One of the initial challenges we sought to address with the sentinelone-validin power-up was how to improve visibility into infrastructure that exists even as domains and hosting change. Validin’s crawler collects fingerprints such as page content, headers and favicons that persist across domain rotation and infrastructure churn. Leveraging these fingerprints allows analysts to identify patterns and connections that might otherwise be overlooked.
Validin’s HTTP crawler captures and fingerprints multiple aspects of web server responses—favicons, body content, HTTP headers, TLS banners, and HTML structure. The power-up parses these fingerprints and models them as pivotable properties in Synapse, enabling infrastructure clustering through content similarity.
inet:fqdn=<target domain> | s1.validin.http --yield

The crawler extracts:
The power-up includes a built-in download capability that retrieves actual file content for deeper analysis. The s1.validin.download command fetches HTTP response bodies, TLS certificates, and favicon images from Validin’s storage, creating file:bytes nodes in the Cortex.
Combined with Synapse’s fileparser.parse, this enables the extraction of embedded indicators such as URLs, email addresses, file hashes, IP addresses, and other IOCs hidden in page content or certificate metadata:
In Synapse, inet:http:request is a GUID node representing a unique HTTP request event in the hypergraph. Each GUID node has a deterministic identifier usually derived from the request’s properties, enabling implicit deduplication and efficient correlation of network artifacts across the graph.
// Download and parse HTTP responses, certificates, and favicons inet:http:request=| s1.validin.download --yield | fileparser.parse
Traditional graph-based investigation requires loading all data into Synapse first, then querying relationships within your local graph. This works well for known datasets but becomes expensive when exploring unknown infrastructure: an analyst may ingest thousands of nodes only to discover they represent CDN infrastructure, shared hosting, or other benign patterns.
The HTTP pivot capability offers an alternative workflow: querying hashes directly via Validin’s API before loading data into Synapse. This enables selective enrichment, allowing the analyst to explore and evaluate potential pivot paths externally before committing to graph expansion.
// Pivot from a favicon hash to find related domains hash:md5=| s1.validin.http.pivot --category FAVICON_HASH // Pivot from an HTTP request node's embedded hashes inet:http:request= | s1.validin.http.pivot --yield // Discover related infrastructure via body hash hash:sha1= | s1.validin.http.pivot --first-seen 2024/01/01
This approach provides flexibility: assess pivot scope first, then selectively load relevant data.The --dry-run flag shows result counts without creating nodes, letting the analyst preview results before ingestion.
The HTTP pivot command supports multiple content fingerprints:
The sentinelone-validin power-up combines multiple data sources in ways that traditional tools cannot. Using this capability, the analyst can retrieve DNS history, HTTP crawl results, certificates and WHOIS records for a domain, all in one query. For example:
inet:fqdn=<target domain> | s1.validin.enrich
This single command populates the Cortex with a rich node graph, giving the analyst a unified view of the target infrastructure and enabling deeper correlation and pivoting across multiple sources.
SentinelLABS has open-sourced the sentinelone-validin power-up so other Synapse users can leverage these capabilities:
// Load and configure pkg.load --path /path/to/s1-validin.yaml s1.validin.setup.apikey// Start investigating inet:fqdn=<target domain> | s1.validin.enrich
Before deploying the power-up to a production environment, test the environment locally. It is possible to test the power-up with the open-source version of Vertex Cortex as follows
# From the repository root docker compose up -d cortex docker compose --profile tools run --rm loadpkg docker compose --profile tools run --rm storm
inet:fqdn=<target domain> | s1.validin.enrich
| uniq after broad pivots.--first-seen/--last-seen on s1.validin.* commands.| limit during exploration to keep result sets manageable.+#rep.investigation.2026_1.stage1) to branch workflows and compare clusters.Using the LaundryBear and FreeDrain campaigns as case studies, we’ve explored how the sentinelone-validin power-up leverages Validin’s multi-source enrichment and HTTP fingerprinting to reveal wider campaign infrastructure within Synapse, from just a handful of indicators.
The integration makes it easier to follow how infrastructure changes over time, trace shared resources across campaigns, and connect what might first appear as isolated indicators. With this richer context available directly in Synapse, analysts can move from collection to understanding with greater speed and confidence in their conclusions.
The SentinelLABS team welcomes feedback and pull requests on the sentinelone-validin GitHub repository to help refine and extend its capabilities for the wider research community.

/*
Checks if the file is tagged with CVE-2017-0199 or CVE-2017-11882
and originates from one of the targeted countries
and the file type is a Word document, RTF, or MS-Office file
*/
import "vt"
rule hunting_cve_maldocs {
meta:
author = "Acronis Threat Research Unit (TRU)"
description = "Hunting for malicious Word/RTF files exploiting CVE-2017-0199 or CVE-2017-11882 from specific countries"
distribution = "TLP:CLEAR"
version = "1.2"
condition:
// Match if the file has CVE-2017-0199 or CVE-2017-11882 in the tags
for any tag in vt.metadata.tags :
(
tag == "cve-2017-0199" or
tag == "cve-2017-11882"
)
// Originates from a specific country?
and
(
// Removed CN due to spam submissions of related maldocs
vt.metadata.submitter.country == "PK" or
vt.metadata.submitter.country == "LK" or
vt.metadata.submitter.country == "BD" or
vt.metadata.submitter.country == "NP" or
vt.metadata.submitter.country == "MM" or
vt.metadata.submitter.country == "MV" or
vt.metadata.submitter.country == "AF"
)
// Is it a DOC, DOCX, or RTF?
and
(
vt.metadata.file_type == vt.FileType.DOC or
vt.metadata.file_type == vt.FileType.DOCX or
vt.metadata.file_type == vt.FileType.RTF
)
// Different TA spotted using .ru TLD (excluding it for now)
and not (
for any url in vt.behaviour.memory_pattern_urls : (
url contains ".ru"
)
)
and vt.metadata.new_file
}
/*
Sidewinder related malicious documents exploiting CVE 2017-0199 used during 2025 campaign
*/
import "vt"
rule apt_sidewinder_documents
{
meta:
author = "Acronis Threat Research Unit (TRU)"
description = "Sidewinder related malicious documents exploiting CVE 2017-0199"
distribution = "TLP:CLEAR"
version = "1.0"
strings:
$a1 = {62544CB1F0B9E6E04433698E85BFB534278B9BDC5F06589C011E9CB80C71DF23}
$a2 = {E20F76CDABDFAB004A6BA632F20CE00512BA5AD2FE8FB6ED9EE1865DFD07504B0304140000}
condition:
filesize < 5000KB
and any of ($a*)
and vt.metadata.new_file
// Getting spammy samples from a CN submitter
and not vt.metadata.submitter.country == "CN"
}
<!--
This YARA rule detects potentially malicious SVG files that are likely being used for crimeware campaigns targeting Colombia.
The rule identifies SVG images that contain legal or judicial terms commonly used in phishing scams,
along with embedded external links that could be used to deliver a payload.
-->
import "vt"
rule crimeware_svg_colombia {
meta:
author = "Acronis Threat Research Unit (TRU)"
description = "Detects potentially malicious SVG files that are likely being used for crimeware campaigns targeting Colombia"
distribution = "TLP:CLEAR"
version = "1.1"
// Reference hashes
hash1 = "6d4a53da259c3c8c0903b1345efcf2fa0d50bc10c3c010a34f86263de466f5a1"
hash2 = "2aae8e206dd068135b16ff87dfbb816053fc247a222aad0d34c9227e6ecf7b5b"
hash3 = "4cfeab122e0a748c8600ccd14a186292f27a93b5ba74c58dfee838fe28765061"
hash4 = "9bbbcb6eae33314b84f5e367f90e57f487d6abe72d6067adcb66eba896d7ce33"
hash5 = "60e87c0fe7c3904935bb1604bdb0b0fc0f2919db64f72666b77405c2c1e46067"
hash6 = "609edc93e075223c5dc8caaf076bf4e28f81c5c6e4db0eb6f502dda91500aab4"
hash7 = "4795d3a3e776baf485d284a9edcf1beef29da42cad8e8261a83e86d35b25cafe"
hash8 = "5673ad3287bcc0c8746ab6cab6b5e1b60160f07c7b16c018efa56bffd44b37aa"
hash9 = "b3e8ab81d0a559a373c3fe2ae7c3c99718503411cc13b17cffd1eee2544a787b"
hash10 = "b5311cadc0bbd2f47549f7fc0895848adb20cc016387cebcd1c29d784779240c"
hash11 = "c3319a8863d5e2dc525dfe6669c5b720fc42c96a8dce3bd7f6a0072569933303"
hash12 = "cb035f440f728395cc4237e1ac52114641dc25619705b605713ecefb6fd9e563"
hash13 = "cf23f7b98abddf1b36552b55f874ae1e2199768d7cefb0188af9ee0d9a698107"
hash14 = "f3208ae62655435186e560378db58e133a68aa6107948e2a8ec30682983aa503"
strings:
// SVG
$svg = "<svg xmlns=" ascii fullword
// Documents containing legal or judicial terms
$s1 = "COPIA" nocase
$s2 = "CITACION" nocase
$s3 = "JUZGADO" nocase
$s4 = "PENAL" nocase
$s5 = "JUDICIAL" nocase
$s6 = "BOGOTA" nocase
$s7 = "DEMANDA" nocase
// When image loads it retrieves payload from external website using HTTPS
$href1= "href='https://" nocase
$href2 = "href=\"https://" nocase
condition:
$svg
and filesize < 3MB
and 3 of ($s*)
and any of ($href*)
and vt.metadata.submitter.country == "CO"
}
rule crimeware_shadow_vector_svg
{
meta:
description = "Detects malicious SVG files associated with Shadow
Vector's Colombian campaign"
author = "Acronis Threat Research Unit (TRU)"
file_type = "SVG"
malware_family = "Shadow Vector"
threat_category = "Crimeware / Malicious Image / Embedded Payload"
tlp = "TLP:CLEAR"
strings:
$svg_tag1 = "<?xml" ascii
$svg_tag2 = "<svg" ascii
$svg_tag3 = "<!DOCTYPE svg" ascii
$svg_tag4 = "http://www.w3.org/2000/svg" ascii
//used by Shadow Vector (possibly generated in batch)
$judicial = "juzgado" ascii nocase
$judicial_1 = "citacion" ascii nocase
$judicial_2 = "judicial" ascii nocase
$judicial_3 = "despacho" ascii nocase
$generado = "Generado" ascii nocase
condition:
filesize < 3MB and
3 of ($svg_tag*) and
(1 of ($judicial*) and $generado)
}
import "vt"
rule ClickFix
{
strings:
$clipboard = /(navigator\.clipboard\.writeText|document\.execCommand\(\"copy\"\))/
$pay01 = /(powershell|cmd|mshta|msiexec|pwsh)/gvfi
condition:
vt.net.url.new_url and
$clipboard and
any of ($pay*)
}
$pay03 = /powershell.{,80}iex/entity:url (content:"navigator.clipboard.writeText" or content:"document.execCommand(\"copy\")") (content:"String.fromCharCode" or content:"atob")
behavior:"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("
import "vt"
rule URLs_Downloading_Decoy_RTF_SideWinder {
meta:
target_entity = "url"
author = "Virustotal"
description = "This YARA rule identify new URLs downloading the decoy file related to SideWinder"
condition:
vt.net.url.downloaded_file.sha256 == "1955c6914097477d5141f720c9e8fa44b4fe189e854da298d85090cbc338b35a"
and vt.net.url.new_url
} !pip install vt-py nest_asyncio
import getpass, vt, json, nest_asyncio
nest_asyncio.apply()
cli = vt.Client(getpass.getpass('Introduce your VirusTotal API key: '))
FILEHASH = "1955c6914097477d5141f720c9e8fa44b4fe189e854da298d85090cbc338b35a"
RELATIONS = "itw_urls"
all_itw_urls = []
async for itemobj in cli.iterator(f'/files/{FILEHASH}/{RELATIONS}', limit=0):
all_itw_urls.append(itemobj.to_dict())
/*
Checks if the file is tagged with CVE-2017-0199 or CVE-2017-11882
and originates from one of the targeted countries
and the file type is a Word document, RTF, or MS-Office file
*/
import "vt"
rule hunting_cve_maldocs {
meta:
author = "Acronis Threat Research Unit (TRU)"
description = "Hunting for malicious Word/RTF files exploiting CVE-2017-0199 or CVE-2017-11882 from specific countries"
distribution = "TLP:CLEAR"
version = "1.2"
condition:
// Match if the file has CVE-2017-0199 or CVE-2017-11882 in the tags
for any tag in vt.metadata.tags :
(
tag == "cve-2017-0199" or
tag == "cve-2017-11882"
)
// Originates from a specific country?
and
(
// Removed CN due to spam submissions of related maldocs
vt.metadata.submitter.country == "PK" or
vt.metadata.submitter.country == "LK" or
vt.metadata.submitter.country == "BD" or
vt.metadata.submitter.country == "NP" or
vt.metadata.submitter.country == "MM" or
vt.metadata.submitter.country == "MV" or
vt.metadata.submitter.country == "AF"
)
// Is it a DOC, DOCX, or RTF?
and
(
vt.metadata.file_type == vt.FileType.DOC or
vt.metadata.file_type == vt.FileType.DOCX or
vt.metadata.file_type == vt.FileType.RTF
)
// Different TA spotted using .ru TLD (excluding it for now)
and not (
for any url in vt.behaviour.memory_pattern_urls : (
url contains ".ru"
)
)
and vt.metadata.new_file
}
/*
Sidewinder related malicious documents exploiting CVE 2017-0199 used during 2025 campaign
*/
import "vt"
rule apt_sidewinder_documents
{
meta:
author = "Acronis Threat Research Unit (TRU)"
description = "Sidewinder related malicious documents exploiting CVE 2017-0199"
distribution = "TLP:CLEAR"
version = "1.0"
strings:
$a1 = {62544CB1F0B9E6E04433698E85BFB534278B9BDC5F06589C011E9CB80C71DF23}
$a2 = {E20F76CDABDFAB004A6BA632F20CE00512BA5AD2FE8FB6ED9EE1865DFD07504B0304140000}
condition:
filesize < 5000KB
and any of ($a*)
and vt.metadata.new_file
// Getting spammy samples from a CN submitter
and not vt.metadata.submitter.country == "CN"
}
<!--
This YARA rule detects potentially malicious SVG files that are likely being used for crimeware campaigns targeting Colombia.
The rule identifies SVG images that contain legal or judicial terms commonly used in phishing scams,
along with embedded external links that could be used to deliver a payload.
-->
import "vt"
rule crimeware_svg_colombia {
meta:
author = "Acronis Threat Research Unit (TRU)"
description = "Detects potentially malicious SVG files that are likely being used for crimeware campaigns targeting Colombia"
distribution = "TLP:CLEAR"
version = "1.1"
// Reference hashes
hash1 = "6d4a53da259c3c8c0903b1345efcf2fa0d50bc10c3c010a34f86263de466f5a1"
hash2 = "2aae8e206dd068135b16ff87dfbb816053fc247a222aad0d34c9227e6ecf7b5b"
hash3 = "4cfeab122e0a748c8600ccd14a186292f27a93b5ba74c58dfee838fe28765061"
hash4 = "9bbbcb6eae33314b84f5e367f90e57f487d6abe72d6067adcb66eba896d7ce33"
hash5 = "60e87c0fe7c3904935bb1604bdb0b0fc0f2919db64f72666b77405c2c1e46067"
hash6 = "609edc93e075223c5dc8caaf076bf4e28f81c5c6e4db0eb6f502dda91500aab4"
hash7 = "4795d3a3e776baf485d284a9edcf1beef29da42cad8e8261a83e86d35b25cafe"
hash8 = "5673ad3287bcc0c8746ab6cab6b5e1b60160f07c7b16c018efa56bffd44b37aa"
hash9 = "b3e8ab81d0a559a373c3fe2ae7c3c99718503411cc13b17cffd1eee2544a787b"
hash10 = "b5311cadc0bbd2f47549f7fc0895848adb20cc016387cebcd1c29d784779240c"
hash11 = "c3319a8863d5e2dc525dfe6669c5b720fc42c96a8dce3bd7f6a0072569933303"
hash12 = "cb035f440f728395cc4237e1ac52114641dc25619705b605713ecefb6fd9e563"
hash13 = "cf23f7b98abddf1b36552b55f874ae1e2199768d7cefb0188af9ee0d9a698107"
hash14 = "f3208ae62655435186e560378db58e133a68aa6107948e2a8ec30682983aa503"
strings:
// SVG
$svg = "<svg xmlns=" ascii fullword
// Documents containing legal or judicial terms
$s1 = "COPIA" nocase
$s2 = "CITACION" nocase
$s3 = "JUZGADO" nocase
$s4 = "PENAL" nocase
$s5 = "JUDICIAL" nocase
$s6 = "BOGOTA" nocase
$s7 = "DEMANDA" nocase
// When image loads it retrieves payload from external website using HTTPS
$href1= "href='https://" nocase
$href2 = "href=\"https://" nocase
condition:
$svg
and filesize < 3MB
and 3 of ($s*)
and any of ($href*)
and vt.metadata.submitter.country == "CO"
}
rule crimeware_shadow_vector_svg
{
meta:
description = "Detects malicious SVG files associated with Shadow
Vector's Colombian campaign"
author = "Acronis Threat Research Unit (TRU)"
file_type = "SVG"
malware_family = "Shadow Vector"
threat_category = "Crimeware / Malicious Image / Embedded Payload"
tlp = "TLP:CLEAR"
strings:
$svg_tag1 = "<?xml" ascii
$svg_tag2 = "<svg" ascii
$svg_tag3 = "<!DOCTYPE svg" ascii
$svg_tag4 = "http://www.w3.org/2000/svg" ascii
//used by Shadow Vector (possibly generated in batch)
$judicial = "juzgado" ascii nocase
$judicial_1 = "citacion" ascii nocase
$judicial_2 = "judicial" ascii nocase
$judicial_3 = "despacho" ascii nocase
$generado = "Generado" ascii nocase
condition:
filesize < 3MB and
3 of ($svg_tag*) and
(1 of ($judicial*) and $generado)
}
import "vt"
rule ClickFix
{
strings:
$clipboard = /(navigator\.clipboard\.writeText|document\.execCommand\(\"copy\"\))/
$pay01 = /(powershell|cmd|mshta|msiexec|pwsh)/gvfi
condition:
vt.net.url.new_url and
$clipboard and
any of ($pay*)
}
$pay03 = /powershell.{,80}iex/entity:url (content:"navigator.clipboard.writeText" or content:"document.execCommand(\"copy\")") (content:"String.fromCharCode" or content:"atob")
behavior:"[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("
import "vt"
rule URLs_Downloading_Decoy_RTF_SideWinder {
meta:
target_entity = "url"
author = "Virustotal"
description = "This YARA rule identify new URLs downloading the decoy file related to SideWinder"
condition:
vt.net.url.downloaded_file.sha256 == "1955c6914097477d5141f720c9e8fa44b4fe189e854da298d85090cbc338b35a"
and vt.net.url.new_url
} !pip install vt-py nest_asyncio
import getpass, vt, json, nest_asyncio
nest_asyncio.apply()
cli = vt.Client(getpass.getpass('Introduce your VirusTotal API key: '))
FILEHASH = "1955c6914097477d5141f720c9e8fa44b4fe189e854da298d85090cbc338b35a"
RELATIONS = "itw_urls"
all_itw_urls = []
async for itemobj in cli.iterator(f'/files/{FILEHASH}/{RELATIONS}', limit=0):
all_itw_urls.append(itemobj.to_dict())
malware_config:30819f300d06092a864886f70d010101050003818d003081890281810096cc4e6ad9aee91ca69b7b44465e17412626a11c7855b7a69daad00f48c0ea98f0e389a0a1c4b74332bf0d603a6e53e05ee734c9a289ff172204bfc9430ed4d6041402d02b526e902b95f6f219598cb1b6391403fa627ab36dbe88646620369e7ec89bdc31f1a2b0bedba1852d5e7656d3b297f9d39f357816f0677563bc496b020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
type:zip AND (metadata:"lnk" AND metadata:".vbs" AND metadata:".pdf") and submitter:HK
Looking at the usage of encoded Telegram Bot based payload inside the C++ implant. Using either content or malware_config modifiers when extracted from the config could help us to identify new samples.
Spawning Powershell.exe LOLBIN.
VT search enablers for checking for malicious email files, if uploaded from Central Asian Geosphere.
ISO-oriented first-stagers.
Multiple behavioral overlaps between YoroTrooper & Silent Lynx and further hunting hypothesis developed by us.
malware_config:30819f300d06092a864886f70d010101050003818d003081890281810096cc4e6ad9aee91ca69b7b44465e17412626a11c7855b7a69daad00f48c0ea98f0e389a0a1c4b74332bf0d603a6e53e05ee734c9a289ff172204bfc9430ed4d6041402d02b526e902b95f6f219598cb1b6391403fa627ab36dbe88646620369e7ec89bdc31f1a2b0bedba1852d5e7656d3b297f9d39f357816f0677563bc496b020301000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
type:zip AND (metadata:"lnk" AND metadata:".vbs" AND metadata:".pdf") and submitter:HK
Looking at the usage of encoded Telegram Bot based payload inside the C++ implant. Using either content or malware_config modifiers when extracted from the config could help us to identify new samples.
Spawning Powershell.exe LOLBIN.
VT search enablers for checking for malicious email files, if uploaded from Central Asian Geosphere.
ISO-oriented first-stagers.
Multiple behavioral overlaps between YoroTrooper & Silent Lynx and further hunting hypothesis developed by us.
Last week, we were fortunate enough to attend the fantastic LABScon conference, organized by the SentinelOne Labs team. While there, we presented a workshop titled 'Advanced Threat Hunting: Automating Large-Scale Operations with LLMs.' The main goal of this workshop was to show attendees how they could automate their research using the VirusTotal API and Gemini. Specifically, we demonstrated how to integrate the power of Google Colab to quickly and efficiently generate Jupyter notebooks using natural language.
It goes without saying that the use of LLMs is a must for every analyst today. For this reason, we also want to make life easier for everyone who uses the VirusTotal API for research.
The VirusTotal API is the programmatic gateway to our massive repository of threat intelligence data. While the VirusTotal GUI is great for agile querying, the API unlocks the ability to conduct large-scale, automated investigations and access raw data with more pivoting opportunities.
To make interacting with the API even easier, we recommend using the vt-py library. It simplifies much of the complexity of HTTP requests, JSON parsing, and rate limit management, making it the go-to choice for Python users.
To bridge the gap between human questions and API queries, we can leverage the integrated Gemini in Google Colab. We have created a "meta Colab" notebook that is pre-populated with working real code snippets for interacting with the VirusTotal API to retrieve different information such as campaigns, threat actors, malware, samples, URLs among others (which we will share soon). This provides Gemini with the necessary context to understand your natural language requests and generate accurate Python code to query the VirusTotal API. Gemini doesn't call the API directly; it creates the code snippet for you to execute.
For Gemini to generate accurate and relevant code, it needs context. Our meta Colab notebook is filled with examples that act as a guide. For complex questions, it will be nice to provide the exact field names that you want to work with. This context generally falls into two categories:
Example of code snippet context that we have included in our meta colab:
query_results_with_behaviors = []
query = "have:sigma have:yara have:ids have:malware_config fs:1d+ have:bundled_file tag:overlay"
RELATIONS = "behaviours"
async for itemobj in cli.iterator('/intelligence/search',params={'query': query, 'relationships': RELATIONS, 'relationship_attributes[%s]'%(RELATIONS): '\*'},limit=0):
query_results_with_behaviors.append(itemobj.to_dict())
res_with_behaviors = list(query_results_with_behaviors)
One of the exercises in our workshop focused on analyzing malicious LNK files submitted to VirusTotal in a specific period of time to limit results. The goal was to discover common execution techniques and interesting command-line patterns.
Here’s how you could approach this with natural language queries in our meta Colab:
You can start by asking Gemini:
Create a code snippet to retrieve all LNK files submitted from January 1st, 2025, until April 1st, 2025, with 5 or more positives.
Code generated:
query_results = []
# Query for LNK files submitted between January 1st, 2025, and April 1st, 2025, with 5 or more positives.
query = "fs:2025-01-01+ fs:2025-04-01- p:5+ type:lnk"
async for itemobj in cli.iterator('/intelligence/search',params={'query': "%s"%(query)},limit=0):
query_results.append(itemobj.to_dict())
lnk_files = list(query_results)
print(f"Found {len(lnk_files)} LNK files matching the criteria.")
Next, you can ask Gemini to process the retrieved data and create visualizations:
Flatten the data in a dataframe and create a bar chart depicting the most common TargetFileDOSName values.
Code generated:
import pandas as pd
import plotly.express as px
# Extract the 'attributes' dictionary from each object in our results
attributes_list = [result.get('attributes', {}) for result in lnk_files]
# Use json_normalize to create a flat DataFrame
df_flat = pd.json_normalize(attributes_list)
# Check if 'exiftool.TargetFileDOSName' column exists and is not empty
if 'exiftool.TargetFileDOSName' in df_flat.columns and not df_flat['exiftool.TargetFileDOSName'].empty:
# Count the occurrences of each TargetFileDOSName
target_file_counts = df_flat['exiftool.TargetFileDOSName'].value_counts().reset_index()
target_file_counts.columns = ['TargetFileDOSName', 'Count']
# Get the top 10 most common TargetFileDOSName values for visualization
top_target_files = target_file_counts.head(10)
# Create an interactive bar chart
fig = px.bar(top_target_files,
x='Count',
y='TargetFileDOSName',
orientation='h',
title='Top 10 Most Common TargetFileDOSName in LNK files',
labels={'Count': 'Number of Occurrences', 'TargetFileDOSName': 'Target File DOS Name'})
fig.show()
else:
print("The 'exiftool.TargetFileDOSName' column was not found or is empty in the flattened data.")
print("DataFrame shape:", df_flat.shape)
df_flat.head()
This will generate a code snippet using pandas and Plotly to give you a clear view of the most frequent target files in the malicious LNKs.
To dig deeper and understand the relationships between the infected machines and the malware, you can ask for a more advanced visualization:
Create a Sankey diagram connecting MachineID (source) to TargetFileDOSName (target), with link widths representing the number of occurrences. Include only MachineID values with 10 or more occurrences, grouping the rest as "Other", and make the visualization interactive with hover details.
Code generated:
import plotly.graph_objects as go
import pandas as pd
# Ensure df_flat is available from previous steps
# If not, you might need to re-run the cell that creates df_flat.
# Check if necessary columns exist in df_flat
if 'lnk_info.machine_id' in df_flat.columns and 'exiftool.TargetFileDOSName' in df_flat.columns:
# Calculate the frequency of each machine ID and target file name pair
pair_frequencies = df_flat.groupby(['lnk_info.machine_id', 'exiftool.TargetFileDOSName']).size().reset_index(name='frequency')
# Identify MachineIDs with less than 10 occurrences
machine_id_counts = pair_frequencies.groupby('lnk_info.machine_id')['frequency'].sum().reset_index(name='count')
other_machine_ids = machine_id_counts[machine_id_counts['count'] < 10]['lnk_info.machine_id'].tolist()
# Replace infrequent MachineIDs with 'Other'
pair_frequencies['source_node'] = pair_frequencies['lnk_info.machine_id'].apply(lambda x: 'Other' if x in other_machine_ids else x)
# Aggregate frequencies for the 'Other' node and other valid nodes
sankey_data = pair_frequencies.groupby(['source_node', 'exiftool.TargetFileDOSName'])['frequency'].sum().reset_index()
# Create unique labels for the Sankey nodes
all_nodes = pd.concat([sankey_data['source_node'], sankey_data['exiftool.TargetFileDOSName']]).unique()
label_to_index = {label: i for i, label in enumerate(all_nodes)}
# Create the Sankey diagram
fig = go.Figure(data=[go.Sankey(
node=dict(
pad=15,
thickness=20,
line=dict(color="black", width=0.5),
label=all_nodes,
color="blue"
),
link=dict(
source=sankey_data['source_node'].map(label_to_index),
target=sankey_data['exiftool.TargetFileDOSName'].map(label_to_index),
value=sankey_data['frequency'],
label=sankey_data.apply(lambda row: f"{row['source_node']} -> {row['exiftool.TargetFileDOSName']}: {row['frequency']}", axis=1)
)
)])
fig.update_layout(title_text="MachineID to TargetFileDOSName Sankey Diagram (Infrequent MachineIDs grouped as 'Other')", font_size=10)
fig.show()
else:
print("Required columns 'lnk_info.machine_id' or 'exiftool.TargetFileDOSName' not found in the DataFrame.")
This will create a powerful visualization that shows how different machines are being targeted with specific files, allowing us identify patterns for each machineID metadata.
Finally, you can investigate the behavior of the LNK files themselves, for example, by looking at how they are executed:
Create a pie chart depicting the distribution of window behaviors for LNK target processes (hidden, minimized,...).
Code generated:
import plotly.express as px
import pandas as pd
# Check if the relevant column exists
if 'lnk_info.header.show_window_str' in df_flat.columns and not df_flat['lnk_info.header.show_window_str'].empty:
# Count the occurrences of each window behavior string
window_behavior_counts = df_flat['lnk_info.header.show_window_str'].value_counts().reset_index()
window_behavior_counts.columns = ['Window Behavior', 'Count']
# Create an interactive pie chart
fig = px.pie(window_behavior_counts,
names='Window Behavior',
values='Count',
title='Distribution of LNK Target Process Window Behaviors',
hover_data={'Count': True})
fig.show()
else:
print("The 'lnk_info.header.show_window_str' column was not found or is empty in the flattened data. Cannot create the pie chart.")
This allows you to quickly identify if the LNK files are trying to hide their execution, a common use case for malware.
Understanding the geographical distribution of malware submissions can provide crucial insights into whether a campaign is widespread or targeting a specific region. By analyzing the submission metadata for our set of LNK files, an analyst can quickly identify potential hotspots, which could indicate a geographically focused attack. This is achieved by fetching the submissions relationship for each file, extracting the country of origin for each submission, and plotting this data on a world map (please note that submissions doesn’t mean targeted countries, but in some cases could be related).
Using the LNK files identified previously, create a code snippet that retrieves the submissions relationship for each file. Then, count the number of submissions from each country and display the results on a choropleth world map to visualize the submission hotspots.
In this case, Gemini uses the step-by-step execution, which basically is a set of consecutive executions. The code generated was:
query_results_with_submissions = []
# Define the search query string for LNK files
query = "fs:2025-01-01+ fs:2025-04-01- p:5+ type:lnk"
# Define the relationship to request
RELATIONS = "submissions"
# Define the relationship attributes to retrieve (all attributes)
ATTRIBUTES_RELATIONS = "*"
# Use cli.iterator to perform an intelligence search with the specified query, relationships, and relationship attributes.
async for itemobj in cli.iterator('/intelligence/search', params={'query': query, 'relationships': RELATIONS, 'relationship_attributes[%s]'%(RELATIONS): ATTRIBUTES_RELATIONS}, limit=0):
query_results_with_submissions.append(itemobj.to_dict())
# Convert query_results_with_submissions to a list called lnk_files_with_submissions
lnk_files_with_submissions = list(query_results_with_submissions)
# Print the number of LNK files found with submission data.
print(f"Found {len(lnk_files_with_submissions)} LNK files with submission data matching the criteria.")
import pandas as pd
# Initialize an empty list to store submission countries
submission_countries = []
# Iterate through each item (LNK file) in the lnk_files_with_submissions list
for item in lnk_files_with_submissions:
# Check if 'relationships' and 'submissions' exist and are not empty
if 'relationships' in item and 'submissions' in item['relationships'] and item['relationships']['submissions']['data']:
# Iterate through each submission object
for submission in item['relationships']['submissions']['data']:
# Extract the 'country' from 'submission['attributes']' and append it to the list
if 'country' in submission['attributes']:
submission_countries.append(submission['attributes']['country'])
# Convert the submission_countries list into a pandas Series
submission_countries_series = pd.Series(submission_countries)
# Count the occurrences of each country and store in a DataFrame
country_counts = submission_countries_series.value_counts().reset_index()
country_counts.columns = ['country', 'count']
print(f"Total unique countries found: {len(country_counts)}")
print("Top 5 submission countries:")
print(country_counts.head())
!pip install pycountry
import plotly.express as px
import pandas as pd
import pycountry
# Function to get ISO-3 code from country name
def get_iso3(country_name):
try:
return pycountry.countries.search_fuzzy(country_name)[0].alpha_3
except:
return None
# Apply the function to get ISO-3 codes
country_counts['iso_alpha'] = country_counts['country'].apply(get_iso3)
# Create a world heatmap using Plotly Express with ISO-3 codes
fig = px.choropleth(country_counts.dropna(subset=['iso_alpha']), # Drop rows where ISO code couldn't be found
locations="iso_alpha", # Use ISO-3 codes for locations
locationmode='ISO-3', # Specify ISO-3 location mode
color="count",
hover_name="country",
color_continuous_scale="Viridis",
title="Submission Country Heatmap")
# Update layout to increase figure size
fig.update_layout(
autosize=False,
width=1000, # Adjust width as needed
height=600 # Adjust height as needed
)
fig.show()
Here are some other examples of how you can use natural language to query the VirusTotal API:
This specific question is actually a really good example of how Google Colab will run the step-by-step process. As you can see, we asked different questions in the same prompt, for that reason Gemini will do it in different steps.
Retrieve all the samples from the /intelligence/search endpoint with the following query: fs:2025-08-01+ fs:2025-08-14- p:5+ tag:crx have:codeinsight. Get the bundled_files and create a new dataframe with them too, but store only those having 5 or more malicious value. Then identify the top 5 magika of those bundled files obtained
Code generated:
query_results_with_bundled_files = []
# Define the search query string
query = "fs:2025-08-01+ fs:2025-08-14- p:5+ tag:crx have:codeinsight"
# Define the relationship to request
RELATIONS = "bundled_files"
# Define the relationship attributes to retrieve (all attributes)
ATTRIBUTES_RELATIONS = "*"
# Use cli.iterator to perform an intelligence search with the specified query, relationships, and relationship attributes.
async for itemobj in cli.iterator('/intelligence/search', params={'query': query, 'relationships': RELATIONS, 'relationship_attributes[%s]'%(RELATIONS): ATTRIBUTES_RELATIONS}, limit=0):
query_results_with_bundled_files.append(itemobj.to_dict())
# Convert query_results_with_bundled_files to a list called crx_files_with_bundled_files
crx_files_with_bundled_files = list(query_results_with_bundled_files)
# Print the number of found CRX files with bundled file data.
print(f"Found {len(crx_files_with_bundled_files)} CRX files with bundled file data matching the criteria.")
import pandas as pd
# List to store all bundled file attributes
all_bundled_files_data = []
# Iterate through each CRX file with bundled file data
for crx_file in crx_files_with_bundled_files:
if 'relationships' in crx_file and 'bundled_files' in crx_file['relationships']:
for bundled_file in crx_file['relationships']['bundled_files']['data']:
all_bundled_files_data.append(bundled_file.get('attributes', {}))
# Create a DataFrame from the extracted bundled file attributes
df_bundled_files = pd.json_normalize(all_bundled_files_data)
# Filter for bundled files with 5 or more malicious detections
df_malicious_bundled_files = df_bundled_files[df_bundled_files['last_analysis_stats.malicious'] >= 5]
print(f"Total bundled files extracted: {len(df_bundled_files)}")
print(f"Bundled files with 5 or more malicious detections: {len(df_malicious_bundled_files)}")
df_malicious_bundled_files.head()
import pandas as pd
import plotly.express as px
# Check if the 'magika' column exists and is not empty in the filtered DataFrame
if 'magika' in df_malicious_bundled_files.columns and not df_malicious_bundled_files['magika'].empty:
# Count the occurrences of each magika type
magika_counts = df_malicious_bundled_files['magika'].value_counts().reset_index()
magika_counts.columns = ['Magika Type', 'Count']
# Get the top 5 most frequent magika types
top_5_magika = magika_counts.head(5)
print("Top 5 Magika Types in malicious bundled files:")
print(top_5_magika)
# Visualize the top 5 magika types
fig = px.bar(top_5_magika,
x='Count',
y='Magika Type',
orientation='h',
title='Top 5 Magika Types in Malicious Bundled Files',
labels={'Count': 'Number of Occurrences', 'Magika Type': 'Magika Type'})
fig.update_layout(yaxis={'categoryorder':'total ascending'}) # Order bars by count
fig.show()
else:
print("The 'magika' column was not found or is empty in the filtered malicious bundled files DataFrame. Cannot identify top magika types.")
Retrieve threat actors targeting the United Kingdom with an espionage motivation. Sort the results in descending order of relevance. Display the total number of threat actors and their names.
Retrieve information about threat actors and malware involved in campaigns targeting Pakistan. For each threat actor, retrieve its country of origin, motivations, and targeted industries. For each malware, retrieve its name.
This workshop, co-authored with Aleksandar from Sentinel LABS, will be presented at future conferences to show the community how to get the most out of the VirusTotal API. We'll be updating the content of our meta colab regularly and will share more information soon about how to get the Google Colab.
In the meantime, if you have any feedback or ideas to contribute, we are open to suggestions.
Last week, we were fortunate enough to attend the fantastic LABScon conference, organized by the SentinelOne Labs team. While there, we presented a workshop titled 'Advanced Threat Hunting: Automating Large-Scale Operations with LLMs.' The main goal of this workshop was to show attendees how they could automate their research using the VirusTotal API and Gemini. Specifically, we demonstrated how to integrate the power of Google Colab to quickly and efficiently generate Jupyter notebooks using natural language.
It goes without saying that the use of LLMs is a must for every analyst today. For this reason, we also want to make life easier for everyone who uses the VirusTotal API for research.
The VirusTotal API is the programmatic gateway to our massive repository of threat intelligence data. While the VirusTotal GUI is great for agile querying, the API unlocks the ability to conduct large-scale, automated investigations and access raw data with more pivoting opportunities.
To make interacting with the API even easier, we recommend using the vt-py library. It simplifies much of the complexity of HTTP requests, JSON parsing, and rate limit management, making it the go-to choice for Python users.
To bridge the gap between human questions and API queries, we can leverage the integrated Gemini in Google Colab. We have created a "meta Colab" notebook that is pre-populated with working real code snippets for interacting with the VirusTotal API to retrieve different information such as campaigns, threat actors, malware, samples, URLs among others (which we will share soon). This provides Gemini with the necessary context to understand your natural language requests and generate accurate Python code to query the VirusTotal API. Gemini doesn't call the API directly; it creates the code snippet for you to execute.
For Gemini to generate accurate and relevant code, it needs context. Our meta Colab notebook is filled with examples that act as a guide. For complex questions, it will be nice to provide the exact field names that you want to work with. This context generally falls into two categories:
Example of code snippet context that we have included in our meta colab:
query_results_with_behaviors = []
query = "have:sigma have:yara have:ids have:malware_config fs:1d+ have:bundled_file tag:overlay"
RELATIONS = "behaviours"
async for itemobj in cli.iterator('/intelligence/search',params={'query': query, 'relationships': RELATIONS, 'relationship_attributes[%s]'%(RELATIONS): '\*'},limit=0):
query_results_with_behaviors.append(itemobj.to_dict())
res_with_behaviors = list(query_results_with_behaviors)
One of the exercises in our workshop focused on analyzing malicious LNK files submitted to VirusTotal in a specific period of time to limit results. The goal was to discover common execution techniques and interesting command-line patterns.
Here’s how you could approach this with natural language queries in our meta Colab:
You can start by asking Gemini:
Create a code snippet to retrieve all LNK files submitted from January 1st, 2025, until April 1st, 2025, with 5 or more positives.
Code generated:
query_results = []
# Query for LNK files submitted between January 1st, 2025, and April 1st, 2025, with 5 or more positives.
query = "fs:2025-01-01+ fs:2025-04-01- p:5+ type:lnk"
async for itemobj in cli.iterator('/intelligence/search',params={'query': "%s"%(query)},limit=0):
query_results.append(itemobj.to_dict())
lnk_files = list(query_results)
print(f"Found {len(lnk_files)} LNK files matching the criteria.")
Next, you can ask Gemini to process the retrieved data and create visualizations:
Flatten the data in a dataframe and create a bar chart depicting the most common TargetFileDOSName values.
Code generated:
import pandas as pd
import plotly.express as px
# Extract the 'attributes' dictionary from each object in our results
attributes_list = [result.get('attributes', {}) for result in lnk_files]
# Use json_normalize to create a flat DataFrame
df_flat = pd.json_normalize(attributes_list)
# Check if 'exiftool.TargetFileDOSName' column exists and is not empty
if 'exiftool.TargetFileDOSName' in df_flat.columns and not df_flat['exiftool.TargetFileDOSName'].empty:
# Count the occurrences of each TargetFileDOSName
target_file_counts = df_flat['exiftool.TargetFileDOSName'].value_counts().reset_index()
target_file_counts.columns = ['TargetFileDOSName', 'Count']
# Get the top 10 most common TargetFileDOSName values for visualization
top_target_files = target_file_counts.head(10)
# Create an interactive bar chart
fig = px.bar(top_target_files,
x='Count',
y='TargetFileDOSName',
orientation='h',
title='Top 10 Most Common TargetFileDOSName in LNK files',
labels={'Count': 'Number of Occurrences', 'TargetFileDOSName': 'Target File DOS Name'})
fig.show()
else:
print("The 'exiftool.TargetFileDOSName' column was not found or is empty in the flattened data.")
print("DataFrame shape:", df_flat.shape)
df_flat.head()
This will generate a code snippet using pandas and Plotly to give you a clear view of the most frequent target files in the malicious LNKs.
To dig deeper and understand the relationships between the infected machines and the malware, you can ask for a more advanced visualization:
Create a Sankey diagram connecting MachineID (source) to TargetFileDOSName (target), with link widths representing the number of occurrences. Include only MachineID values with 10 or more occurrences, grouping the rest as "Other", and make the visualization interactive with hover details.
Code generated:
import plotly.graph_objects as go
import pandas as pd
# Ensure df_flat is available from previous steps
# If not, you might need to re-run the cell that creates df_flat.
# Check if necessary columns exist in df_flat
if 'lnk_info.machine_id' in df_flat.columns and 'exiftool.TargetFileDOSName' in df_flat.columns:
# Calculate the frequency of each machine ID and target file name pair
pair_frequencies = df_flat.groupby(['lnk_info.machine_id', 'exiftool.TargetFileDOSName']).size().reset_index(name='frequency')
# Identify MachineIDs with less than 10 occurrences
machine_id_counts = pair_frequencies.groupby('lnk_info.machine_id')['frequency'].sum().reset_index(name='count')
other_machine_ids = machine_id_counts[machine_id_counts['count'] < 10]['lnk_info.machine_id'].tolist()
# Replace infrequent MachineIDs with 'Other'
pair_frequencies['source_node'] = pair_frequencies['lnk_info.machine_id'].apply(lambda x: 'Other' if x in other_machine_ids else x)
# Aggregate frequencies for the 'Other' node and other valid nodes
sankey_data = pair_frequencies.groupby(['source_node', 'exiftool.TargetFileDOSName'])['frequency'].sum().reset_index()
# Create unique labels for the Sankey nodes
all_nodes = pd.concat([sankey_data['source_node'], sankey_data['exiftool.TargetFileDOSName']]).unique()
label_to_index = {label: i for i, label in enumerate(all_nodes)}
# Create the Sankey diagram
fig = go.Figure(data=[go.Sankey(
node=dict(
pad=15,
thickness=20,
line=dict(color="black", width=0.5),
label=all_nodes,
color="blue"
),
link=dict(
source=sankey_data['source_node'].map(label_to_index),
target=sankey_data['exiftool.TargetFileDOSName'].map(label_to_index),
value=sankey_data['frequency'],
label=sankey_data.apply(lambda row: f"{row['source_node']} -> {row['exiftool.TargetFileDOSName']}: {row['frequency']}", axis=1)
)
)])
fig.update_layout(title_text="MachineID to TargetFileDOSName Sankey Diagram (Infrequent MachineIDs grouped as 'Other')", font_size=10)
fig.show()
else:
print("Required columns 'lnk_info.machine_id' or 'exiftool.TargetFileDOSName' not found in the DataFrame.")
This will create a powerful visualization that shows how different machines are being targeted with specific files, allowing us identify patterns for each machineID metadata.
Finally, you can investigate the behavior of the LNK files themselves, for example, by looking at how they are executed:
Create a pie chart depicting the distribution of window behaviors for LNK target processes (hidden, minimized,...).
Code generated:
import plotly.express as px
import pandas as pd
# Check if the relevant column exists
if 'lnk_info.header.show_window_str' in df_flat.columns and not df_flat['lnk_info.header.show_window_str'].empty:
# Count the occurrences of each window behavior string
window_behavior_counts = df_flat['lnk_info.header.show_window_str'].value_counts().reset_index()
window_behavior_counts.columns = ['Window Behavior', 'Count']
# Create an interactive pie chart
fig = px.pie(window_behavior_counts,
names='Window Behavior',
values='Count',
title='Distribution of LNK Target Process Window Behaviors',
hover_data={'Count': True})
fig.show()
else:
print("The 'lnk_info.header.show_window_str' column was not found or is empty in the flattened data. Cannot create the pie chart.")
This allows you to quickly identify if the LNK files are trying to hide their execution, a common use case for malware.
Understanding the geographical distribution of malware submissions can provide crucial insights into whether a campaign is widespread or targeting a specific region. By analyzing the submission metadata for our set of LNK files, an analyst can quickly identify potential hotspots, which could indicate a geographically focused attack. This is achieved by fetching the submissions relationship for each file, extracting the country of origin for each submission, and plotting this data on a world map (please note that submissions doesn’t mean targeted countries, but in some cases could be related).
Using the LNK files identified previously, create a code snippet that retrieves the submissions relationship for each file. Then, count the number of submissions from each country and display the results on a choropleth world map to visualize the submission hotspots.
In this case, Gemini uses the step-by-step execution, which basically is a set of consecutive executions. The code generated was:
query_results_with_submissions = []
# Define the search query string for LNK files
query = "fs:2025-01-01+ fs:2025-04-01- p:5+ type:lnk"
# Define the relationship to request
RELATIONS = "submissions"
# Define the relationship attributes to retrieve (all attributes)
ATTRIBUTES_RELATIONS = "*"
# Use cli.iterator to perform an intelligence search with the specified query, relationships, and relationship attributes.
async for itemobj in cli.iterator('/intelligence/search', params={'query': query, 'relationships': RELATIONS, 'relationship_attributes[%s]'%(RELATIONS): ATTRIBUTES_RELATIONS}, limit=0):
query_results_with_submissions.append(itemobj.to_dict())
# Convert query_results_with_submissions to a list called lnk_files_with_submissions
lnk_files_with_submissions = list(query_results_with_submissions)
# Print the number of LNK files found with submission data.
print(f"Found {len(lnk_files_with_submissions)} LNK files with submission data matching the criteria.")
import pandas as pd
# Initialize an empty list to store submission countries
submission_countries = []
# Iterate through each item (LNK file) in the lnk_files_with_submissions list
for item in lnk_files_with_submissions:
# Check if 'relationships' and 'submissions' exist and are not empty
if 'relationships' in item and 'submissions' in item['relationships'] and item['relationships']['submissions']['data']:
# Iterate through each submission object
for submission in item['relationships']['submissions']['data']:
# Extract the 'country' from 'submission['attributes']' and append it to the list
if 'country' in submission['attributes']:
submission_countries.append(submission['attributes']['country'])
# Convert the submission_countries list into a pandas Series
submission_countries_series = pd.Series(submission_countries)
# Count the occurrences of each country and store in a DataFrame
country_counts = submission_countries_series.value_counts().reset_index()
country_counts.columns = ['country', 'count']
print(f"Total unique countries found: {len(country_counts)}")
print("Top 5 submission countries:")
print(country_counts.head())
!pip install pycountry
import plotly.express as px
import pandas as pd
import pycountry
# Function to get ISO-3 code from country name
def get_iso3(country_name):
try:
return pycountry.countries.search_fuzzy(country_name)[0].alpha_3
except:
return None
# Apply the function to get ISO-3 codes
country_counts['iso_alpha'] = country_counts['country'].apply(get_iso3)
# Create a world heatmap using Plotly Express with ISO-3 codes
fig = px.choropleth(country_counts.dropna(subset=['iso_alpha']), # Drop rows where ISO code couldn't be found
locations="iso_alpha", # Use ISO-3 codes for locations
locationmode='ISO-3', # Specify ISO-3 location mode
color="count",
hover_name="country",
color_continuous_scale="Viridis",
title="Submission Country Heatmap")
# Update layout to increase figure size
fig.update_layout(
autosize=False,
width=1000, # Adjust width as needed
height=600 # Adjust height as needed
)
fig.show()
Here are some other examples of how you can use natural language to query the VirusTotal API:
This specific question is actually a really good example of how Google Colab will run the step-by-step process. As you can see, we asked different questions in the same prompt, for that reason Gemini will do it in different steps.
Retrieve all the samples from the /intelligence/search endpoint with the following query: fs:2025-08-01+ fs:2025-08-14- p:5+ tag:crx have:codeinsight. Get the bundled_files and create a new dataframe with them too, but store only those having 5 or more malicious value. Then identify the top 5 magika of those bundled files obtained
Code generated:
query_results_with_bundled_files = []
# Define the search query string
query = "fs:2025-08-01+ fs:2025-08-14- p:5+ tag:crx have:codeinsight"
# Define the relationship to request
RELATIONS = "bundled_files"
# Define the relationship attributes to retrieve (all attributes)
ATTRIBUTES_RELATIONS = "*"
# Use cli.iterator to perform an intelligence search with the specified query, relationships, and relationship attributes.
async for itemobj in cli.iterator('/intelligence/search', params={'query': query, 'relationships': RELATIONS, 'relationship_attributes[%s]'%(RELATIONS): ATTRIBUTES_RELATIONS}, limit=0):
query_results_with_bundled_files.append(itemobj.to_dict())
# Convert query_results_with_bundled_files to a list called crx_files_with_bundled_files
crx_files_with_bundled_files = list(query_results_with_bundled_files)
# Print the number of found CRX files with bundled file data.
print(f"Found {len(crx_files_with_bundled_files)} CRX files with bundled file data matching the criteria.")
import pandas as pd
# List to store all bundled file attributes
all_bundled_files_data = []
# Iterate through each CRX file with bundled file data
for crx_file in crx_files_with_bundled_files:
if 'relationships' in crx_file and 'bundled_files' in crx_file['relationships']:
for bundled_file in crx_file['relationships']['bundled_files']['data']:
all_bundled_files_data.append(bundled_file.get('attributes', {}))
# Create a DataFrame from the extracted bundled file attributes
df_bundled_files = pd.json_normalize(all_bundled_files_data)
# Filter for bundled files with 5 or more malicious detections
df_malicious_bundled_files = df_bundled_files[df_bundled_files['last_analysis_stats.malicious'] >= 5]
print(f"Total bundled files extracted: {len(df_bundled_files)}")
print(f"Bundled files with 5 or more malicious detections: {len(df_malicious_bundled_files)}")
df_malicious_bundled_files.head()
import pandas as pd
import plotly.express as px
# Check if the 'magika' column exists and is not empty in the filtered DataFrame
if 'magika' in df_malicious_bundled_files.columns and not df_malicious_bundled_files['magika'].empty:
# Count the occurrences of each magika type
magika_counts = df_malicious_bundled_files['magika'].value_counts().reset_index()
magika_counts.columns = ['Magika Type', 'Count']
# Get the top 5 most frequent magika types
top_5_magika = magika_counts.head(5)
print("Top 5 Magika Types in malicious bundled files:")
print(top_5_magika)
# Visualize the top 5 magika types
fig = px.bar(top_5_magika,
x='Count',
y='Magika Type',
orientation='h',
title='Top 5 Magika Types in Malicious Bundled Files',
labels={'Count': 'Number of Occurrences', 'Magika Type': 'Magika Type'})
fig.update_layout(yaxis={'categoryorder':'total ascending'}) # Order bars by count
fig.show()
else:
print("The 'magika' column was not found or is empty in the filtered malicious bundled files DataFrame. Cannot identify top magika types.")
Retrieve threat actors targeting the United Kingdom with an espionage motivation. Sort the results in descending order of relevance. Display the total number of threat actors and their names.
Retrieve information about threat actors and malware involved in campaigns targeting Pakistan. For each threat actor, retrieve its country of origin, motivations, and targeted industries. For each malware, retrieve its name.
This workshop, co-authored with Aleksandar from Sentinel LABS, will be presented at future conferences to show the community how to get the most out of the VirusTotal API. We'll be updating the content of our meta colab regularly and will share more information soon about how to get the Google Colab.
In the meantime, if you have any feedback or ideas to contribute, we are open to suggestions.

The Sentinels League is the official, week-by-week standings for the Threat Hunting World Championship – the first-of-its-kind tournament where the world’s top defenders go head-to-head across four surfaces: AI, Cloud, SIEM, and Endpoint. Thousands of blue teamers from more than 100 countries are tackling real-world attack scenarios to earn points, climb the tables, and secure their path to Las Vegas.
Bookmark this blog post to check your position, track the movement each week, and jump into the next qualifier if you’re not on the board yet.
Qualifiers run throughout the month of September across the four league tracks with players who finish in the top 50 in each league advancing to the Regional Finals on October 22 for the Americas, Europe, and Asia Pacific & Japan. From there, regional champions progress to the Grand Final at OneCon in Las Vegas from November 4 to 6, where the World Champion is crowned.
This is more than a game. It’s a global showdown that blends entertainment, education, and elite competition. Defenders everywhere will up-level their skills and battle for:
Only one player will take home the title, but everyone gains the experience of battling in real-world scenarios that sharpen the skills cyber defenders use daily.
These games are grounded in real incidents and operational trade-offs. Players earn points for flags captured and accuracy under time limits. This means pace and precision both matter. The tables below display each player’s alias, alongside points, and the prize they would receive should they finish in that same position.
Compete online from anywhere, or in-person at select events this month. Earn Threat Hunting Hero badges, prizes, and points that advance you up the league tables. Throughout September, players may enter once per qualifier and compete across all four tracks.
The top 200 players from each region (Americas, Europe, Asia Pacific & Japan) will face off live in an action-packed online event. Only three regional champions will advance.
Three finalists will earn an all-expenses-paid trip to OneCon 2025 in Las Vegas to compete live on stage for the World Championship title, the trophy, and the $100K prize pool.
Live table for the AI League Qualifiers are as follows. Top 50 on October 2 qualify for the Regional Finals.
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | Sean | 4800 | $2,000 + Entry |
| 2 | Gon | 4800 | $1,200 + Entry |
| 3 | Hyena | 4800 | $800 + Entry |
| 4 | 0xDariusNG | 4800 | $500 + Entry |
| 5 | PHEAKRO | 4780 | Entry |
| 6 | 0xKowloon | 4780 | Entry |
| 7 | Mingi | 4780 | $500 + Entry |
| 8 | injun | 4760 | $500 + Entry |
| 9 | cameronpaddyTL | 4740 | $500 + Entry |
| 10 | donghyeok | 4740 | $500 + Entry |
| 11 | Gowda | 4730 | Entry |
| 12 | kerostic | 4700 | Entry |
| 13 | Absol | 4700 | Entry |
| 14 | NotFound | 4700 | Entry |
| 15 | Jay | 4700 | Entry |
| 16 | Anonghost | 4700 | Entry |
| 17 | Siwoo | 4680 | Entry |
| 18 | qutypie | 4680 | Entry |
| 19 | AAA | 4680 | Entry |
| 20 | avynilite | 4680 | Entry |
| 21 | Shawn_Kwak | 4660 | Entry |
| 22 | ouoaaa | 4660 | Entry |
| 23 | N-dawg | 4660 | Entry |
| 24 | Johncena | 4660 | Entry |
| 25 | haon | 4660 | Entry |
| 26 | matrix | 4660 | Entry |
| 27 | meowfoobar | 4640 | Entry |
| 28 | bheda | 4640 | Entry |
| 29 | host | 4600 | Entry |
| 30 | weeknd | 4550 | Entry |
| 31 | davkjp | 4500 | Entry |
| 32 | ThreatAnalystX | 4500 | Entry |
| 33 | clerkofcourse | 4500 | Entry |
| 34 | Sujin | 4500 | Entry |
| 35 | heogi | 4400 | Entry |
| 36 | gwthm01 | 4400 | Entry |
| 37 | elesh27 | 4240 | Entry |
| 38 | 1-1063 | 4160 | Entry |
| 39 | mohan | 4150 | Entry |
| 40 | haysia-aml | 3980 | Entry |
| 41 | SmolAME | 3960 | Entry |
| 42 | riz_wan | 3920 | Entry |
| 43 | Ninja | 3860 | Entry |
| 44 | Paul-NZ | 3760 | Entry |
| 45 | dinnershow | 3700 | Entry |
| 46 | aaditya_khandke | 3680 | Entry |
| 47 | sanalk | 3660 | Entry |
| 48 | Gibbo | 3600 | Entry |
| 49 | Nisanak | 3520 | Entry |
| 50 | weeknd | 3460 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | ELL | 4800 | $2,000 + Entry |
| 2 | Andy | 4800 | $1,200 + Entry |
| 3 | Krzysztof | 4800 | Entry |
| 4 | christopher | 4800 | $500 + Entry |
| 5 | HermessNRJ | 4800 | $500 + Entry |
| 6 | jodie | 4800 | $500 + Entry |
| 7 | Arnau | 4800 | $500 + Entry |
| 8 | Fenio2 | 4800 | $500 + Entry |
| 9 | imouse | 4800 | Entry |
| 10 | TristanA | 4800 | $500 + Entry |
| 11 | SSman | 4800 | Entry |
| 12 | nicpooon | 4800 | Entry |
| 13 | goksara01 | 4800 | Entry |
| 14 | TomEdwards | 4800 | Entry |
| 15 | msnaydenov | 4800 | Entry |
| 16 | mrdiSec | 4800 | Entry |
| 17 | Kurty | 4800 | Entry |
| 18 | HackNSeek | 4780 | Entry |
| 19 | SEnev | 4780 | Entry |
| 20 | Plissken | 4780 | Entry |
| 21 | mka | 4780 | Entry |
| 22 | Ptikek | 4780 | Entry |
| 23 | Chris | 4780 | Entry |
| 24 | stahl | 4780 | Entry |
| 25 | D1vy | 4780 | Entry |
| 26 | alexcohen | 4780 | Entry |
| 27 | Krxsx | 4780 | Entry |
| 28 | hemalsoni22 | 4780 | Entry |
| 29 | bytesize | 4780 | Entry |
| 30 | manthan1501 | 4780 | Entry |
| 31 | buttercup6789 | 4780 | Entry |
| 32 | CBVirus | 4780 | Entry |
| 33 | Kamil7cd | 4760 | Entry |
| 34 | Pikachu | 4760 | Entry |
| 35 | krysix | 4760 | Entry |
| 36 | gandalf | 4760 | Entry |
| 37 | Parshwa | 4760 | Entry |
| 38 | P1ckl3 | 4760 | Entry |
| 39 | DenRubai | 4740 | Entry |
| 40 | A380 | 4740 | Entry |
| 41 | alwayshungry | 4740 | Entry |
| 42 | xdoubtful | 4720 | Entry |
| 43 | Sunny59 | 4720 | Entry |
| 44 | AJ56 | 4700 | Entry |
| 45 | nobody27 | 4680 | Entry |
| 46 | bluephish | 4680 | Entry |
| 47 | Kalilee | 4660 | Entry |
| 50 | ft44k | 4380 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | eforsha | 4800 | $2,000 + Entry |
| 2 | Thomas | 4800 | $1,200 + Entry |
| 3 | 1-2-3-4 | 4800 | $800 + Entry |
| 4 | AU1 | 4800 | $500 + Entry |
| 5 | Survivor4Ever | 4800 | $500 + Entry |
| 6 | NightHammer | 4800 | $500 + Entry |
| 7 | ZachsAlt | 4800 | $500 + Entry |
| 8 | Romulus | 4800 | $500 + Entry |
| 9 | pmchale | 4800 | $500 + Entry |
| 10 | ByKroo | 4800 | Entry |
| 11 | kquirosf102 | 4800 | Entry |
| 12 | JConatus | 4800 | Entry |
| 13 | bwillhelm | 4800 | Entry |
| 14 | jasonmull | 4800 | Entry |
| 15 | ThreatSlayer | 4800 | Entry |
| 16 | james | 4800 | Entry |
| 17 | JayHole | 4800 | Entry |
| 18 | capnjack | 4800 | Entry |
| 19 | mainasara | 4800 | Entry |
| 20 | Sil3nt_gh0st | 4800 | Entry |
| 21 | RakeshN | 4800 | Entry |
| 22 | ninjacat | 4800 | Entry |
| 23 | jswiegele | 4800 | Entry |
| 24 | Max | 4780 | Entry |
| 25 | nkoester | 4780 | Entry |
| 26 | benthehen100 | 4780 | Entry |
| 27 | nok0 | 4780 | Entry |
| 28 | max | 4780 | Entry |
| 29 | Dani | 4780 | Entry |
| 30 | testuser | 4780 | Entry |
| 31 | mprof | 4780 | Entry |
| 32 | caputdraconis | 4780 | Entry |
| 33 | colsaBoys | 4780 | Entry |
| 34 | Endlaze | 4780 | Entry |
| 35 | littymac | 4780 | Entry |
| 36 | jlytle | 4780 | Entry |
| 37 | ana7z | 4780 | Entry |
| 38 | mkilp | 4780 | Entry |
| 39 | ComradePanda | 4780 | Entry |
| 40 | SHWON | 4760 | Entry |
| 41 | s-swift | 4760 | Entry |
| 42 | sickstick | 4760 | Entry |
| 43 | David_S | 4760 | Entry |
| 44 | EchoNight | 4760 | Entry |
| 45 | gg88gg99 | 4760 | Entry |
| 46 | rtovell | 4760 | Entry |
| 47 | saberwolf617 | 4745 | Entry |
| 48 | alevine | 4740 | Entry |
| 49 | enleak | 4740 | Entry |
| 50 | ahmad | 4740 | Entry |
Back to the Menu Quick Jump
Live table for the Cloud League Qualifiers are as follows. Top 50 on October 2 qualify for the Regional Finals.
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | NotFound | 3900 | $2,000 + Entry |
| 2 | Sean | 3900 | $1,200 + Entry |
| 3 | Shawn_Kwak | 3900 | $800 + Entry |
| 4 | Absol | 3900 | $500 + Entry |
| 5 | Salmon-Mia | 3900 | $500 + Entry |
| 6 | injun | 3900 | $500 + Entry |
| 7 | Gon | 3900 | $500 + Entry |
| 8 | Hyena | 3900 | $500 + Entry |
| 9 | donghyeok | 3900 | $500 + Entry |
| 10 | Minyoung | 3900 | $500 + Entry |
| 11 | 1stTimer | 3900 | Entry |
| 12 | HoumanD | 3900 | Entry |
| 13 | mastoto | 3900 | Entry |
| 14 | Jim | 3900 | Entry |
| 15 | gwthm01 | 3900 | Entry |
| 16 | cyrusmehra | 3900 | Entry |
| 17 | kerostic | 3880 | Entry |
| 18 | 0xDariusNG | 3880 | Entry |
| 19 | Jay | 3880 | Entry |
| 20 | ouoaaa | 3880 | Entry |
| 21 | pgpt | 3880 | Entry |
| 22 | HNVN | 3880 | Entry |
| 23 | TI-MG | 3880 | Entry |
| 24 | weeknd | 3880 | Entry |
| 25 | Bolito687 | 3880 | Entry |
| 26 | Sujin | 3880 | Entry |
| 27 | Siwoo | 3860 | Entry |
| 28 | Johncena | 3860 | Entry |
| 29 | Nisanak | 3860 | Entry |
| 30 | 1-1063 | 3860 | Entry |
| 31 | Ketsui | 3860 | Entry |
| 32 | clerkofcourse | 3850 | Entry |
| 33 | wliu | 3840 | Entry |
| 34 | heogi | 3820 | Entry |
| 35 | usrbin | 3820 | Entry |
| 36 | SmolAME | 3810 | Entry |
| 37 | qutypie | 3800 | Entry |
| 38 | quifl | 3800 | Entry |
| 39 | avynilite | 3770 | Entry |
| 40 | sanketsalve | 3760 | Entry |
| 41 | r00t | 3750 | Entry |
| 42 | ctrlmurray | 3740 | Entry |
| 43 | Dia | 3680 | Entry |
| 44 | Gowda | 3460 | Entry |
| 45 | skkcyb3r | 3390 | Entry |
| 46 | ezhunt | 3080 | Entry |
| 47 | jeba | 2740 | Entry |
| 48 | josep | 2720 | Entry |
| 49 | pincode | 2700 | Entry |
| 50 | Shiva | 2660 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | ELL | 3900 | $2,000 + Entry |
| 2 | french_taco | 3900 | $1,200 + Entry |
| 3 | jodie | 3900 | $800 + Entry |
| 4 | Revil | 3900 | $500 + Entry |
| 5 | EthicalPetal | 3900 | $500 + Entry |
| 6 | hemalsoni22 | 3900 | $500 + Entry |
| 7 | Krish | 3900 | $500 + Entry |
| 8 | Parshwa | 3900 | $500 + Entry |
| 9 | D1vy | 3900 | $500 + Entry |
| 10 | HermessNRJ | 3900 | $500 + Entry |
| 11 | mka | 3900 | Entry |
| 12 | ah01 | 3900 | Entry |
| 13 | tomkerswill | 3900 | Entry |
| 14 | demisto | 3900 | Entry |
| 15 | P3ngu1nB3er | 3900 | Entry |
| 16 | Arnau | 3880 | Entry |
| 17 | A380 | 3880 | Entry |
| 18 | Lennard | 3880 | Entry |
| 19 | Fenio | 3880 | Entry |
| 20 | manthan1501 | 3880 | Entry |
| 21 | imouse | 3880 | Entry |
| 22 | rado-van | 3880 | Entry |
| 23 | MrHokage | 3880 | Entry |
| 24 | guin | 3880 | Entry |
| 25 | Duall | 3880 | Entry |
| 26 | jamesthor | 3880 | Entry |
| 27 | Dhara23 | 3870 | Entry |
| 28 | christopher | 3860 | Entry |
| 29 | moon77 | 3860 | Entry |
| 30 | eniz | 3860 | Entry |
| 31 | Oscar_G | 3860 | Entry |
| 32 | dcpl | 3860 | Entry |
| 33 | htue | 3860 | Entry |
| 34 | sug4r-wr41th | 3840 | Entry |
| 35 | modeus | 3840 | Entry |
| 36 | blackhat | 3840 | Entry |
| 37 | xdoubtful | 3840 | Entry |
| 38 | CBVirus | 3840 | Entry |
| 39 | Plissken | 3840 | Entry |
| 40 | Igor | 3840 | Entry |
| 41 | StijnG | 3820 | Entry |
| 42 | RDx | 3820 | Entry |
| 43 | JohnMatrix | 3820 | Entry |
| 44 | Ptikek | 3820 | Entry |
| 45 | Kalilee | 3800 | Entry |
| 46 | canigetabeepbeep | 3780 | Entry |
| 47 | SilentPursuit | 3780 | Entry |
| 48 | nobody27 | 3780 | Entry |
| 49 | Drako | 3770 | Entry |
| 50 | desidosa | 3760 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | Stephen | 3900 | $2,000 + Entry |
| 2 | Honu | 3900 | Entry |
| 3 | AU1 | 3900 | $800 + Entry |
| 4 | Red-Beard | 3900 | $500 + Entry |
| 5 | Thomas | 3900 | $500 + Entry |
| 6 | 1-2-3-4 | 3900 | $500 + Entry |
| 7 | nmkoester | 3900 | $500 + Entry |
| 8 | bwillhelm | 3900 | $500 + Entry |
| 9 | WilliamMailhot | 3900 | $500 + Entry |
| 10 | alevine | 3900 | $500 + Entry |
| 11 | eforsha | 3900 | Entry |
| 12 | GenericAll | 3900 | Entry |
| 13 | threathunting123 | 3900 | Entry |
| 14 | benthehen100 | 3900 | Entry |
| 15 | Cwallis | 3900 | Entry |
| 16 | Joshua_Knight | 3900 | Entry |
| 17 | JacobL | 3900 | Entry |
| 18 | josh_24v_15 | 3900 | Entry |
| 19 | james | 3900 | Entry |
| 20 | maverick | 3900 | Entry |
| 21 | Hunter53 | 3900 | Entry |
| 22 | tessah_k | 3900 | Entry |
| 23 | Wisdom1k | 3900 | Entry |
| 24 | riskybusiness | 3900 | Entry |
| 25 | rpatrick | 3900 | Entry |
| 26 | wizard113 | 3900 | Entry |
| 27 | Dr_Ew | 3900 | Entry |
| 28 | Survivor4Ever | 3900 | Entry |
| 29 | BGrad | 3900 | Entry |
| 30 | 0x626d | 3900 | Entry |
| 31 | _operator | 3900 | Entry |
| 32 | oj_cup | 3900 | Entry |
| 33 | ThreatSlayer | 3900 | Entry |
| 34 | Seasalt | 3900 | Entry |
| 35 | daswon | 3880 | Entry |
| 36 | dwest | 3880 | Entry |
| 37 | mprof | 3880 | Entry |
| 38 | Dani | 3880 | Entry |
| 39 | hue | 3880 | Entry |
| 40 | ZachsAlt | 3880 | Entry |
| 41 | flipyaforreal | 3880 | Entry |
| 42 | jswisher | 3880 | Entry |
| 43 | gary | 3880 | Entry |
| 44 | ana7z | 3880 | Entry |
| 45 | DefenderA | 3880 | Entry |
| 46 | Avlyssna | 3880 | Entry |
| 47 | JayHole | 3880 | Entry |
| 48 | Max | 3880 | Entry |
| 49 | TheExemplar | 3880 | Entry |
| 50 | eDak | 3880 | Entry |
Back to the Menu Quick Jump
Live table for the SIEM League Qualifiers are as follows. Top 50 on October 2 qualify for the Regional Finals.
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | Jay | 4100 | $2,000 + Entry |
| 2 | Sean | 4100 | $1,200 + Entry |
| 3 | ouoaaa | 4100 | $800 + Entry |
| 4 | injun | 4100 | $500 + Entry |
| 5 | Hyena | 4100 | $500 + Entry |
| 6 | 0xKowloon | 4100 | Entry |
| 7 | Gon | 4080 | $500 + Entry |
| 8 | NotFound | 4080 | $500 + Entry |
| 9 | drake | 3980 | $500 + Entry |
| 10 | Johncena | 3820 | $500 + Entry |
| 11 | Absol | 3800 | Entry |
| 12 | Shawn_Kwak | 3800 | Entry |
| 13 | Bolito687 | 3800 | Entry |
| 14 | heogi | 3780 | Entry |
| 15 | kerostic | 3760 | Entry |
| 16 | Mingi | 3720 | Entry |
| 17 | 1stTimer | 3680 | Entry |
| 18 | ctrlmurray | 3680 | Entry |
| 19 | avynilite | 3660 | Entry |
| 20 | Tape_Dispenser | 3600 | Entry |
| 21 | AgentMrX | 3600 | Entry |
| 22 | Duckduck | 3580 | Entry |
| 23 | SteveM | 3540 | Entry |
| 24 | Minyoung | 3500 | Entry |
| 25 | GCTDLover | 3500 | Entry |
| 26 | Salmon-Mia | 3480 | Entry |
| 27 | HYEOK | 3480 | Entry |
| 28 | Siwoo | 3440 | Entry |
| 29 | gwthm01 | 3440 | Entry |
| 30 | Sujin | 3440 | Entry |
| 31 | SmolAME | 3400 | Entry |
| 32 | 1-1063 | 3320 | Entry |
| 33 | host | 3200 | Entry |
| 34 | Ketsui | 3200 | Entry |
| 35 | 0xDariusNG | 3200 | Entry |
| 36 | tianred | 3180 | Entry |
| 37 | 1stTimer | 3180 | Entry |
| 38 | Anusthika | 3020 | Entry |
| 39 | null_faruq | 2780 | Entry |
| 40 | ace | 2760 | Entry |
| 41 | usrbin | 2680 | Entry |
| 42 | haysia-aml | 2660 | Entry |
| 43 | MooH | 2660 | Entry |
| 44 | CTF_threathunt9 | 2660 | Entry |
| 45 | clerkofcourse | 2640 | Entry |
| 46 | quifl | 2640 | Entry |
| 47 | shreyas | 2620 | Entry |
| 48 | hardikjain | 2580 | Entry |
| 49 | Genie | 2580 | Entry |
| 50 | Dastr0 | 2560 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | Red-Beard | 4100 | $2,000 + Entry |
| 2 | Romulus | 4100 | $1,200 + Entry |
| 3 | Survivor4Ever | 4100 | $800 + Entry |
| 4 | nok0 | 4000 | $500 + Entry |
| 5 | staas | 4000 | $500 + Entry |
| 6 | Sneha | 3960 | $500 + Entry |
| 7 | ninjascout_ii | 3900 | $500 + Entry |
| 8 | CmdnControl | 3900 | $500 + Entry |
| 9 | 1-2-3-4 | 3880 | $500 + Entry |
| 10 | post | 3880 | $500 + Entry |
| 11 | ZachsAlt | 3880 | Entry |
| 12 | jqueso | 3860 | Entry |
| 13 | rzv | 3840 | Entry |
| 14 | zero_cool | 3780 | Entry |
| 15 | SHWON | 3740 | Entry |
| 16 | m4lwhere | 3700 | Entry |
| 17 | rutvij2811 | 3700 | Entry |
| 18 | spelosi | 3680 | Entry |
| 19 | mp-549228 | 3640 | Entry |
| 20 | TheExemplar | 3620 | Entry |
| 21 | Max | 3600 | Entry |
| 22 | AU1 | 3580 | Entry |
| 23 | Sil3nt_gh0st | 3580 | Entry |
| 24 | Kizzmit | 3580 | Entry |
| 25 | mprof | 3500 | Entry |
| 26 | jasonmull | 3500 | Entry |
| 27 | riskybusiness | 3480 | Entry |
| 28 | Tester123 | 3480 | Entry |
| 29 | oj_cup | 3480 | Entry |
| 30 | noobpro | 3460 | Entry |
| 31 | eforsha | 3440 | Entry |
| 32 | french_taco | 3400 | Entry |
| 33 | Hacker | 3400 | Entry |
| 34 | Linus | 3400 | Entry |
| 35 | heringfish | 3400 | Entry |
| 36 | malik | 3400 | Entry |
| 37 | cyberpanda | 3400 | Entry |
| 38 | Dani | 3380 | Entry |
| 39 | LindzerBeamz | 3340 | Entry |
| 40 | Diasum | 3300 | Entry |
| 41 | NotTotallyHere | 3300 | Entry |
| 42 | dwest | 3300 | Entry |
| 43 | alevine | 3300 | Entry |
| 44 | james | 3300 | Entry |
| 45 | pgruntkowski | 3300 | Entry |
| 46 | ninjacat | 3280 | Entry |
| 47 | 4thelulz1 | 3280 | Entry |
| 48 | eDak | 3280 | Entry |
| 49 | OptimalNaptime | 3200 | Entry |
| 50 | Tony_Willey27 | 3200 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | Arnau | 3980 | $2,000 + Entry |
| 2 | acassano | 3900 | $1,200 + Entry |
| 3 | tocj | 3900 | $800 + Entry |
| 4 | JoeS | 3900 | $500 + Entry |
| 5 | carlosgomez | 3880 | $500 + Entry |
| 6 | demisto | 3880 | $500 + Entry |
| 7 | RDx | 3880 | Entry |
| 8 | jodie | 3860 | $500 + Entry |
| 9 | Pinax | 3860 | $500 + Entry |
| 10 | Chris | 3860 | $500 + Entry |
| 11 | Fenio | 3860 | Entry |
| 12 | desidosa | 3840 | Entry |
| 13 | mka | 3800 | Entry |
| 14 | Nirmit | 3800 | Entry |
| 15 | SSman | 3780 | Entry |
| 16 | karasek | 3780 | Entry |
| 17 | blackhat | 3760 | Entry |
| 18 | Kamil7cd | 3740 | Entry |
| 19 | rado-van | 3700 | Entry |
| 20 | Pst | 3700 | Entry |
| 21 | tomkerswill | 3700 | Entry |
| 22 | Mzk00 | 3680 | Entry |
| 23 | ALDX | 3620 | Entry |
| 24 | mtekbicak | 3580 | Entry |
| 25 | modeus | 3560 | Entry |
| 26 | andresitoo | 3540 | Entry |
| 27 | eniz | 3540 | Entry |
| 28 | DenRubai | 3540 | Entry |
| 29 | StijnG | 3500 | Entry |
| 30 | HackNSeek | 3500 | Entry |
| 31 | Plissken | 3480 | Entry |
| 32 | m3m3kritis | 3460 | Entry |
| 33 | trashclutch | 3460 | Entry |
| 34 | Dante | 3440 | Entry |
| 35 | DFJ | 3420 | Entry |
| 36 | __zCK | 3340 | Entry |
| 37 | alwayshungry | 3320 | Entry |
| 38 | seclingua | 3260 | Entry |
| 39 | ronald_mcdonald | 3260 | Entry |
| 40 | mara-deva | 3180 | Entry |
| 41 | ABogdan | 3160 | Entry |
| 42 | icheptrosu | 3160 | Entry |
| 43 | MrMurkl | 3160 | Entry |
| 44 | TristanA | 3040 | Entry |
| 45 | h4ckm4estro | 2920 | Entry |
| 46 | gen_kai | 2880 | Entry |
| 47 | Dani | 2860 | Entry |
| 48 | Graf | 2800 | Entry |
| 49 | hipparcos | 2760 | Entry |
| 50 | Bilal | 2740 | Entry |
Back to the Menu Quick Jump
Live table for the Endpoint League Qualifiers are as follows. Top 50 on October 2 qualify for the Regional Finals.
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | Salmon-Mia | 6100 | $2,000 + Entry |
| 2 | Jay | 6100 | $1,200 + Entry |
| 3 | ouoaaa | 6100 | $800 + Entry |
| 4 | Sean | 6100 | $500 + Entry |
| 5 | INTfinityBeyond | 6100 | $500 + Entry |
| 6 | tanjiro | 6100 | $500 + Entry |
| 7 | Tape_Dispenser | 6100 | $500 + Entry |
| 8 | Duckduck | 6100 | $500 + Entry |
| 9 | GCTDLover | 6100 | $500 + Entry |
| 10 | PrincessLeia | 6100 | $500 + Entry |
| 11 | injigi | 6100 | Entry |
| 12 | Hyena | 6100 | Entry |
| 13 | heogi | 6100 | Entry |
| 14 | HYEOK | 6100 | Entry |
| 15 | NotFound | 6100 | Entry |
| 16 | ctrlmurray | 6100 | Entry |
| 17 | 0xDariusNG | 6100 | Entry |
| 18 | Minyoung | 6100 | Entry |
| 19 | v_chips | 6100 | Entry |
| 20 | Muhammed | 6100 | Entry |
| 21 | avynilite | 6080 | Entry |
| 22 | ana | 6080 | Entry |
| 23 | nilnocnil | 6080 | Entry |
| 24 | jstanINTern | 6060 | Entry |
| 25 | Johncena | 6060 | Entry |
| 26 | matrix | 6060 | Entry |
| 27 | Siwoo | 6060 | Entry |
| 28 | DemetrianTitus | 6050 | Entry |
| 29 | kerostic | 6050 | Entry |
| 30 | BobCrusader | 6040 | Entry |
| 31 | pgpt | 6000 | Entry |
| 32 | SmolAME | 6000 | Entry |
| 33 | haszayan | 5990 | Entry |
| 34 | jsil | 5990 | Entry |
| 35 | JasonPhang98 | 5930 | Entry |
| 36 | MPrin | 5920 | Entry |
| 37 | null_faruq | 5900 | Entry |
| 38 | MooH | 5870 | Entry |
| 39 | clerkofcourse | 5850 | Entry |
| 40 | Anusthika | 5810 | Entry |
| 41 | JimmyJames007 | 5780 | Entry |
| 42 | drake | 5780 | Entry |
| 43 | l3Iadk | 5670 | Entry |
| 44 | tigerkali | 5650 | Entry |
| 45 | gwthm01 | 5580 | Entry |
| 46 | Anonghost | 5560 | Entry |
| 47 | ZKAD00SH | 5550 | Entry |
| 48 | Sujin | 5540 | Entry |
| 49 | Gowda | 5510 | Entry |
| 50 | qutypie | 5360 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | AU1 | 6100 | $2,000 + Entry |
| 2 | eforsha | 6100 | $1,200 + Entry |
| 3 | Red-Beard | 6100 | $800 + Entry |
| 4 | Thomas | 6100 | $500 + Entry |
| 5 | Survivor4Ever | 6100 | $500 + Entry |
| 6 | Stephen | 6100 | $500 + Entry |
| 7 | wgadzinski | 6100 | $500 + Entry |
| 8 | jdennen | 6100 | $500 + Entry |
| 9 | french_taco | 6100 | $500 + Entry |
| 10 | Romulus | 6100 | $500 + Entry |
| 11 | 1-2-3-4 | 6100 | Entry |
| 12 | packetnerd | 6100 | Entry |
| 13 | josh_24v_15 | 6100 | Entry |
| 14 | jswisher | 6100 | Entry |
| 15 | nok0 | 6100 | Entry |
| 16 | bwillhelm | 6100 | Entry |
| 17 | bcs3c | 6100 | Entry |
| 18 | ThreatSlayer | 6100 | Entry |
| 19 | testuser | 6100 | Entry |
| 20 | benthehen100 | 6100 | Entry |
| 21 | mar | 6100 | Entry |
| 22 | alphacentauri | 6080 | Entry |
| 23 | jqueso | 6080 | Entry |
| 24 | IamMalayali | 6080 | Entry |
| 25 | tresscross | 6080 | Entry |
| 26 | OptimalNaptime | 6080 | Entry |
| 27 | ZachsAlt | 6080 | Entry |
| 28 | riskybusiness | 6080 | Entry |
| 29 | Cwallis | 6080 | Entry |
| 30 | Tester123 | 6080 | Entry |
| 31 | Dani | 6080 | Entry |
| 32 | mp-549228 | 6070 | Entry |
| 33 | dwest | 6060 | Entry |
| 34 | bat | 6060 | Entry |
| 35 | cgrussell | 6060 | Entry |
| 36 | David_S | 6060 | Entry |
| 37 | ninjascout_ii | 6060 | Entry |
| 38 | staas | 6050 | Entry |
| 39 | bsimm | 6050 | Entry |
| 40 | garfield | 6050 | Entry |
| 41 | Diasum | 6040 | Entry |
| 42 | SHWON | 6040 | Entry |
| 43 | CyberSaiyan84 | 6040 | Entry |
| 44 | Kratos | 6030 | Entry |
| 45 | LowImpulsControl | 6030 | Entry |
| 46 | relogonm | 6030 | Entry |
| 47 | WilliamMailhot | 6020 | Entry |
| 48 | purpleai | 6020 | Entry |
| 49 | silly_monkey | 6020 | Entry |
| 50 | Gagneet | 6020 | Entry |
| Rank | Alias | Score | Prize |
|---|---|---|---|
| 1 | Tarak | 6100 | $2,000 + Entry |
| 2 | eceh | 6100 | Entry |
| 3 | Andy | 6100 | $800 + Entry |
| 4 | Naruto | 6100 | Entry |
| 5 | ELL | 6100 | $500 + Entry |
| 6 | jodie | 6100 | $500 + Entry |
| 7 | kochl0 | 6100 | Entry |
| 8 | mka | 6100 | Entry |
| 9 | RDx | 6090 | Entry |
| 10 | jasmineadams | 6080 | $500 + Entry |
| 11 | Sid_XDR | 6070 | Entry |
| 12 | carlosgomez | 6070 | Entry |
| 13 | gen_kai | 6060 | Entry |
| 14 | SSman | 6060 | Entry |
| 15 | Arnau | 6050 | Entry |
| 16 | Chris | 6050 | Entry |
| 17 | IamKD | 6040 | Entry |
| 18 | tdlwv | 6040 | Entry |
| 19 | acassano | 6020 | Entry |
| 20 | Linus | 6000 | Entry |
| 21 | Vaishnavi | 6000 | Entry |
| 22 | Meghana | 6000 | Entry |
| 23 | StijnG | 6000 | Entry |
| 24 | Revil | 6000 | Entry |
| 25 | D1vy | 6000 | Entry |
| 26 | Pinax | 6000 | Entry |
| 27 | Shreya | 6000 | Entry |
| 28 | moon77 | 5980 | Entry |
| 29 | Obfuscated_LOL | 5980 | Entry |
| 30 | Nico | 5980 | Entry |
| 31 | Devarsh | 5980 | Entry |
| 32 | hemalsoni22 | 5980 | Entry |
| 33 | manthan1501 | 5980 | Entry |
| 34 | jenilsadrani | 5980 | Entry |
| 35 | Krish | 5980 | Entry |
| 36 | jaygohel | 5960 | Entry |
| 37 | monster77 | 5960 | Entry |
| 38 | EthicalPetal | 5960 | Entry |
| 39 | Parshwa | 5950 | Entry |
| 40 | Skandora | 5940 | Entry |
| 41 | rado-van | 5940 | Entry |
| 42 | surennp | 5930 | Entry |
| 43 | palgari9718 | 5910 | Entry |
| 44 | karasek | 5890 | Entry |
| 45 | VRO | 5860 | Entry |
| 46 | sstoyanov | 5800 | Entry |
| 47 | Mzk00 | 5800 | Entry |
| 48 | Xavier | 5780 | Entry |
| 49 | eniz | 5680 | Entry |
| 50 | MelonPan | 5660 | Entry |
Back to the Menu Quick Jump
This championship is proud to unite thousands of cybersecurity defenders in a showcase of skill, innovation, and strategy. We invite you to share this blog for live updates, engage with us on social media, help grow the buzz across our community, and watch as the stage for threat hunting glory gets bigger. Also, it’s not too late to make a run at Regionals. Enter the next qualifier and save your spot in the Sentinels League today!
Participation is open worldwide. Prize eligibility is subject to Terms & Conditions and some countries are not eligible to receive monetary rewards. See the full rules for details.

p:5+ have:behavior fs:30d+ not have:sigma
p:5+ (sandbox_name:"CAPE Sandbox" or sandbox_name:"Zenbox") fs:30d+ not have:sigma
p:5+ have:behavior fs:30d+ sigma_critical:0 sigma_high:0 sigma_medium:0 sigma_low:2-
title: Detect The Execution Of More.com And Vbc.exe Related to Lummac Stealer
id: 19b3806e-46f2-4b4c-9337-e3d8653245ea
status: experimental
description: Detects the execution of more.com and vbc.exe in the process tree. This behaviors was observed by a set of samples related to Lummac Stealer. The Lummac payload is injected into the vbc.exe process.
references:
- https://www.virustotal.com/gui/file/14d886517fff2cc8955844b252c985ab59f2f95b2849002778f03a8f07eb8aef
- https://strontic.github.io/xcyclopedia/library/more.com-EDB3046610020EE614B5B81B0439895E.html
- https://strontic.github.io/xcyclopedia/library/vbc.exe-A731372E6F6978CE25617AE01B143351.html
author: Joseliyo Sanchez, @Joseliyo_Jstnk
date: 2024-11-14
tags:
- attack.defense-evasion
- attack.t1055
logsource:
category: process_creation
product: windows
detection:
# VT Query: behaviour_processes:"C:\\Windows\\SysWOW64\\more.com" behaviour_processes:"C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe"
selection_parent:
ParentImage|endswith: '\more.com'
selection_child:
- Image|endswith: '\vbc.exe'
- OriginalFileName: 'vbc.exe'
condition: all of selection_*
falsepositives:
- Unknown
level: high
{
"System": {
"Provider": {
"Guid": "{5770385F-C22A-43E0-BF4C-06F5698FFBD9}",
"Name": "Microsoft-Windows-Sysmon"
},
"EventID": 1,
"Version": 5,
"Level": 4,
"Task": 1,
"Opcode": 0,
"Keywords": "0x8000000000000000",
"TimeCreated": {
"SystemTime": "2024-11-26T16:23:05.132539500Z"
},
"EventRecordID": 692861,
"Correlation": {},
"Execution": {
"ProcessID": 2396,
"ThreadID": 3116
},
"Channel": "Microsoft-Windows-Sysmon/Operational",
"Computer": "DESKTOP-B0T93D6",
"Security": {
"UserID": "S-1-5-18"
}
},
"EventData": {
"RuleName": "-",
"UtcTime": "2024-11-26 16:23:05.064",
"ProcessGuid": "{C784477D-F5E9-6745-6006-000000003F00}",
"ProcessId": 4184,
"Image": "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe",
"FileVersion": "14.8.3761.0",
"Description": "Visual Basic Command Line Compiler",
"Product": "Microsoft® .NET Framework",
"Company": "Microsoft Corporation",
"OriginalFileName": "vbc.exe",
"CommandLine": "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe",
"CurrentDirectory": "C:\\Users\\george\\AppData\\Roaming\\comlocal\\RUYCLAXYVMFJ\\",
"User": "DESKTOP-B0T93D6\\george",
"LogonGuid": "{C784477D-9D9B-66FF-6E87-050000000000}",
"LogonId": "0x5876e",
"TerminalSessionId": 1,
"IntegrityLevel": "High",
"Hashes": {
"SHA1": "61F4D9A9EE38DBC72E840B3624520CF31A3A8653",
"MD5": "FCCB961AE76D9E600A558D2D0225ED43",
"SHA256": "466876F453563A272ADB5D568670ECA98D805E7ECAA5A2E18C92B6D3C947DF93",
"IMPHASH": "1460E2E6D7F8ECA4240B7C78FA619D15"
},
"ParentProcessGuid": "{C784477D-F5D4-6745-5E06-000000003F00}",
"ParentProcessId": 6572,
"ParentImage": "C:\\Windows\\SysWOW64\\more.com",
"ParentCommandLine": "C:\\Windows\\SysWOW64\\more.com",
"ParentUser": "DESKTOP-B0T93D6\\george"
}
}
title: File Creation Related To RAT Clients
id: 2f3039c8-e8fe-43a9-b5cf-dcd424a2522d
status: experimental
description: File .conf created related to VenomRAT, AsyncRAT and Lummac samples observed in the wild.
references:
- https://www.virustotal.com/gui/file/c9f9f193409217f73cc976ad078c6f8bf65d3aabcf5fad3e5a47536d47aa6761
- https://www.virustotal.com/gui/file/e96a0c1bc5f720d7f0a53f72e5bb424163c943c24a437b1065957a79f5872675
author: Joseliyo Sanchez, @Joseliyo_Jstnk
date: 2024-11-15
tags:
- attack.execution
logsource:
category: file_event
product: windows
detection:
# VT Query: behaviour_files:"\\AppData\\Roaming\\DataLogs\\DataLogs.conf"
# VT Query: behaviour_files:"DataLogs.conf" or behaviour_files:"hvnc.conf" or behaviour_files:"dcrat.conf"
selection_required:
TargetFilename|contains: '\AppData\Roaming\'
selection_variants:
TargetFilename|endswith:
- '\datalogs.conf'
- '\hvnc.conf'
- '\dcrat.conf'
TargetFilename|contains:
- '\mydata\'
- '\datalogs\'
- '\hvnc\'
- '\dcrat\'
condition: all of selection_*
falsepositives:
- Legitimate software creating a file with the same name
level: high
{
"System": {
"Provider": {
"Guid": "{5770385F-C22A-43E0-BF4C-06F5698FFBD9}",
"Name": "Microsoft-Windows-Sysmon"
},
"EventID": 11,
"Version": 2,
"Level": 4,
"Task": 11,
"Opcode": 0,
"Keywords": "0x8000000000000000",
"TimeCreated": {
"SystemTime": "2024-12-02T00:52:23.072811600Z"
},
"EventRecordID": 1555690,
"Correlation": {},
"Execution": {
"ProcessID": 2624,
"ThreadID": 3112
},
"Channel": "Microsoft-Windows-Sysmon/Operational",
"Computer": "DESKTOP-B0T93D6",
"Security": {
"UserID": "S-1-5-18"
}
},
"EventData": {
"RuleName": "-",
"UtcTime": "2024-12-02 00:52:23.059",
"ProcessGuid": "{C784477D-04C6-674D-5C06-000000004B00}",
"ProcessId": 7592,
"Image": "C:\\Users\\george\\Desktop\\ezzz.exe",
"TargetFilename": "C:\\Users\\george\\AppData\\Roaming\\MyData\\DataLogs.conf",
"CreationUtcTime": "2024-12-02 00:52:23.059",
"User": "DESKTOP-B0T93D6\\george"
}
sigma_rule:a1021d4086a92fd3782417a54fa5c5141d1e75c8afc9e73dc6e71ef9e1ae2e9c
sigma_rule:8f179585d5c1249ab1ef8cec45a16d112a53f91d143aa2b0b6713602b1d19252

Pivoting on infrastructure is a handy skill for cyber threat
intelligence (CTI) analysts to learn. It can help to reveal the bigger picture
when it comes to malware, phishing, or network exploitation campaigns. Infrastructure
pivoting essentially is the act of looking for more systems an adversary has
created. The main benefit of this pursuit is the identification of additional
targets or victims, more tools or malware samples, and ultimately new insights
about the adversary’s capabilities.
If done correctly, being able to pivot on adversary
infrastructure will be very useful during incident response (IR) engagements. For
example, it may lead to being able to attribute the intrusion to a known
adversary. This will help others during an IR engagement understand the level
of threat posed to the victim organisation.
To be able to pivot on adversary infrastructure, threat data
is needed such as the intelligence shared by threat reports put out
by various researchers from public and private sector organisations. This
scenario, however, involves relying on the analysis skills of other researchers to explain
what the infrastructure is and when they observed it in use.
This blog will examine threat data provided by public sector
organisations such as the Computer Emergency Response Team of Ukraine (CERT-UA)
as well as cybersecurity vendors such as Deep Instinct, Cyble, and Fortinet.
These organisations have shared indicators of compromise (IOCs) uncovered
following analysis of adversary intrusion activities or upload to online
malware sandboxes, such as VirusTotal, among others.
On 3 June 2024, Fortinet shared a report
on malicious XLS macro documents leading to Cobalt Strike Beacons. Analysis of
the XLS documents showed that they appeared to be targeting the Ukrainian
military and linked to a known Belarusian state-sponsored APT group tracked as Ghostwriter
(aka UNC1151, UAC-0057, TA445). On 4 June 2024, Cyble also shared a report
on a similar campaign.
In both reports, if the XLS was opened and the macros were executed
by the target, a malicious DLL file was downloaded from an adversary-created domain.
In Fortinet’s report, two similar “.shop” domains were mentioned. In Cyble’s
report another “.shop” domain was also called out.
The first pivot on Ghostwriter APT infrastructure that will be
demonstrated involves finding indicators of compromise (IOCs) such as domains
and IP addresses that appear in multiple threat reports.
The fastest way to realize these overlaps is through
continuous collection of reported IOCs into a Threat Intelligence Platform
(TIP). This will reveal IOCs that appear in multiple threat reports through
tagging and sources of where IOCs come from. Eventually, one domain or IP
address will get reported by multiple entities and the connection will make
itself apparent.
In Figure 1 (see below) the domain “goudieelectric[.]shop”
appeared in both Cyble’s blog and Fortinet’s blog. Analysis of all three
domains found that they use the same generic top-level domain (gTLD),
registrar, and name servers, as well as have a robots.txt directory configured.
These common infrastructure characteristics indicate that all three domains
were created by the same adversary.
When more IOCs are reported in other threat reports it is
possible to link them to other known domains, this is due to adversaries
reusing the same registrars, name servers, and gTLDs.
In Figure 2 (see below), Deep Instinct reported
two more domains that could also be linked to the previous three domains through
the mutual use of the PublicDomainsRegistry registrar, Cloudflare name servers,
and the robots.txt file.
Further, CERT-UA reported three more domains (see
Figure 3 below) that could be linked to the infrastructure cluster through this
same method as well. This pattern of behaviour is a strong indicator that these
domains were created by the same adversary.
Since the domains from the above threat reports were
collected and linked together through overlapping attributes, it is now
possible to use these attributes to find more domains that had gone unreported.
Using a VirusTotal domain attribute query, additional domains
can be found by using the following registration pattern:
This revealed up to 24 domains that matched this pattern
that were likely created by Ghostwriter, a state-sponsored APT group:
Note: VirusTotal domain searches are only available
to VirusTotal Enterprise users. There are other providers which allow you to search
for domain registration patterns such as DomainTools, Validin, and Zetalytics. There
also some free OSINT sites such as nslookup.io
and viewdns.info that can be useful in
certain scenarios.
Using the list of similar domains that were uncovered
through the registration pattern search, it is then possible to find additional
malware samples communicating with them.
This can be achieved by looking at domains in VirusTotal and checking the Relations tab can show communicating files as shown in Figure 4 below.
Using a VirusTotal graph can help to reveal every
communicating file with every domain discovered through the registration pattern
search, as shown in Figure 5 below.
URL to the VirusTotal Graph: https://www.virustotal.com/graph/embed/gd2c04407d9ba4b75b2ce73d6155d166d3ef75eaf29894ff5ac287c90400072bc?theme=dark
URL to the VirusTotal Collection: https://www.virustotal.com/gui/collection/2aa6b36a717be8bc49f7925434ca40f3ecb9f628414b491da3e985677508ca08/iocs
In conclusion, it is important for CTI analysts to closer
inspect the attributes of the IOCs they come across. It is not uncommon for
state-sponsored APT groups to make such mistakes when creating their
infrastructure to launch attacks from. By exploiting this fact, CTI analysts
can learn much more about the adversary’s targets, capabilities, and the behaviours
of the humans themselves behind such campaigns.
The importance of this type of work was demonstrated in
December 2023 when the US Treasury
sanctioned members of the Russian APT group known as Callisto
(aka Star Blizzard, BlueCharlie, COLDRIVER, GOSSAMER BEAR). The real world
identity of Andrey Korinets was revealed after he was sanctioned for fraudulently
creating and registering malicious domain infrastructure for Russian federal
security service (FSB) spear phishing campaigns.
p:5+ have:behavior fs:30d+ not have:sigma
p:5+ (sandbox_name:"CAPE Sandbox" or sandbox_name:"Zenbox") fs:30d+ not have:sigma
p:5+ have:behavior fs:30d+ sigma_critical:0 sigma_high:0 sigma_medium:0 sigma_low:2-
title: Detect The Execution Of More.com And Vbc.exe Related to Lummac Stealer
id: 19b3806e-46f2-4b4c-9337-e3d8653245ea
status: experimental
description: Detects the execution of more.com and vbc.exe in the process tree. This behaviors was observed by a set of samples related to Lummac Stealer. The Lummac payload is injected into the vbc.exe process.
references:
- https://www.virustotal.com/gui/file/14d886517fff2cc8955844b252c985ab59f2f95b2849002778f03a8f07eb8aef
- https://strontic.github.io/xcyclopedia/library/more.com-EDB3046610020EE614B5B81B0439895E.html
- https://strontic.github.io/xcyclopedia/library/vbc.exe-A731372E6F6978CE25617AE01B143351.html
author: Joseliyo Sanchez, @Joseliyo_Jstnk
date: 2024-11-14
tags:
- attack.defense-evasion
- attack.t1055
logsource:
category: process_creation
product: windows
detection:
# VT Query: behaviour_processes:"C:\\Windows\\SysWOW64\\more.com" behaviour_processes:"C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe"
selection_parent:
ParentImage|endswith: '\more.com'
selection_child:
- Image|endswith: '\vbc.exe'
- OriginalFileName: 'vbc.exe'
condition: all of selection_*
falsepositives:
- Unknown
level: high
{
"System": {
"Provider": {
"Guid": "{5770385F-C22A-43E0-BF4C-06F5698FFBD9}",
"Name": "Microsoft-Windows-Sysmon"
},
"EventID": 1,
"Version": 5,
"Level": 4,
"Task": 1,
"Opcode": 0,
"Keywords": "0x8000000000000000",
"TimeCreated": {
"SystemTime": "2024-11-26T16:23:05.132539500Z"
},
"EventRecordID": 692861,
"Correlation": {},
"Execution": {
"ProcessID": 2396,
"ThreadID": 3116
},
"Channel": "Microsoft-Windows-Sysmon/Operational",
"Computer": "DESKTOP-B0T93D6",
"Security": {
"UserID": "S-1-5-18"
}
},
"EventData": {
"RuleName": "-",
"UtcTime": "2024-11-26 16:23:05.064",
"ProcessGuid": "{C784477D-F5E9-6745-6006-000000003F00}",
"ProcessId": 4184,
"Image": "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe",
"FileVersion": "14.8.3761.0",
"Description": "Visual Basic Command Line Compiler",
"Product": "Microsoft® .NET Framework",
"Company": "Microsoft Corporation",
"OriginalFileName": "vbc.exe",
"CommandLine": "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\vbc.exe",
"CurrentDirectory": "C:\\Users\\george\\AppData\\Roaming\\comlocal\\RUYCLAXYVMFJ\\",
"User": "DESKTOP-B0T93D6\\george",
"LogonGuid": "{C784477D-9D9B-66FF-6E87-050000000000}",
"LogonId": "0x5876e",
"TerminalSessionId": 1,
"IntegrityLevel": "High",
"Hashes": {
"SHA1": "61F4D9A9EE38DBC72E840B3624520CF31A3A8653",
"MD5": "FCCB961AE76D9E600A558D2D0225ED43",
"SHA256": "466876F453563A272ADB5D568670ECA98D805E7ECAA5A2E18C92B6D3C947DF93",
"IMPHASH": "1460E2E6D7F8ECA4240B7C78FA619D15"
},
"ParentProcessGuid": "{C784477D-F5D4-6745-5E06-000000003F00}",
"ParentProcessId": 6572,
"ParentImage": "C:\\Windows\\SysWOW64\\more.com",
"ParentCommandLine": "C:\\Windows\\SysWOW64\\more.com",
"ParentUser": "DESKTOP-B0T93D6\\george"
}
}
title: File Creation Related To RAT Clients
id: 2f3039c8-e8fe-43a9-b5cf-dcd424a2522d
status: experimental
description: File .conf created related to VenomRAT, AsyncRAT and Lummac samples observed in the wild.
references:
- https://www.virustotal.com/gui/file/c9f9f193409217f73cc976ad078c6f8bf65d3aabcf5fad3e5a47536d47aa6761
- https://www.virustotal.com/gui/file/e96a0c1bc5f720d7f0a53f72e5bb424163c943c24a437b1065957a79f5872675
author: Joseliyo Sanchez, @Joseliyo_Jstnk
date: 2024-11-15
tags:
- attack.execution
logsource:
category: file_event
product: windows
detection:
# VT Query: behaviour_files:"\\AppData\\Roaming\\DataLogs\\DataLogs.conf"
# VT Query: behaviour_files:"DataLogs.conf" or behaviour_files:"hvnc.conf" or behaviour_files:"dcrat.conf"
selection_required:
TargetFilename|contains: '\AppData\Roaming\'
selection_variants:
TargetFilename|endswith:
- '\datalogs.conf'
- '\hvnc.conf'
- '\dcrat.conf'
TargetFilename|contains:
- '\mydata\'
- '\datalogs\'
- '\hvnc\'
- '\dcrat\'
condition: all of selection_*
falsepositives:
- Legitimate software creating a file with the same name
level: high
{
"System": {
"Provider": {
"Guid": "{5770385F-C22A-43E0-BF4C-06F5698FFBD9}",
"Name": "Microsoft-Windows-Sysmon"
},
"EventID": 11,
"Version": 2,
"Level": 4,
"Task": 11,
"Opcode": 0,
"Keywords": "0x8000000000000000",
"TimeCreated": {
"SystemTime": "2024-12-02T00:52:23.072811600Z"
},
"EventRecordID": 1555690,
"Correlation": {},
"Execution": {
"ProcessID": 2624,
"ThreadID": 3112
},
"Channel": "Microsoft-Windows-Sysmon/Operational",
"Computer": "DESKTOP-B0T93D6",
"Security": {
"UserID": "S-1-5-18"
}
},
"EventData": {
"RuleName": "-",
"UtcTime": "2024-12-02 00:52:23.059",
"ProcessGuid": "{C784477D-04C6-674D-5C06-000000004B00}",
"ProcessId": 7592,
"Image": "C:\\Users\\george\\Desktop\\ezzz.exe",
"TargetFilename": "C:\\Users\\george\\AppData\\Roaming\\MyData\\DataLogs.conf",
"CreationUtcTime": "2024-12-02 00:52:23.059",
"User": "DESKTOP-B0T93D6\\george"
}
sigma_rule:a1021d4086a92fd3782417a54fa5c5141d1e75c8afc9e73dc6e71ef9e1ae2e9c
sigma_rule:8f179585d5c1249ab1ef8cec45a16d112a53f91d143aa2b0b6713602b1d19252