An unusual scan signature

Last Tuesday my Snort sensor flagged a scan from a single source IP. The pattern did not match any of the standard scanner signatures I have rules for. It also did not match any nmap scan type I recognise. The mystery was useful enough as a diagnostic exercise that the writeup is worth sharing.

What the scan looked like

From my structured logs, the relevant entries:

ts=2000-01-25T03:14:01Z event=fw_drop src=203.0.113.7:53 dst=192.0.2.10:21 proto=tcp flags=SYN-FIN
ts=2000-01-25T03:14:01Z event=fw_drop src=203.0.113.7:53 dst=192.0.2.10:22 proto=tcp flags=SYN-FIN
ts=2000-01-25T03:14:01Z event=fw_drop src=203.0.113.7:53 dst=192.0.2.10:23 proto=tcp flags=SYN-FIN
ts=2000-01-25T03:14:01Z event=fw_drop src=203.0.113.7:53 dst=192.0.2.10:25 proto=tcp flags=SYN-FIN
... (about 200 destinations)

Four observations from this on first read:

Source port is 53. Most legitimate traffic from port 53 is DNS (server-side). Source-port 53 is sometimes used by scanners as an evasion technique — some firewalls are misconfigured to allow inbound traffic from any source port 53, on the assumption that DNS replies use that source.

Flags are SYN+FIN. This is not a valid TCP packet. SYN initiates a connection; FIN closes one. A packet with both is malformed by RFC 793. Different operating systems handle this packet in different ways, which makes it a useful probe for stack fingerprinting.

Multiple destination ports, one source. Standard scan pattern.

Timestamps are tightly clustered. All within a one-second window. This is fast — too fast for normal interactive use, slow enough to be an automated tool.

What I tried first

My first hypothesis was that this was nmap with a particular flag set. nmap's --scanflags option lets you specify arbitrary TCP flag combinations. I have rules for several common combinations.

The SYN+FIN combination is the SYN/FIN scan, an evasion technique documented in the nmap man page. It exploits the fact that some IDS rules look for SYN packets and miss SYN+FIN packets, and that some firewalls treat SYN+FIN differently than SYN. A scanner using this combination is deliberately trying to evade detection.

My Snort rule for SYN/FIN scans did not fire on this scan. Why?

Because my Snort rule, in its current form, matched on packets with SYN+FIN and destination port < 1024. It was scoped that way to reduce false positives on application traffic. The current scan was hitting random destination ports above 1024 as well, and the rule was missing the overall pattern.

This was the first lesson: my rule was too narrow. I have updated it.

What it might have been

The SYN+FIN combination is specific enough to narrow the candidate tools. The well-known options:

  • nmap with --scanflags SYNFIN. Possible.
  • Hping with crafted flags. Possible.
  • Nessus, which sometimes uses unusual TCP flag combinations to fingerprint services. Possible.
  • A custom tool. Possible.

I looked at the source IP. Whois showed it belonged to a residential cable-modem range in eastern Europe. The reverse DNS was a randomly-generated string. This is consistent with a compromised home computer running an automated scanner — exactly the demographic that operates from cable connections at 03:00 local time and produces high-volume undirected scanning.

This ruled out, in my own assessment, a targeted attacker. Targeted attackers do not scan from random eastern-european residential IPs at 3am with malformed packets and hope. They use cleaner techniques.

The most likely explanation is: a compromised home computer running a script, written by someone who knows about the SYN+FIN evasion trick, used as a node in a distributed scanning operation. The attacker is using many such nodes to scan many targets in parallel, building a database of vulnerable hosts that they will later attack from a different IP.

What I did about it

Four things, in order.

Updated my Snort rule to match the broader pattern. The new rule fires on SYN+FIN regardless of destination port:

alert tcp $EXTERNAL_NET any -> $HOME_NET any \
    (msg:"SCAN SYN-FIN scan"; \
     flags:SF; \
     classtype:attempted-recon;)

The flags:SF matches packets with both SYN and FIN set, regardless of other flags. This should catch the same pattern in future even if the destination port range changes.

Added a firewall rule to drop SYN+FIN packets at the kernel level, before they reach Snort. The rule is:

ipchains -A input -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP

This is belt-and-braces — Snort would already detect it, but dropping at the firewall is faster and saves cycles.

Reported the source IP to the responsible ISP. I sent a courteous email with the relevant log excerpts and timestamps. I do not expect immediate action, but creating an evidence trail at the ISP is the right thing to do, and occasionally produces results.

Audited my own services for what they would do if a SYN+FIN packet did reach them. The Linux 2.2 kernel handles malformed flag combinations correctly in my testing — the connection is not established, no resources are consumed, the packet is simply discarded. Some older or less robust stacks behave differently. Worth checking on any commercial or embedded systems on the network.

The general lesson

A scan signature that does not match anything you have a rule for is, in my experience, most often a known tool with a particular flag combination you have not catalogued. Almost all scans in the wild are produced by a small number of widely-used tools. The variety is in the configuration, not in the implementation.

The diagnostic process I followed — extract the exact pattern, rule out the obvious tools by reference to their known behaviour, characterise the source, propose a likely explanation — is essentially the same process I would apply to any unknown traffic. The discipline of writing it down has, in retrospect, helped me clarify the steps.

The last point: my rule was too narrow because I had scoped it to reduce false positives. The trade-off between sensitivity and specificity is the central tension in writing detection rules. Too narrow misses real activity. Too broad floods the alerting channel. The right balance is contextual — depends on what the rule is for, how it is reviewed, what the consequences of each failure mode are.

The rule update I made is a small example of this contextual judgement. The change is from one balance point to another, slightly different one. Different again next time the pattern shifts. The discipline is to keep adjusting based on real data.


Back to all writing