T1681

Search Threat Vendor Data

Reconnaissance Last updated:

Detects adversary reconnaissance activity where threat actors query threat intelligence vendor services — such as VirusTotal, Shodan, Recorded Future, AlienVault OTX, or GreyNoise — to monitor whether their own infrastructure, malware samples, or campaign indicators have been detected and published. Since this technique primarily occurs outside the victim network, detections are indirect and focus on observable side effects: suspicious outbound connections to threat intel APIs from hosts with no legitimate business reason, correlation of known malicious IP indicators making threat intel queries visible through egress proxy logs, and rapid indicator rotation patterns following public threat intel disclosures. Adversaries have been documented replacing flagged indicators within days of publication, making behavioral correlation between threat intel release timestamps and infrastructure changes a secondary hunting signal.

What is T1681 Search Threat Vendor Data?

Search Threat Vendor Data (T1681) maps to the Reconnaissance tactic — the adversary is trying to gather information they can use to plan future operations in MITRE ATT&CK.

This page provides production-ready detection logic for Search Threat Vendor Data, covering the data sources and telemetry it touches: Microsoft Sentinel, Network Proxy / Firewall (CEF format), Microsoft Defender Threat Intelligence. The queries below are rated medium severity at low confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.

MITRE ATT&CK

Tactic
Reconnaissance
Technique
T1681 Search Threat Vendor Data
Canonical reference
https://attack.mitre.org/techniques/T1681/
Microsoft Sentinel / Defender
kusto
let ThreatIntelAPIs = dynamic([
    "virustotal.com", "api.virustotal.com",
    "api.shodan.io", "shodan.io",
    "api.recordedfuture.com", "app.recordedfuture.com",
    "api.greynoise.io", "viz.greynoise.io",
    "otx.alienvault.com",
    "urlscan.io", "urlscan.io",
    "malwarebazaar.abuse.ch", "bazaar.abuse.ch",
    "threatfox.abuse.ch",
    "mb-api.abuse.ch",
    "pulsedive.com",
    "api.threatminer.org",
    "www.hybrid-analysis.com", "api.hybrid-analysis.com",
    "tria.ge", "api.tria.ge",
    "any.run"
]);
let KnownSOCAccounts = dynamic(["svc-threathunting", "svc-siem", "soc-analyst", "siem-collector"]);
CommonSecurityLog
| where TimeGenerated > ago(7d)
| where isnotempty(RequestURL)
| extend AccessedDomain = tolower(extract(@"(?:https?://)?([^/:?#\\s]+)", 1, RequestURL))
| where AccessedDomain has_any (ThreatIntelAPIs)
| where SourceUserName !in~ (KnownSOCAccounts)
| where DeviceAction !in ("block", "deny", "drop")
| summarize
    QueryCount = count(),
    UniqueURLs = dcount(RequestURL),
    SampledURLs = make_set(RequestURL, 10),
    UserAccounts = make_set(SourceUserName, 10),
    BytesOut = sum(SentBytes),
    FirstSeen = min(TimeGenerated),
    LastSeen = max(TimeGenerated)
    by SourceIP, AccessedDomain
| join kind=leftouter (
    ThreatIntelligenceIndicator
    | where TimeGenerated > ago(30d)
    | where IsActive == true
    | where IndicatorType == "networkip"
    | summarize ThreatScore = max(ConfidenceScore), ThreatTypes = make_set(ThreatType, 5) by NetworkIP
) on $left.SourceIP == $right.NetworkIP
| extend RiskFlag = case(
    isnotempty(ThreatScore) and ThreatScore > 70, "KnownMaliciousSource",
    QueryCount > 100 and array_length(UserAccounts) == 1, "HighVolumeNonSOC",
    UniqueURLs > 20, "BroadRecon",
    "Low"
)
| where RiskFlag != "Low"
| project FirstSeen, LastSeen, SourceIP, AccessedDomain, QueryCount, UniqueURLs, SampledURLs, UserAccounts, ThreatScore, ThreatTypes, RiskFlag
| sort by ThreatScore desc, QueryCount desc

