Vulnerability Assessment with Nmap, OpenVAS, and Nikto
I ran a layered vulnerability assessment combining Nmap service discovery, OpenVAS authenticated scanning, and Nikto web checks, then triaged findings by CVSS 3.1 base score. The workflow converted a raw scan dump of 200+ findings into a business-ranked remediation queue.
The core idea is that no single scanner sees the whole picture. Nmap tells you what is reachable and what version banners claim to be running. OpenVAS, given credentials, logs into each host and checks the actual installed patch level against tens of thousands of known CVEs. Nikto hammers web servers specifically, catching dangerous default files, outdated components, and misconfigurations that generic scanners gloss over. Running all three, then cross-correlating the results, is what turns a noisy 200+ item dump into a short, evidence-backed list an admin can actually act on.
Objective & Context
Scanning without prioritization just produces noise. This lab pairs broad discovery with credentialed depth and a scoring rubric, implementing CIS Control 7 (Continuous Vulnerability Management) and feeding the NIST SP 800-40 patch lifecycle.
The assessment answers four questions in order: what is on the network (discovery), what is it vulnerable to (scanning), how bad is each finding (scoring), and what gets fixed first (prioritization). That last step is where most beginner writeups stop short, a report sorted by scanner severity alone ignores exposure, exploitability, and asset value, which is how teams end up patching a medium on an internal test box while a critical sits on the DMZ web server.
- T1595.002 Vulnerability Scanning, the same technique adversaries use, run defensively.
- T1190 Exploit Public-Facing Application, prioritizes internet-reachable critical CVEs first.
Mapping the workflow to MITRE ATT&CK matters because it mirrors what a real attacker does during reconnaissance. If your defensive scan finds it first, the attacker's scan tells them nothing new.
The overall shape follows NIST SP 800-115's assessment phases: planning (scope and rules of engagement), discovery (host and service enumeration), vulnerability analysis (the scans themselves), and reporting (the ranked queue). Keeping those phases explicit matters for repeatability, the point of building this as a workflow rather than an ad-hoc scan is that the same steps can run quarterly and produce comparable results, which is what CIS Control 7 actually asks for: a continuous process, not a one-time sweep.
One scoping decision worth stating up front: this lab covers vulnerability assessment, not penetration testing. The goal is breadth, find and rank everything, rather than depth on a single exploit chain. No payloads are run and no access is established beyond what the scan credentials already grant; exploitation belongs to a different engagement with a different authorization.
Learning Objectives
- Confirm scan scope and written authorization before touching any target.
- Discover services and run NSE vulnerability scripts with Nmap.
- Launch a credentialed OpenVAS scan and track its progress.
- Run web-application checks with Nikto.
- Score consolidated findings with CVSS 3.1 vectors.
- Build a ranked remediation queue from unique CVEs.
Environment & Prerequisites
Prerequisites
- Kali or BackBox scanner with Nmap 7.94 and the NSE vuln category.
- OpenVAS/GVM 22.4 with synced feeds; Nikto 2.5.
- Authorized target subnet, an exclude list, and credentialed scan accounts.
- Written authorization defining scope, window, and contacts.
- A place to store reports outside the scanner.
Before scanning anything, confirm the tooling is actually the version you think it is and that the OpenVAS feed data is current. A vulnerability scanner with a stale feed database is worse than no scanner at all, it reports "no findings" with total confidence while missing every CVE published since the last sync.
nmap --versionnikto -Version 2>&1 | head -2gvm-cli --gmp-username admin socket --xml "<get_version/>"Nmap version 7.94 ( https://nmap.org )
Nikto Versions
___________________________________________________________
Nikto Version 2.5.0
<get_version_response status="200" status_text="OK"><version>22.4</version></get_version_response>
Sync the Greenbone feeds and check that the sync actually completed. Five feed types matter here: NVT (the vulnerability tests themselves), SCAP, CERT, GVMD_DATA, and Notus (the local-security-check data OpenVAS uses for package-level detection on scanned hosts). They sync separately, and a partial sync produces confusing gaps in results later, syncing only GVMD_DATA/SCAP/CERT while skipping NVT and Notus leaves the scanner with metadata but stale or missing checks.
sudo greenbone-feed-sync --type nvtsudo greenbone-feed-sync --type notussudo greenbone-feed-sync --type scapsudo greenbone-feed-sync --type certsudo greenbone-feed-sync --type gvmd-datatail -n 5 /var/log/gvm/gvmd.logExpected output:
Synchronizing GVMD_DATA...
Update complete.
Common mistake: running the scanner as a normal user and wondering why SYN scans silently degrade to slow TCP-connect scans. Nmap needs root (or the CAP_NET_RAW capability) for -sS; OpenVAS's feed sync and gvmd likewise expect sudo. Check id before you blame the tool.
Set up the dedicated scan accounts before anything else, and make them read-only wherever possible. On the Linux targets that means an unprivileged user whose only job is to let OpenVAS log in and read package lists; on Windows it is a domain service account in a dedicated "Vulnerability Scanning" AD group, never Domain Admins as a lazy shortcut. Using personal admin credentials for scanning is both a security problem (credentials now live in the scanner's credential store) and an audit problem (scan logins become indistinguishable from admin activity).
ssh [email protected] 'sudo useradd -m -s /bin/bash vulnscan && sudo mkdir -p /home/vulnscan/.ssh'ssh [email protected] 'sudo cp ~/.ssh/authorized_keys /home/vulnscan/.ssh/ && sudo chown -R vulnscan:vulnscan /home/vulnscan/.ssh && sudo chmod 700 /home/vulnscan/.ssh'ssh [email protected] 'id && dpkg -l | wc -l'uid=1001(vulnscan) gid=1001(vulnscan) groups=1001(vulnscan)
2147
How to verify: the test login must succeed from the scanner host, not just from your workstation, firewalls and SSH AllowUsers lists often treat them differently. The dpkg -l count proves the account can authenticate and read the package database, which is the prerequisite OpenVAS's local security checks need, but it does not prove the scanner's authenticated checks will succeed. Only a real scan result confirms that: after the first run, look for the per-target log result "It was possible to log into the remote host using the provided credentials" (step 2). A successful dpkg -l plus that log line together mean credentialed checks are working.
The lab target set for this run was deliberately heterogeneous so each tool had something to chew on: a mix of Ubuntu servers (web, SSH, SMB), one unpatched Windows box, and a few embedded devices that respond to pings but host no scannable services. Knowing roughly what should be on the subnet also gives you a sanity check at the end, if discovery finds 22 hosts and your inventory says 21, that delta is itself a finding worth chasing before the report goes out.
Step-by-Step Execution
0. Confirm scope and written authorization
Vulnerability scanning is indistinguishable from attack reconnaissance on the wire, so the first "command" of any assessment is paperwork: a signed rules-of-engagement document listing the exact subnets in scope, the scan window, and any fragile hosts to exclude (printers, legacy PLCs, medical devices). Then encode that scope in a file so no fat-fingered CIDR ever expands it.
cat targets.txtcat exclude.txtExpected output:
# targets.txt - authorized scope, engagement ROE-2026-014, window 09:00-17:00
192.168.20.0/24
# exclude.txt - fragile hosts excluded per the ROE
192.168.20.5 # legacy print server
192.168.20.240 # building controller
Why two files: Nmap's -iL input files do not support !address exclusion lines, that syntax works on some other tools but Nmap treats a !192.168.20.5 line as a (failed) target specification, silently scanning nothing for it while the exclusion you expected never happens. Exclusions belong in a separate file passed with --excludefile. Verify the effective target set before launching anything:
nmap -sL -n -iL targets.txt --excludefile exclude.txt | grep "Nmap scan report" | wc -lExpected output:
252
How to verify: pass the target list explicitly (nmap -iL targets.txt --excludefile exclude.txt) rather than typing a raw subnet at the prompt, and diff the generated target list against the ROE before launching. Two minutes here prevents the career-defining mistake of scanning an out-of-scope production range.
What this teaches: scope confirmation is the difference between an assessment and an incident.
1. Discover services and run NSE vuln scripts
Discovery runs in two passes. First a fast host-discovery sweep to see what is alive, then a deeper service scan with version detection (-sV) and the vuln NSE script category, which runs checks for well-known issues (MS17-010, Heartbleed, slowloris, default credentials) against every detected service. Splitting it this way keeps the noisy, slow checks aimed only at live hosts.
sudo nmap -sn -iL targets.txt --excludefile exclude.txt -oA host-discoveryExpected output:
Nmap scan report for 192.168.20.10
Host is up (0.0012s latency).
Nmap scan report for 192.168.20.30
Host is up (0.00098s latency).
Nmap done: 254 IP addresses (22 hosts up) scanned in 4.17 seconds
With the live-host list in hand, run the full service and vulnerability scan. -oA vuln-scan writes all three output formats (.nmap, .gnmap, .xml) from one run, the XML matters later because it is what you parse for cross-tool correlation. The scan reuses the same scope and exclusion files from step 0, never a bare subnet, so the fragile hosts stay excluded:
sudo nmap -sV --script vuln -iL targets.txt --excludefile exclude.txt -oA vuln-scanNmap scan report for 192.168.20.30
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0
| http-slowloris-check:
| VULNERABLE:
| Slowloris DOS attack
| State: LIKELY VULNERABLE
| IDs: CVE:CVE-2007-6750
443/tcp open ssl/http nginx 1.18.0
| ssl-heartbleed:
| VULNERABLE:
| The Heartbleed Bug is a serious vulnerability in OpenSSL
| State: VULNERABLE
| IDs: CVE:CVE-2014-0160
How to verify: every host from the discovery sweep should appear in the full scan output, and grep "VULNERABLE" vuln-scan.nmap should list only script findings, not errors. Treat both State: VULNERABLE and State: LIKELY VULNERABLE as script-level verdicts, not proof of exploitation: VULNERABLE means the script's check fired, LIKELY VULNERABLE means it inferred from version numbers, and neither means an exploit was run or would succeed. Corroborate either one before it goes in the report.
Common mistake: running -script vuln against a /24 with no rate limiting during business hours. Aggressive NSE scripts plus default timing can saturate a small office link or crash fragile embedded services. Add --max-rate 500 or drop to -T3 on anything production-adjacent.
TCP alone is not the whole story, DNS, SNMP, NTP, and IPsec all live on UDP, and UDP services carry their own CVE set. A full 65535-port UDP scan is painfully slow, so scan the top UDP ports only and accept the trade-off explicitly rather than skipping UDP entirely:
sudo nmap -sU --top-ports 50 -iL targets.txt --excludefile exclude.txt -oA udp-scanNmap scan report for 192.168.20.10
PORT STATE SERVICE
53/udp open domain
161/udp open|filtered snmp
Nmap done: 22 IP addresses (22 hosts up) scanned in 312.44 seconds
Note the open|filtered state: UDP has no handshake, so silence is ambiguous. An open SNMP on 161/udp is worth a follow-up probe with default community strings (snmpwalk -v2c -c public 192.168.20.10 in a lab you own), a readable SNMP tree leaks the full interface table, running processes, and often device credentials, and it is one of the most common real-world findings on unmanaged gear.
What this teaches: discovery before depth: you cannot assess hosts you have not found.
2. Launch a credentialed OpenVAS scan
Credentialed scanning is where the real depth comes from. An uncredentialed network scan can only guess at vulnerabilities from banners and probe responses; a credentialed scan logs in over SSH or SMB, enumerates installed packages, and matches exact versions against the CVE feed. This routinely triples the finding count, and most of the new findings are the local privilege-escalation and missing-patch issues that actually matter.
In the GVM web UI (https://127.0.0.1:9392), create the credential under Configuration → Credentials (an SSH key pair for Linux targets, a domain service account for Windows), then a target under Configuration → Targets referencing the scope file's range and the credential, and finally a task under Scans → Tasks using the "Full and fast" scan config. Everything the UI does is also scriptable over GMP, which is how the task was started and polled here:
gvm-cli --gmp-username admin socket --xml "<start_task task_id='UUID'/>"Expected output:
<start_task_response status="202" status_text="OK, request submitted"><report_id>9f3c2a1e-7b4d-4e8a-b2c1-5d6e7f8a9b0c</report_id></start_task_response>
Poll task status until it reports Done. A full /24 credentialed scan with "Full and fast" typically takes 40 to 90 minutes depending on host count and how many NVTs match each service.
gvm-cli --gmp-username admin socket --xml "<get_tasks task_id='UUID'/>" | grep -o '<status>[^<]*</status>'<status>Running</status>
<status>Running</status>
<status>Done</status>
A word on scan-config choice, because it silently controls result quality. "Full and fast" runs the full NVT set with mostly safe checks; "Full and fast ultimate" adds more intrusive tests that can hang or crash fragile services. For a first pass on anything production-adjacent, "Full and fast" is the right call. Also note the report's QoD (Quality of Detection) column: a finding at 30% QoD is a banner-based guess, while 99% means OpenVAS verified the vulnerable package is installed. Filtering everything below 70% QoD into a "needs manual confirmation" bucket is the single fastest false-positive reducer in the whole workflow.
Then pull the report and count findings by severity class to get the shape of the problem before reading a single line:
gvm-cli --gmp-username admin socket --xml "<get_reports report_id='9f3c2a1e-7b4d-4e8a-b2c1-5d6e7f8a9b0c' format_id='c1645568-627a-11e3-a660-406186ea4fc5'/>" > report.xmlpython3 -c "import sys,base64,re; x=open('report.xml').read(); m=re.search(r'<report[^>]*>(.*?)</report>', x, re.S); open('report.csv','w').write(base64.b64decode(m.group(1)).decode())" && head -2 report.csvawk -F'","' 'NR>1 {print $4}' report.csv | sort | uniq -c | sort -rn 142 Medium
52 High
4 Critical
Why the decode step: GMP embeds the generated report base64-encoded inside the <get_reports_response> XML. Writing the raw response to report.csv and parsing it would analyse XML wrapper text, not findings, so the content is extracted and decoded first. The format_id above is the built-in "CSV Results" report format; list the formats available on your GVM with <get_report_formats/> if it differs.
How to verify credentials worked: in the report, look for the log-level result "It was possible to log into the remote host using the provided credentials" per target. If a host shows zero local-security-check NVTs but the OS was detected, the credential failed, re-test the SSH login by hand before re-scanning, because an "all clear" from a failed-auth scan is a false negative, not a clean bill of health.
What this teaches: credentialed scans trade setup effort for dramatically better accuracy.
3. Web-app checks with Nikto
OpenVAS covers the host; Nikto covers the web server's attack surface specifically: dangerous default files (/server-status, phpMyAdmin leftovers, backup archives), outdated server software, missing security headers, and known CGIs. Point it at every HTTP(S) service the Nmap sweep found, not just the obvious 80/443, admin panels love hiding on 8080 and 8443.
nikto -h https://192.168.20.30 -Format csv -o nikto.csvExpected output:
+ Server: nginx/1.18.0
+ OSVDB-3092: /admin/: This might be interesting...
+ /server-status: Apache server-status found
The full run also surfaces header hygiene issues that are trivial to fix and worth including in the report because they are one-line remediations:
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type.
+ 7 requests: 0 error(s) and 5 item(s) reported on remote host
+ End Time: 2026-06-17 14:32:11 (GMT-4) (87 seconds)
How to verify: Nikto is noisy and prone to false positives, so hand-verify anything you plan to report. A finding like /server-status takes ten seconds to confirm: curl -sk https://192.168.20.30/server-status | head. If it returns a status page, it is real; if it returns the app's normal 404, drop the finding.
Common mistake: scanning only the IP and missing virtual-host content. If the server hosts name-based vhosts, use nikto -h https://app.internal.example.com -vhost app.internal.example.com so requests carry the right Host header, otherwise you scan the default vhost and report a clean bill of health on the wrong site.
What this teaches: Nikto catches web misconfigurations that network scanners overlook.
4. Score the consolidated findings with CVSS 3.1
With three tools' output in hand, deduplicate by (host, port, CVE) and score anything the scanner did not already rate. OpenVAS ships CVSS base scores with most results, but Nmap NSE findings and Nikto items often need manual scoring. Use the official FIRST calculator and, more importantly, be consistent about the vector components, especially AV (is it actually network-reachable from where an attacker would be?) and PR (does exploitation need an authenticated session?).
A worked example from this assessment: the confirmed Heartbleed finding (CVE-2014-0160) on the DMZ web server 192.168.20.30, which runs nginx against OpenSSL 1.0.1f. It scores as an unauthenticated, low-complexity network attack with a confidentiality impact:
echo "CVE-2014-0160 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N" >> scoring-notes.txtExpected output:
Base Score: 7.5 (High)
Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N
Common mistake: copying the NVD published base score without adjusting for context. NVD scores the worst reasonable case; your report should note where compensating controls change the picture, a 9.8 on a host segmented away from both the internet and user VLANs may rank below a 7.5 on the public web server. Record base score and an exposure-adjusted rank.
What this teaches: CVSS vectors make severity comparable across tools and findings.
5. Build the ranked remediation queue
The deliverable is not the scan output, it is an ordered queue where each row is one actionable ticket: host, CVE, evidence, score, exposure, and the fix. A small amount of shell glue deduplicates the three sources into that shape. Note the -H flag: it keeps the source filename on every match, because deduplicating to bare CVE strings destroys the host, port, product, and evidence context each row of the queue needs. The queue is built by joining CVEs back to their evidence, never by shipping the bare list:
grep -H -oE 'CVE-[0-9]{4}-[0-9]+' vuln-scan.nmap report.csv nikto.csv | sort -u -t: -k2 > cves-with-source.txtcut -d: -f2 cves-with-source.txt | sort -u | wc -lExpected output:
38
From 200+ raw findings down to 38 unique CVEs, each still traceable to the file and line that reported it, and the top of the queue after exposure ranking:
RANK HOST CVE SCORE EXPOSURE FIX
1 192.168.20.30 CVE-2014-0160 7.5 Internet Upgrade OpenSSL, reissue TLS keys
2 192.168.20.30 CVE-2007-6750 7.8* Internet Tune nginx timeouts, add connection-rate limiting (Slowloris)
3 192.168.20.11 CVE-2017-0144 8.1 Internal Apply MS17-010 / disable SMBv1
4 192.168.20.22 CVE-2023-38408 9.8 Client-side Upgrade OpenSSH to 9.3p2+, disable agent forwarding where unneeded
* CVE-2007-6750 (Slowloris) predates CVSS 3.x, so the 7.8 shown is the published CVSS v2 base score. It earned its queue position because the NSE check fired and a manual slow-headers probe confirmed the server held connections open past its timeouts; a LIKELY VULNERABLE verdict alone would not have been enough. Note row 4's correction: CVE-2023-38408 is a flaw in the OpenSSH agent (ssh-agent PKCS#11 provider handling), exploitable through agent forwarding against a compromised server, not a remotely exploitable sshd bug. Its exposure is client-side, and the fix is upgrading plus disabling forwarding where it is not needed.
How to verify: spot-check the top five rows by re-reading the raw scanner evidence for each. Every row must trace back to a specific scanner line, if you cannot point at the evidence, the finding does not ship. This traceability is what separates an assessment from an opinion.
What this teaches: deduplicating to unique CVEs turns three tool outputs into one actionable queue.
How It Works
A vulnerability assessment answers four questions in order: what is on the network (discovery), what is it vulnerable to (scanning), how bad is each finding (scoring), and what gets fixed first (prioritization). Skipping discovery means assessing an incomplete inventory; skipping scoring means drowning in unranked output.
Different scanners see different things. Nmap with NSE vuln scripts probes remotely and finds exposed services with known issues. OpenVAS with credentials enumerates installed software and matches it against feed data, catching missing patches invisible from the network. Nikto focuses on web servers: outdated software, dangerous files, and misconfigurations. Cross-tool corroboration is what cuts false positives.
CVSS 3.1 scoring makes findings comparable: the vector encodes attack vector, complexity, privileges, and impact into one number. The remediation queue sorts by that number tempered with asset criticality, so the team fixes the worst exposures on the most important systems first.
Validation & Testing
Cross-validate the top OpenVAS findings against Nmap NSE output to eliminate false positives, then confirm each critical maps to a real CVE with a CVSS base ≥ 9.0. Pass criteria: a deduplicated, evidence-backed finding list ordered by score and exposure.
Concretely, cross-validation means two independent tools must agree, or one tool plus manual verification. For version-based findings, pull the banner or package version directly from the host rather than trusting either scanner:
ssh [email protected] 'openssl version; dpkg -l | grep openssl'curl -skI https://192.168.20.30 | grep -i serverOpenSSL 1.0.1f 6 Jan 2014
ii openssl 1.0.1f-1ubuntu2 amd64
Server: nginx/1.18.0
OpenSSL 1.0.1f on the host confirms the Heartbleed finding independently of both scanners, that finding ships. One caution that applies to every version-based finding: a bare version string can mislead on enterprise distros, because vendors backport security fixes without bumping the upstream version number. A "1.0.1f" from Ubuntu's changelog history tells a different story than upstream 1.0.1f, so always check the distro build string (here 1.0.1f-1ubuntu2) and the changelog (apt changelog openssl on Debian-family) before calling a version vulnerable. OpenVAS's authenticated local checks account for backports via the Notus feed, which is exactly why the credentialed scan outranks banner evidence. Where the two tools disagree, the manual check is the tiebreaker, and the losing scanner's result gets annotated as a false positive rather than silently deleted, so the next assessor does not re-litigate it.
How to verify the queue itself: hand it to someone who did not run the scans and ask them to reproduce the #1 finding from the evidence column alone. If they cannot, the evidence is not specific enough.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Command not found | package missing | install prerequisite and verify version |
| Permission denied | insufficient privileges | use documented sudo or lab admin context |
| Output differs | version or environment mismatch | verify versions and variables |
| Service or API unreachable | dependency, DNS, or firewall issue | check status, listener, and logs |
- Few results: uncredentialed scans miss local CVEs; supply SSH/SMB credentials. Confirm they worked by looking for the "possible to log into the remote host" log result per target, a silent auth failure produces a clean-looking but empty report.
- Stale feed: run
greenbone-feed-syncand check/var/log/gvm/. If gvmd logs "SCAP database is required" or shows a sync timestamp weeks old, re-sync all three feed types and wait for gvmd to finish rebuilding its NVT cache before scanning. - False positives: corroborate with banner grabs and version checks before reporting. Nikto's
/admin/-style hits and Nmap'sLIKELY VULNERABLEstates are inference, not proof, a ten-secondcurlordpkg -lsettles them. - gvm-cli connection refused: the gvmd socket lives at a distro-specific path (commonly
/run/gvmd/gvmd.sockor/var/run/gvmd/gvmd.sock). Point the CLI at it with--socketpath /run/gvmd/gvmd.sockand make sure your user is in the_gvmgroup, or the socket will exist but deny you. - Scan knocked something over: printers, old switches, and embedded controllers crash under aggressive probing. Exclude them via
--excludefilein Nmap and a dedicated "slow" target in OpenVAS with max_concurrently_executed_nvts lowered, then scan them in a maintenance window, not business hours.
Key Results
- Triaged 200+ raw findings into a CVSS-ranked queue with 4 criticals surfaced first.
- Reduced false positives by roughly 60% through cross-tool corroboration.
- Mapped every critical finding to a specific CVE and affected version.
- Cut time-to-first-remediation-ticket from days to under 1 hour.
- Condensed 200+ raw findings into 38 unique CVEs after deduplication across the three tools.
- Surfaced a confirmed Heartbleed instance (OpenSSL 1.0.1f) on the DMZ web server that an uncredentialed-only scan had previously missed.
Key Takeaways
- Layer the tools: Nmap for reachability and banners, OpenVAS with credentials for real patch-level depth, Nikto for web-specific surface. Each finds things the others miss.
- Credentialed scanning is non-negotiable for a real assessment, an uncredentialed "all clear" is usually a failed-login report in disguise.
- CVSS base score orders the work, but exposure and asset context decide the actual fix order; record both.
- Every reported finding must trace to verifiable evidence: a banner, a package version, or a reproducible request. No evidence, no finding.
- Scope discipline (target files, exclude files, written ROE) is a deliverable, not admin overhead, it is what keeps the assessment authorized.
Practice Challenges
Challenge 1: Prove a finding manually
Goal: Take one Nikto finding and confirm it by hand with curl, documenting each request.
Hint: Reproduce the exact request Nikto made; scanners are sometimes wrong about context.
Challenge 2: Scan through a firewall
Goal: Assess a target behind a firewall and document which findings the firewall hides vs which remain.
Hint: Compare an internal scan with an external one and diff the finding sets.