l1ackers
Not marked. Sign in and it follows you.

~/tutorials/026-a-version-string-that-lies.md

026: A version string that lies

Lesson seventeen treated the version string as a claim you cannot verify from the network. This lesson is the day the claim is wrong on purpose, and the ways you catch it anyway. The ground moves here: up to now the scanner's worst vice was guessing. From here it can be fed.

How a string lies

Three ways, in the order you will meet them.

Stale. The package updated, the daemon never restarted, and the banner still names the old version. The machine is patched and the network says it is not. Harmless, common, and the reason "patched" is a claim about processes, not packages.

Edited. Somebody rewrote the banner to feed scanners. Shortened to nothing, changed to a different product, or pinned to a version that was never vulnerable. This is a real defensive technique and it makes every version column a negotiation: the string is what the operator chose to tell you.

Forged. The thing answering on the port is not the product the banner names. A honeypot wearing a banner, a backdoor with a copied one, or a wrapper proxying the real service elsewhere. The string is bait, and the port is the trap.

The tells, from the network

You cannot break the lie from a distance, but lies leak, and the tells are comparisons:

  • Against the protocol. A banner claiming OpenSSH 9.6 that mishandles an edge of the handshake a real 9.6 handles is caught by behaviour, not version. The claim and the conduct disagree, and conduct is the harder thing to fake.
  • Against the platform. nginx 1.24.0 (Ubuntu) is a specific package of a specific distribution. Version and packaging that never shipped together is a forged string assembled carelessly, and packaging histories are public.
  • Against a second port. Two doors claiming the same product should agree about everything else too: timing, ordering, TLS behaviour. nmap -sV 127.0.0.1 | grep nginx shows two here, and on a real host the pair is a free corroboration check.

The tell you cannot get here

This shell answers from a snapshot, so the strongest tell, asking the host itself, does not exist on this side of the glass. That is the honest limit of this lesson: I can show you the shape of the lie and the comparisons that catch it, and the ground truth comparison you will run at home, ssh in one window and scan in the other. The gap between those two answers is the whole technique, and no snapshot can demonstrate it for you.

The habit

Trust version strings the way you trust introductions: useful, usually true, occasionally cover. Never build a finding on the string alone when a comparison is available, and always record which comparisons you ran. A report that says "banner claims X, behaviour consistent with X, packaging plausible" is worth ten that say "X".

Try it

Each of these has one answer, and the shell gives it to you. Check yourself.

  1. Pull the ssh line and the two nginx lines from one -sV scan. Say which fields of each line are the claim, and which are the scanner's measurement.
  2. The packaging tell: read the exact strings and say what a forger would have to check before inventing a plausible sibling. The distro histories are public, which is the point.
  3. Two ports claim nginx here. On a live host, name two comparisons between the pair that would expose one of them lying.
  4. Invent a version string that could never have shipped: pick a version and a packaging that do not match anything real. Now write the finding that catches it, using the tells above and the four-field shape from lesson twenty-five.

The snapshot cannot lie to you about being a snapshot. Its banner lines are claims by a host that changes, and the stamp is on every answer.

Not marked. Sign in and it follows you.
l1ackers · shell this is a way in, not a requirement
$