l1ackers
Not marked. Sign in and it follows you. Next: 057: A baseline scan, read honestly

~/tutorials/056-nikto-and-the-honest-banner.md

056: nikto, and the honest banner

The scanner trilogy closes where it began, at the Server header, with the question that decides how much of a scanner report you can act on. Lesson 054 established that the strongest scanner finding is said-so, the target's own testimony. This lesson asks the question that testimony has always begged: what happens when the target lies. The answer is the lesson. The scanner will believe it. Faithfully, verbatim, at machine speed, forever, and every finding downstream of the lie inherits the lie.

What this lesson is for

Calibration, the last turn. You now know what scanners can know, testimony and gaps and answered guesses, and what they cannot, meaning. What remains is the trust question, and it has a hard edge: version findings drive real decisions, patch schedules, severity calls, whether a client panics or sleeps, and a lying banner turns all of it into confident noise. This lesson receipts the lie at full size so the habit it teaches, verify the banner before you act on it, is something you have seen happen rather than something you were told.

What the reader meets

A server that lies on purpose, built for this lesson on the web lab page's wire. It is a dozen lines of Python, a current 2026 interpreter, serving one plain page. Its whole configuration is one overwritten method: the banner it sends says Apache/2.2.15 (Unix). That is the entire deception. No Apache exists anywhere in the container, and 2.2.15 was old when the internet was young, a version with famous holes and a long CVE list.

The truth and the lie, side by side. The truth is in the lab's build: python 3.12, stock http library, one handler class. The lie is in the response headers, receipted by whatweb from the scanner seat of the web lab page:

http://172.31.16.2:5002/ [200 OK] Apache[2.2.15], Country[RESERVED][ZZ],
HTTPServer[Unix][Apache/2.2.15 (Unix)], IP[172.31.16.2]

whatweb read the banner and reported an Apache. It found no Apache. There is no Apache. It found a string, and the string said Apache, and the fingerprinter's job is to report strings faithfully, so it did. And nikto, one step further, reads the version and checks it against its database of version ages:

+ Server: Apache/2.2.15 (Unix)
+ [600050] Apache/2.2.15 appears to be outdated (current is at least 2.4.68).

Two findings, both false in the way that matters. The server is not Apache. The version is not 2.2.15. Nothing about this box is vulnerable to anything Apache 2.2.15 was ever vulnerable to, because there is no Apache here to be vulnerable. And a scanner report based on these rows would recommend, in confident green and red, an Apache upgrade for a Python service, and severity rankings for holes that cannot exist on this machine.

The receipt's most important property is its silence on the other side: not one finding in the run says the banner might be false. Not one scanner on earth prints the column that would have saved the report, believes this or not, because that column is not a sensing question. It is the 055 lesson again, one tier-lesson deeper: the scanner reads what is said, and honesty is not said anywhere. It is verified, or it is assumed, and assuming it is how a twelve line Python file becomes an emergency Apache patch in somebody's Monday meeting.

The instrument

Why banners lie, because the motive is not exotic. Three reasons, in the order you will meet them.

Defense through ambiguity. Hardening guides since the nineties have recommended suppressing or faking the banner, on the theory that an attacker who cannot fingerprint cannot target. It does not work, fingerprinters read behavior now, protocol quirks and header order and timing, not just strings, but the recommendation survives and the banners get faked anyway. When you meet a lying banner in the wild, this is the most common reason: somebody followed old advice.

The proxy in front. Load balancers and CDNs routinely overwrite the Server header with their own, so the banner you read may name the edge, not the origin. This is not deception, it is architecture, but the finding it produces is the same shape: your version report is about the wrong machine. The whatweb receipt in lesson 054 read Apache 2.4.25 because DVWA runs Apache, and on a real deployment that same site behind a CDN might read as the CDN's nginx, version and all, and the DVWA Apache would be invisible to every banner reader on the internet.