Monitors proxy and firewall logs (CommonSecurityLog) for outbound connections from internal hosts to known threat intelligence vendor APIs and platforms. Correlates source IPs against the ThreatIntelligenceIndicator table to flag when hosts with existing threat intelligence hits are querying these services — a pattern consistent with adversaries checking if their infrastructure has been detected and reported. Also flags high-volume, non-SOC queries suggesting automated reconnaissance.

medium severity low confidence

Data Sources

Microsoft Sentinel Network Proxy / Firewall (CEF format) Microsoft Defender Threat Intelligence

Required Tables

CommonSecurityLog ThreatIntelligenceIndicator

False Positives

  • Security Operations Center analysts performing daily threat hunting or indicator enrichment via threat intel APIs
  • Automated SOAR playbooks or SIEM enrichment workflows querying VirusTotal or similar platforms to enrich alerts
  • Vulnerability management or penetration testing tools performing infrastructure fingerprinting via Shodan
  • Security researchers and threat intelligence teams conducting legitimate campaign analysis
  • Endpoint protection platforms that perform cloud-based file reputation lookups through proxy-visible connections

Sigma rule & cross-platform mapping

The detection logic for Search Threat Vendor Data (T1681) above is provided in a vendor-neutral form so you can deploy it on any SIEM. The same logic is shipped here as native KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the following logsource:

logsource:
  category: network_connection
  product: windows

Browse the community-maintained Sigma rules for this technique:


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1VirusTotal API Indicator Self-Lookup via PowerShell

    Expected signal: Sysmon Event ID 3 (Network Connection) showing powershell.exe connecting to www.virustotal.com:443. Proxy logs (CommonSecurityLog / squid) showing HTTPS CONNECT to www.virustotal.com with User-Agent indicating PowerShell Invoke-RestMethod. DNS query (Sysmon Event ID 22) for www.virustotal.com.

  2. Test 2Shodan Infrastructure Reconnaissance via Python Script

    Expected signal: Linux auditd SYSCALL records for execve of python3 with the Shodan API script content. Network connection logs (firewall/proxy) showing outbound HTTPS to api.shodan.io:443 from the test host. DNS query log entry for api.shodan.io.

  3. Test 3Automated Multi-Vendor Threat Intel Sweep Simulating Adversary Self-Monitoring

    Expected signal: Network/proxy logs showing sequential outbound HTTPS connections to urlscan.io, threatfox-api.abuse.ch (abuse.ch), and api.greynoise.io within a 30-second window from the same source IP. Auditd SYSCALL records for execve of curl (or bash executing the script). DNS queries for all three domains in rapid succession.


Response Playbook

Triage

  1. Step 1: Identify the source host by IP — determine whether it is a workstation, server, or cloud instance. Run a reverse DNS lookup and cross-reference with CMDB to establish expected role.
  2. Step 2: Review the specific URLs accessed — extract the indicator being queried (hash, domain, IP, URL). Determine if it matches any known active threat intel reports, recent CVEs, or your organization's own infrastructure ranges.
  3. Step 3: Examine the user account making the requests. Is it a personal account, service account, or anonymous? Check last login events (SigninLogs) for unusual geography, impossible travel, or first-time access patterns.
  4. Step 4: Correlate query timestamps with recent public threat intelligence publications — check if the queried indicators match those mentioned in reports published within the past 7–14 days. This is the key behavioral signal for T1681.
  5. Step 5: Determine query frequency and pattern — one-time lookups suggest manual review; automated high-volume queries (>50 in an hour) suggest scripted/tooled reconnaissance. Check for API key usage in the request headers or query strings.
  6. Step 6: Check if the queried infrastructure (domain, IP, hash) belongs to your organization, a known threat actor group, or is entirely unrelated — this determines whether the adversary is performing self-monitoring or general threat intel gathering.

