Repository navigation
feature: emit a redirect fingerprint when a target redirects to another host - #171
m0hamed541 wants to merge 4 commits into
Conversation
…er host When the first response of the scanned target is a 3xx whose Location is on a different host (a leading www. is ignored), emit one extra v3.fingerprint.*.service.library message: library_name: redirect library_version: the HTTP status code detail: the absolute destination URL The destination is read from the RedirectLocation plugin of the first output line, before the blacklist is applied. RedirectLocation stays blacklisted so it still does not turn the location into a library name. Same-host redirects (http to https, example.com to www.example.com, path redirects) emit nothing. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RRPn4p16aFe9YiRsnD6YgZ
| definitions.REDIRECT_FINGERPRINT_NAME, | ||
| str(status_code), | ||
| definitions.DEFAULT_FINGERPRINT_TYPE, | ||
| detail_override=destination, |
There was a problem hiding this comment.
Do not persist the raw destination URL verbatim into detail. The Location header of a redirect frequently points at a login page and can carry query strings or fragments containing sessions tokens/codes; the value is stored in the backend detail column (limit 4096) and logged at INFO. Keep only the scheme, host, and path (dropping query and fragment), and cap the length, so no credential-bearing material is recorded.
There was a problem hiding this comment.
This is now addressed in the head revision. _get_redirect_target feeds the destination through _clean_redirect_destination, which discards the userinfo/credentials, the query string, and the fragment (parse.urlunsplit(..., "", "")), and caps the result to REDIRECT_DESTINATION_MAX_LENGTH (2048, below the backend's 4096). The new tests testWhatWebAgent_whenDestinationHasQueryFragmentAndCredentials_keepsOnlySchemeHostPortAndPath and testWhatWebAgent_whenDestinationIsVeryLong_capsTheDetailLength cover both behaviors. Resolving this thread.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RRPn4p16aFe9YiRsnD6YgZ
Address the review comments on the redirect fingerprint: - A malformed Location (for example "http://[bad") raised ValueError out of _parse_emit_result and dropped every fingerprint of the target. The URL parsing is guarded, unexpected plugin value shapes are skipped, and the other fingerprints are still emitted. - Store only the scheme, host, port and path of the destination. The query string, the fragment and any userinfo can carry tokens or credentials and were stored in the fingerprint detail and logged. The result is capped to 2048 characters (the backend detail column holds 4096). - Keep scanning the remaining values and plugin entries when one resolves to the same host, instead of stopping at the first one. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RRPn4p16aFe9YiRsnD6YgZ
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RRPn4p16aFe9YiRsnD6YgZ
Summary
When the scanned target redirects to a different host, emit one extra fingerprint so the platform can show which port redirects and where to.
Context: a customer saw a PHP service on three domains that only answer on port 80 with a 301 to another site. WhatWeb saw the redirect but dropped it, and the technologies of the destination were recorded against the scanned domain with nothing explaining why.
How it works
RedirectLocationplugin of that line, resolved against the line's URL withurljoin, so relativeLocationvalues work.www.is ignored).httptohttps,example.comtowww.example.comand path redirects emit nothing.RedirectLocationstays inBLACKLISTED_PLUGINS: the generic path would turn itsstring(the URL) into a library name. The new code reads the plugin before that filter.v3.report.vulnerabilityis reported for the redirect fingerprint._get_msg_datagets an optionaldetail_override, used only by the redirect message. The detail is the bare URL because the frontend parses it to show the destination host.Tests
Two new tests with two fixtures (
redirect_output.json,same_host_redirect_output.json): a cross-host redirect emits exactly oneredirectmessage (301,http://www.rexel.com/) next to the normal fingerprints; a same-host redirect emits none.pytest tests/whatweb_test.py: 35 passed (28 existing + 7 new: redirect, same-host, malformed Location, unexpected plugin shape, query/fragment/credentials stripped, length cap, same-host value before a cross-host one).ruffandmypyclean.Not verified
[url, status, plugins]JSON shape comes from the existing fixtures. The Dockerfile clones upstream WhatWeb at build time, so a format change upstream would silently stop redirects from being emitted.feature/redirect-fingerprint. That one was built and scanned on a VM.feature/service-redirect-chip.Review feedback addressed
Location(e.g.http://[bad) no longer drops the target's fingerprints: URL parsing is guarded and unexpected plugin values are skipped.detailcolumn holds 4096).Still open
http://a.comtohttps://a.comtohttps://b.comemits nothing, because the first hop stays on the same host.agent/ostorlab/whatwebalso runs in groups next toosv/nuclei(e.g.ai_network_pentest). I did not check whether they consumev3.fingerprint.*.service.libraryand would look up a library namedredirect.🤖 Generated with Claude Code
https://claude.ai/code/session_01RRPn4p16aFe9YiRsnD6YgZ