The default nobody changed. Python's http.server, Werkzeug in debug, development servers of every species, announce themselves proudly, and half the banners on the real internet are just the truth of a tool nobody configured. The DVWA banner is this: honest, because it was never touched.

The response, for a tester, is one move taught three ways in this tier already. Verify before you act. Not because scanners are bad, they are testimony collectors and their recall is perfect, but because testimony is only as good as the witness. The cheap verifications, in escalating cost: read the behavior fingerprint, whatweb with higher aggression reads more than strings and may name the Python behind the Apache claim. Probe the protocol, a HEAD request, an OPTIONS, a deliberately malformed request, and watch what the error answers, because error pages confess what banners hide, stack traces name the true framework every time. And when it matters, the version finding that will drive severity in a report, hold it to the standard this whole site runs on: reproduce the claimed behavior, not just the claimed string. An Apache 2.2.15 with a known directory traversal finding that does not traverse is not an Apache 2.2.15, and one request settles it.

Try it

  1. Build the liar. The web lab page carries this lesson's server, banner overwrite and all, a dozen lines. Run it, run whatweb and nikto against it, and read your own report of an Apache that does not exist. Then fix the report by hand: write the two findings' truth, and notice that writing it required knowing the build, which is the point, the truth was never in the bytes.
  2. Turn the liar honest. Edit the server to send a banner that is true, run both scanners again, and compare the two reports. The honest report is smaller, or the same, and never larger, and the difference is exactly the noise the lie generated. That difference, measured once by hand, is the reason the verify habit pays for itself.
  3. Meet a real proxy lie. Pick a large site you use, read its Server header with curl -I, and note who the banner names. Then reason, in one written sentence, about whether that named software is plausibly the actual origin or the edge in front of it. You are practicing the architecture-shaped lie, and the one-sentence habit is the professional version of this whole lesson.
Reveal the answer

The banner trust card, the working response to every version finding a scanner hands you:

WHEN A REPORT SAYS: "Server: X/Y.Z (outdated)"

1. WHO said it?        one header string, from one response, quoted verbatim
2. WHO ELSE says it?   behavior fingerprint, error pages, protocol quirks,
                       any second source that does not read the same string
3. DOES IT ACT like X? one probe drawn from X's known behavior or known holes
4. WHAT IS IT IN FRONT OF? the banner may name the edge, not the origin,
                       and the origin's version was never in your bytes
5. THEN act.           severity, patch advice, client panic level

Worked with this lesson's liar:
  1. the string said Apache/2.2.15      -> a string
  2. nothing else says Apache           -> a lie by a dozen-line python
  3. no Apache behavior exists to probe -> the probe cannot even run
  4. nothing in front, bare container   -> the lie is whole
  5. act: on nothing. Report the truth: python 3.12, honest banner absent.

The card's quiet law is in step 1's phrasing. Every version finding reduces to one string from one response, and the entire question of trust is whether any second source agrees. Scanners print the string and stop, because agreement is not a sensing question, it is the work, and the work is why you are in the room. Keep the card with the 054 kinds-of-yes and the 055 cannot-know ledger: those two taught you how to read a report, this one teaches you when to distrust its best row, and together they are the complete tester's relationship with automated output, in three cards that fit on one page.

What this lesson does not claim

The verify habit has a cost, and honesty names it. Probing every version finding takes time, and most banners on most days are honest defaults nobody touched, which means the paranoid path wastes your afternoon on the truthful ninety percent. The professional calibration is triage, not suspicion: verify the findings that will carry severity in a report, the ones a client will act on, the ones you would be embarrassed to retract. The scanner remains the cheapest testimony collector you own, and this trilogy's teaching order was deliberate, can-know first, cannot-know second, trust last, because the trust question only makes sense once you know what the knowledge was made of. The banner is honest until proven otherwise, the proof is one probe, and the probe is yours.

Not marked. Sign in and it follows you. Next: 057: A baseline scan, read honestly
l1ackers · shell this is a way in, not a requirement
$