Containment

  1. If source IP belongs to known malicious infrastructure making queries: block the IP at the perimeter firewall and add to threat block lists. If source is an internal endpoint that has been compromised and is being used as a proxy for the adversary's queries, isolate it from the network.
  2. If evidence of automated API key usage is present in logs: revoke any threat intel API keys that may be shared with or stolen by the adversary. Rotate credentials for all threat intel platform accounts.
  3. If the queried indicator is your organization's own infrastructure: treat this as a strong indicator of pre-attack reconnaissance. Initiate review of the queried asset (domain, IP range, certificate) for potential takedown or rotation to deny the adversary operational intelligence.
  4. Implement egress filtering to require proxy authentication for threat intel API access, limiting it to SOC service accounts with known-good source IPs.

Evidence Collection

  1. Export full proxy/firewall logs for the source IP for at least 30 days — look for patterns of threat intel queries, infrastructure OSINT tools (Shodan, Censys), and domain registration services accessed from the same source.
  2. Capture network packet captures (PCAP) for ongoing connections from the source IP to threat intel vendor APIs to extract full HTTP request headers, including User-Agent strings and API keys that may identify the adversary toolset.
  3. If the source is an internal endpoint, collect: process execution logs (Sysmon Event ID 1), network connection logs (Sysmon Event ID 3), browser history, and PowerShell command history to identify which process initiated the queries.
  4. Document all indicators queried (hashes, domains, IPs) — cross-reference against active threat intelligence reports to build a timeline of what the adversary was checking and when relative to threat intel publication dates.
  5. Preserve authentication logs for the threat intel platform accounts (SigninLogs, AuditLogs) to determine if adversary-controlled accounts were created to access the platforms directly, distinct from proxy-based access.

Escalation Criteria

  • ! Escalate immediately if the queried indicators match your organization's own infrastructure — this indicates the adversary is specifically monitoring their attack surface against your environment.
  • ! Escalate if the source IP correlates with a known threat actor group in threat intelligence feeds, particularly APT groups documented using T1681 such as UNC3886 or Contagious Interview.
  • ! Escalate if infrastructure changes (domain deregistration, IP rotation, certificate replacement) are observed within 72 hours of the threat intel queries — this is the operational indicator that the adversary is actively evading detection.
  • ! Escalate if access to your organization's internal threat intelligence platform (e.g., MISP, OpenCTI, ThreatConnect) is detected from an unusual source, suggesting the adversary has infiltrated your own TI toolchain.

Investigation Guide

Forensic Artifacts

  • > Proxy access logs showing outbound HTTPS connections to threat intel vendor API endpoints with timestamps and byte counts
  • > DNS query logs (Sysmon Event ID 22, or DNS debug logs) for threat intel platform hostnames from non-SOC hosts
  • > Browser history files (SQLite format) on endpoints: Chrome History at %LOCALAPPDATA%\Google\Chrome\User Data\Default\History, Firefox places.sqlite at %APPDATA%\Mozilla\Firefox\Profiles\*.default\places.sqlite
  • > PowerShell ScriptBlock logs (Event ID 4104) containing Invoke-RestMethod or Invoke-WebRequest calls to threat intel APIs with embedded API keys
  • > Environment variables or configuration files on compromised hosts containing threat intel API keys (VirusTotal, Shodan, Recorded Future API keys)
  • > Scheduled task XML files (C:\Windows\System32\Tasks\) or cron jobs on Linux (/etc/cron.d/, /var/spool/cron/) automating periodic threat intel queries

Tuning Guidance

This detection has inherently low confidence because T1681 is a PRE-attack technique occurring outside the defender's visibility. Tune by: (1) Building and maintaining a SOC exclusion list of service accounts and workstations legitimately accessing threat intel APIs — this is the highest-value tuning action. (2) Focusing on the ThreatIntelligenceIndicator join — alerts where source IPs match known threat actor indicators are highest fidelity. (3) Adjusting the QueryCount threshold (currently 100/period) based on your environment's baseline — run the query without the threshold filter for two weeks to establish a baseline, then set the threshold at 3x the 95th percentile. (4) For indicator rotation hunting, the signal improves when correlated with public threat intel release dates — manually validate hits against recent publications from vendors like Mandiant, SentinelOne, or Google Threat Intelligence.


