Internet Scanning in VirusTotal: hunting infrastructure by what it exposes

Until now, an IP report in VirusTotal told you a lot about reputation, who hosts it, what resolves to it (passive DNS) and which files talk to it. It told you nothing about what the machine itself was running.

VirusTotal now scans the public IPv4 space every day and stores, for each IP, the open and closed ports, the service behind each port, its banner and its fingerprints. All of it is searchable. In this post we cover what you will find in the reports and how to use it to hunt and pivot, with real examples worked end to end.

What we store for every port

Each IP now carries a list of port records. Every record has two layers: the lifecycle of the port and the latest analysis of the service running on it.

Field
What it tells you

Status
open, closed or recently closed. Updated daily.

First seen / Open since / Last seen open
When we first saw the port, since when it has been open without interruption, and the last day we saw it open.

Protocol, product and version
The service identified on the port, e.g. ssh / OpenSSH / 9.6p1 Ubuntu 3ubuntu13.19.

CPEs
Standard CPE identifiers for the product, useful to map the service to known vulnerabilities.

Banner
The raw banner returned by the service.

OS and device type
Operating system or device class inferred from the service (Linux, Windows, router, firewall…).

Fingerprints
SSH host key fingerprints and RDP fingerprints.

Protocol details
HTTP status line and response headers, SMTP capabilities, IMAP/POP3 capabilities and similar protocol-specific output.

The "closed" side matters as much as the "open" one. When a port stops answering we don't delete it: we keep the record, flip the status and preserve the last date it was seen open. That is what lets you answer "when did this C2 go dark?" weeks after it happened.

All of this lives in the new Ports tab of the IP report, with a table of every port we know about and a detailed card per port.

Searching the scanning data

Everything above is indexed and can be queried from the search bar or the API with entity:ip plus the new modifiers:

Modifier
Example
Matches

port
entity:ip port:3389
IPs with any information on that port

open_port / closed_port
entity:ip open_port:22
IPs where the port is currently open / closed

port_status
entity:ip port_status:open
Filter by port status

port_protocol
entity:ip port_protocol:ssh
Protocol running on the port

port_service_product
entity:ip port_service_product:openssh
Product name

port_service_version
entity:ip port_service_version:8.2p1
Product version

port_service_cpe
entity:ip port_service_cpe:"cpe:/o:linux:linux_kernel"
CPE identifier

port_banner
entity:ip port_banner:mikrotik
Text inside the service banner

os_type / device_type
entity:ip device_type:router
Detected OS / device class

fingerprint
entity:ip fingerprint:"SHA256:..."
SSH or RDP fingerprint

The part we like most is the bracket syntax. On a host with several services, port_service_product:nginx port_service_version:1.24.0 would match even if nginx lives on one port and version 1.24.0 belongs to something else on another. Putting the port in brackets pins every condition to the same service:

entity:ip port_service_product[80]:nginx port_service_version[80]:1.24.0
entity:ip os_type[445]:Windows
entity:ip port_banner[21]:mikrotik
entity:ip port_service_cpe[22]:"cpe:/o:linux:linux_kernel"

The bracket form works for port_banner, port_protocol, port_service_product, port_service_version, port_service_cpe, os_type, device_type and fingerprint. And since these are regular modifiers, you can combine them with everything you already use for IPs: asn, country, ssl_subject, jarm, threat_actor, collection, have and so on.

A word about noise

Our first instinct was to hunt C2 frameworks by their default ports. entity:ip open_port:50050 (Cobalt Strike's default team server port) returned more than 1.5 million IPs. A quick look at the results explains why: many of those hosts answer on every port we probe, including 4444, 5552, 6606 or 8808 at the same time.

An open port on its own is a weak signal. What makes a query useful is what is behind the port: a product, a version, a banner string or a fingerprint.

Pivoting on an SSH host key: a real example

This is where the fingerprints earn their place. An SSH host key is generated when a server is installed. If two IPs present the same key, you are usually looking at the same machine that moved, or at a server cloned from the same

[…]
Content was trimmed to protect the source. Please visit the original article for the full text.

This article has been indexed from VirusTotal Blog

Read the original article: