How to check a PCAP against your threat-intel (IOC) lists
An indicator list is only useful if it is checked against the traffic you actually have. Matching a capture by hand is quick for one list and one file, but the details matter: subdomains, address ranges, names that only appear in TLS, and files that only show up as bytes in a stream.
In PCAPNG Analyzer Pro you paste or load a list once, in whatever format the feed uses, and every capture is checked against it automatically: addresses, domains in DNS, TLS, QUIC and HTTP, file hashes and fingerprints. Re-scan applies a new list to the captures you’ve already analysed.
See a sample incident report →1. Prepare the lists
Feeds and incident reports rarely arrive in a form a filter accepts. Before matching, put one indicator per line and split them by type: ips.txt (addresses and CIDR ranges), domains.txt, hashes.txt (SHA-256) and fingerprints.txt (JA4, JA3 or HASSH). Along the way:
- Re-fang defanged entries:
1.2.3[.]4becomes1.2.3.4, andhxxps://becomeshttps://. - Reduce URLs to their host name. A capture of HTTPS traffic won't show the path anyway.
- Drop comment lines, ports and trailing whitespace.
- Note where each list came from and how old it is. Addresses go stale fastest: yesterday's C2 server is often today's legitimate cloud customer.
2. Match addresses
tshark accepts a set of addresses and ranges, separated by commas. paste builds it from the file:
tshark -r capture.pcapng -Y "ip.addr in {$(paste -sd, ips.txt)}" \
-T fields -e frame.time -e ip.src -e ip.dst -e _ws.col.Protocol
CIDR ranges such as 203.0.113.0/24 work inside the set. Use ipv6.addr for an IPv6 list. A match tells you an address appeared in a packet, in either direction; the judging step decides what that means.
3. Match domain names
A name can appear in three places: a DNS query, a TLS or QUIC server name, and an HTTP Host header. Check all three, and match subdomains too: a listing for evil.example should catch cdn.evil.example. This builds one filter covering all of them from domains.txt:
re=$(sed 's/\./\\./g' domains.txt | paste -sd'|')
filter=$(printf 'dns.qry.name matches r"(^|\\.)(%s)$" || tls.handshake.extensions_server_name matches r"(^|\\.)(%s)$" || http.host matches r"(^|\\.)(%s)$"' "$re" "$re" "$re")
tshark -r capture.pcapng -Y "$filter" \
-T fields -e frame.time -e ip.src -e dns.qry.name \
-e tls.handshake.extensions_server_name -e http.host
The r"..." raw strings keep the regular expression's backslashes intact. When a DNS query matches, note the addresses in its answer and match those too: the connection that follows a lookup is the activity that matters, and it shows only an address.
4. Match file hashes
File hashes can only be matched for files that crossed the wire in clear text, which in practice means plain HTTP. Export every HTTP object, hash the files and compare:
tshark -r capture.pcapng -q --export-objects http,objects
sha256sum objects/* | grep -i -F -f hashes.txt
A file must be complete to match. A download that the capture caught only part of, or one cut short, hashes differently from the original. Files fetched over HTTPS are invisible to this step, however the list is written.
5. Match TLS and SSH fingerprints
Fingerprints identify client software rather than infrastructure, so they keep matching when an attacker moves servers. Quote each value and test the fields that apply:
set=$(sed 's/.*/"&"/' fingerprints.txt | paste -sd,)
tshark -r capture.pcapng \
-Y "tls.handshake.ja4 in {$set} || tls.handshake.ja3 in {$set} || ssh.kex.hassh in {$set}" \
-T fields -e frame.time -e ip.src -e ip.dst -e tls.handshake.extensions_server_name
The JA3 and JA4 guide explains why a JA3 from a modern browser rarely matches twice.
6. Judge a hit
A match is the start of the investigation. For each hit, find the conversation and answer:
- Which direction? An internal host connecting out to a listed address is very different from a listed scanner knocking on your firewall.
- Did the connection complete? A SYN that was never answered, or a DNS lookup that a sinkhole answered, is weaker evidence than a full TLS session with data.
- How much, and how often? One connection at login, a steady timer, or a large upload each tell a different story.
- Is the indicator still good? Shared hosting, CDNs and cloud providers recycle addresses. A hit on a broad range or an old address needs corroboration from a name, a fingerprint or a hash.
- Which host? Behind NAT or a proxy, the address in the capture may be the gateway rather than the machine responsible.
Feeds contain errors, stale entries and over-broad ranges. Record which list and which entry produced each hit, so the conclusion can be traced and challenged later.
Manual method vs PCAPNG Analyzer
Manual method
- Clean and split each list by type.
- Run address, name, hash and fingerprint filters.
- Follow the DNS answers to the connections that came next.
- Judge each hit by direction, completion and volume.
- Repeat for every new capture and every list update.
With PCAPNG Analyzer
- Create a list in Settings → Threat Intel, and paste or load the indicators, defanged or not.
- Analyse captures as usual: a match raises a finding naming the list, the indicator and where it appeared. Re-scan all checks older captures.
- Follow the stream or export the matching packets, and click the indicator to see every capture it appears in.
Lists accept the formats feeds actually use: bare addresses (with or without a port), CIDR ranges, domains (each covering its subdomains), URLs reduced to their host, defanged indicators, hosts-file blocklists and CSV rows. They also accept SHA-256 file hashes and JA3, JA4 and HASSH fingerprints. Matching covers IP traffic, DNS lookups, TLS and QUIC server names, HTTP Host headers, the hashes of files transferred over plain HTTP, and TLS and SSH client fingerprints. Each list has its own severity, and the finding takes the most severe list that matched. Lists are only ever imported by you; the app never fetches a feed, and nothing about your traffic leaves the server.
Check every capture against your own intelligence
Import your lists once and every capture is checked automatically, with the lists and the traffic kept on your own computer or server.
Compare Free and ProSelf-host it