Hunting Queries

Hunts for scripted command-line invocations of threat intelligence vendor APIs using PowerShell, Python, curl, or wget — consistent with automated tooling an adversary might deploy on a compromised host to periodically poll threat intel status of their infrastructure.

Hunting — KQL
kql
// Hunt for PowerShell or scripted API calls to threat intel vendors from endpoints
DeviceProcessEvents
| where TimeGenerated > ago(30d)
| where FileName in~ ("powershell.exe", "pwsh.exe", "python.exe", "python3.exe", "curl.exe", "wget.exe")
| where ProcessCommandLine has_any (
    "virustotal", "api.virustotal",
    "shodan",
    "greynoise",
    "otx.alienvault",
    "urlscan.io",
    "malwarebazaar",
    "threatfox",
    "hybrid-analysis",
    "pulsedive"
)
| where ProcessCommandLine !contains "soc-" and ProcessCommandLine !contains "siem"
| project TimeGenerated, DeviceName, AccountName, FileName, ProcessCommandLine, InitiatingProcessFileName, InitiatingProcessCommandLine
| sort by TimeGenerated desc
Hunting — SPL
spl
index=endpoint sourcetype="XmlWinEventLog:Microsoft-Windows-Sysmon/Operational" EventCode=1
| where (Image like "%powershell.exe" OR Image like "%pwsh.exe" OR Image like "%python.exe" OR Image like "%curl.exe")
| where (CommandLine like "%virustotal%" OR CommandLine like "%shodan%" OR CommandLine like "%greynoise%" OR CommandLine like "%otx.alienvault%" OR CommandLine like "%urlscan.io%" OR CommandLine like "%malwarebazaar%" OR CommandLine like "%threatfox%" OR CommandLine like "%hybrid-analysis%")
| table _time, ComputerName, User, Image, CommandLine, ParentImage, ParentCommandLine
| sort -_time

Hunts for indicator rotation patterns — identifies threat intelligence indicators that have been published and then rapidly disappear from observed network telemetry, which may indicate the adversary noticed the publication and rotated the flagged infrastructure.

Hunting — KQL
kql
// Hunt for indicator rotation patterns — detect domains/IPs flagged in TI that subsequently disappear from DNS or network telemetry
let TIIndicators = ThreatIntelligenceIndicator
    | where TimeGenerated > ago(30d)
    | where IsActive == true
    | where IndicatorType in ("domainname", "url")
    | project IndicatorPublishTime = TimeGenerated, DomainName, ConfidenceScore
    | where ConfidenceScore > 60;
let PostPublicationWindow = 7d;
TIIndicators
| join kind=leftanti (
    DeviceNetworkEvents
    | where TimeGenerated > ago(30d)
    | where isnotempty(RemoteUrl)
    | extend ObservedDomain = tolower(extract(@"(?:https?://)?([^/:?#]+)", 1, RemoteUrl))
    | summarize LastObserved = max(TimeGenerated) by ObservedDomain
) on $left.DomainName == $right.ObservedDomain
| where IndicatorPublishTime < ago(3d)
| project IndicatorPublishTime, DomainName, ConfidenceScore
| sort by IndicatorPublishTime desc
Hunting — SPL
spl
| inputlookup threat_intel_domains
| rename domain AS indicator_domain
| eval publish_time = strptime(publish_date, "%Y-%m-%d")
| where publish_time > relative_time(now(), "-30d@d")
| join type=leftanti indicator_domain
    [search index=dns OR index=proxy earliest=-30d
    | eval observed_domain = lower(coalesce(query, url_domain, dest_host))
    | stats max(_time) AS last_seen BY observed_domain
    | rename observed_domain AS indicator_domain]
| eval days_since_publish = round((now() - publish_time) / 86400, 1)
| where days_since_publish > 3
| table indicator_domain, publish_date, days_since_publish, confidence
| sort -days_since_publish

Hunts for newly created accounts or first-time logins to threat intelligence SaaS platforms federated through Azure AD — adversaries have been documented creating accounts with threat intelligence vendors to directly query for their own campaign indicators, distinct from using compromised systems.

Hunting — KQL
kql
// Hunt for new accounts or first-time access to threat intel SaaS platforms via Azure AD sign-in logs
SigninLogs
| where TimeGenerated > ago(30d)
| where AppDisplayName has_any ("VirusTotal", "Recorded Future", "Mandiant Advantage", "CrowdStrike Falcon", "ThreatConnect", "Anomali", "EclecticIQ")
| summarize
    LoginCount = count(),
    UniqueIPs = dcount(IPAddress),
    IPList = make_set(IPAddress, 10),
    Countries = make_set(Location, 10),
    FirstLogin = min(TimeGenerated),
    LastLogin = max(TimeGenerated)
    by UserPrincipalName, AppDisplayName
| where FirstLogin > ago(14d)
| extend DaysSinceFirstLogin = datetime_diff('day', now(), FirstLogin)
| where DaysSinceFirstLogin < 14
| sort by FirstLogin desc
Hunting — SPL
spl
index=azure_ad OR index=o365 sourcetype="azure:monitor:aad" OR sourcetype="o365:management:activity"
| where like(lower(app_display_name), "%virustotal%") OR like(lower(app_display_name), "%recorded future%") OR like(lower(app_display_name), "%threatconnect%") OR like(lower(app_display_name), "%anomali%")
| stats min(_time) AS first_login, max(_time) AS last_login, count AS login_count, dc(ip) AS unique_ips, values(ip) AS ip_list, values(country) AS countries BY user, app_display_name
| eval first_login_readable = strftime(first_login, "%Y-%m-%d %H:%M:%S")
| eval days_since_first = round((now() - first_login) / 86400, 1)
| where days_since_first < 14
| table user, app_display_name, first_login_readable, days_since_first, login_count, unique_ips, ip_list, countries
| sort days_since_first

Atomic Red Team Tests

Test 1 VirusTotal API Indicator Self-Lookup via PowerShell
windows

Simulates an adversary using PowerShell and a VirusTotal API key to query whether a specific file hash or domain has been detected and reported — the core behavior of T1681. This test generates proxy-visible HTTPS traffic to api.virustotal.com from a non-SOC context.

Command

powershell
# Replace VT_API_KEY with a valid VirusTotal public API key for testing
$apiKey = "VT_API_KEY"
$indicator = "44d88612fea8a8f36de82e1278abb02f"  # Known EICAR test hash
$headers = @{"x-apikey" = $apiKey}
$url = "https://www.virustotal.com/api/v3/files/$indicator"
try {
    $response = Invoke-RestMethod -Uri $url -Headers $headers -Method GET
    Write-Output "Detection count: $($response.data.attributes.last_analysis_stats.malicious)"
    Write-Output "First submission: $($response.data.attributes.first_submission_date)"
} catch {
    Write-Output "API Error: $($_.Exception.Message)"
}

Cleanup

powershell
# No persistent changes — network-only test
Write-Output "Atomic test complete. Review proxy logs for api.virustotal.com connection from this host."

Expected Telemetry

Sysmon Event ID 3 (Network Connection) showing powershell.exe connecting to www.virustotal.com:443. Proxy logs (CommonSecurityLog / squid) showing HTTPS CONNECT to www.virustotal.com with User-Agent indicating PowerShell Invoke-RestMethod. DNS query (Sysmon Event ID 22) for www.virustotal.com.

Expected Detection

KQL detection should fire if the executing host's IP is not in the SOC exclusion list and is present in ThreatIntelligenceIndicator (if testing from a flagged IP). SPL detection should surface the proxy log entry with query_count increment.

Test 2 Shodan Infrastructure Reconnaissance via Python Script
linux

Simulates an adversary using a Python script with the Shodan API to enumerate open ports and services on their own command-and-control infrastructure to verify whether it has been indexed and flagged by Shodan — a documented adversary behavior pattern for monitoring infrastructure exposure.

Command

bash
# Requires: pip install shodan
# Replace SHODAN_API_KEY with a valid Shodan API key
python3 -c "
import urllib.request
import json
api_key = 'SHODAN_API_KEY'
# Query Shodan for an IP (use your own test IP, not a production system)
test_ip = '8.8.8.8'
url = f'https://api.shodan.io/shodan/host/{test_ip}?key={api_key}'
try:
    with urllib.request.urlopen(url) as response:
        data = json.loads(response.read())
        print(f'Hostnames: {data.get(\"hostnames\", [])}')
        print(f'Ports: {data.get(\"ports\", [])}')
        print(f'Tags: {data.get(\"tags\", [])}')
except Exception as e:
    print(f'Error: {e}')
"

Cleanup

bash
# No persistent changes — network-only test

Expected Telemetry

Linux auditd SYSCALL records for execve of python3 with the Shodan API script content. Network connection logs (firewall/proxy) showing outbound HTTPS to api.shodan.io:443 from the test host. DNS query log entry for api.shodan.io.

Expected Detection

SPL detection should surface the proxy/firewall log entry for api.shodan.io access from a non-approved source IP. The HighVolumeNonSOC flag would not trigger on a single request, but the BroadRecon flag may trigger if multiple vendor APIs are queried in sequence.

Test 3 Automated Multi-Vendor Threat Intel Sweep Simulating Adversary Self-Monitoring
linux

Simulates an adversary using a shell script to programmatically query multiple threat intelligence platforms for a specific domain or IP, consistent with automated tooling used to monitor whether campaign infrastructure has been flagged across vendors. This test demonstrates the breadth-of-query pattern that triggers the BroadRecon risk flag.

Command

bash
#!/bin/bash
# Simulates multi-vendor threat intel sweep — queries 5+ TI vendors for a test indicator
TEST_DOMAIN="example.com"  # Replace with a test domain; do not use production infrastructure
echo "[*] Querying threat intel vendors for: $TEST_DOMAIN"

# URLScan.io (public, no API key required for basic search)
curl -s "https://urlscan.io/search/#domain:${TEST_DOMAIN}" \
    -H "User-Agent: Mozilla/5.0" \
    -o /dev/null -w "[+] urlscan.io HTTP status: %{http_code}\n"

sleep 2

# ThreatFox (abuse.ch) — public search endpoint
curl -s -X POST 'https://threatfox-api.abuse.ch/api/v1/' \
    -H 'Content-Type: application/json' \
    -d "{\"query\": \"search_ioc\", \"search_term\": \"${TEST_DOMAIN}\"}" \
    -o /dev/null -w "[+] threatfox.abuse.ch HTTP status: %{http_code}\n"

sleep 2

# GreyNoise Community API (no key required)
curl -s "https://api.greynoise.io/v3/community/${TEST_DOMAIN}" \
    -o /dev/null -w "[+] greynoise.io HTTP status: %{http_code}\n"

echo "[*] Multi-vendor sweep complete. Check proxy logs for connections to urlscan.io, threatfox.abuse.ch, greynoise.io"

Cleanup

bash
# No persistent changes. Remove the script if saved to disk:
rm -f /tmp/ti_sweep_test.sh

Expected Telemetry

Network/proxy logs showing sequential outbound HTTPS connections to urlscan.io, threatfox-api.abuse.ch (abuse.ch), and api.greynoise.io within a 30-second window from the same source IP. Auditd SYSCALL records for execve of curl (or bash executing the script). DNS queries for all three domains in rapid succession.

Expected Detection

The BroadRecon flag (UniqueURLs > 20 threshold not met by this test but query breadth across vendors is visible) in both KQL and SPL detections. The multi-vendor sweep pattern in the hunting query for scripted API calls (Hunting Query 1) should surface this if curl is monitored via auditd or Sysmon on Linux.

Related Detections