Nikto web server scanner: techniques
intermediate
va
Basic Usage #
Simple Web Server Scan #
# Basic scan
nikto -h http://target.com
# Scan with HTTPS
nikto -h https://target.com
# Scan specific port
nikto -h http://target.com:8080
# Scan multiple hosts
nikto -h http://target1.com,http://target2.com
# Scan from file
echo "http://target1.com" > targets.txt
echo "http://target2.com" >> targets.txt
nikto -h targets.txtPort and Protocol Options #
# Scan specific port
nikto -h target.com -p 80,443,8080,8443
# Scan port range
nikto -h target.com -p 80-90
# Force SSL
nikto -h target.com -ssl
# Disable SSL
nikto -h target.com -nossl
# Use specific HTTP method
nikto -h target.com -method GET
nikto -h target.com -method POSTAuthentication #
# Basic authentication
nikto -h http://target.com -id username:password
# NTLM authentication
nikto -h http://target.com -id domain\\username:password
# Custom headers
nikto -h http://target.com -H "Authorization: Bearer token123"
# Cookie authentication
nikto -h http://target.com -H "Cookie: sessionid=abc123"
# Multiple headers
nikto -h http://target.com -H "Authorization: Bearer token" -H "X-API-Key: key123"Advanced Scanning #
Tuning Options #
# Scan specific categories
nikto -h target.com -Tuning 1 # Interesting File / Seen in logs
nikto -h target.com -Tuning 2 # Misconfiguration / Default File
nikto -h target.com -Tuning 3 # Information Disclosure
nikto -h target.com -Tuning 4 # Injection (XSS/Script/HTML)
nikto -h target.com -Tuning 5 # Remote File Retrieval - Inside Web Root
nikto -h target.com -Tuning 6 # Denial of Service
nikto -h target.com -Tuning 7 # Remote File Retrieval - Server Wide
nikto -h target.com -Tuning 8 # Command Execution - Remote Shell
nikto -h target.com -Tuning 9 # SQL Injection
nikto -h target.com -Tuning 0 # File Upload
nikto -h target.com -Tuning a # Authentication Bypass
nikto -h target.com -Tuning b # Software Identification
nikto -h target.com -Tuning c # Remote Source Inclusion
nikto -h target.com -Tuning x # Reverse Tuning Options (exclude)
# Multiple tuning options
nikto -h target.com -Tuning 1,2,3,4
# Exclude specific tests
nikto -h target.com -Tuning x6 # Exclude DoS testsPlugin Management #
# List available plugins
nikto -list-plugins
# Use specific plugins
nikto -h target.com -Plugins "apacheusers,cgi"
# Exclude plugins
nikto -h target.com -Plugins "@@DEFAULT" -Plugins "-outdated"
# Custom plugin directory
nikto -h target.com -plugindir /path/to/plugins
# Plugin-specific options
nikto -h target.com -Plugins "cgi(all)"
nikto -h target.com -Plugins "headers(verbose)"Output and Reporting #
# Save output to file
nikto -h target.com -o scan_results.txt
# Specify output format
nikto -h target.com -Format txt -o results.txt
nikto -h target.com -Format xml -o results.xml
nikto -h target.com -Format csv -o results.csv
nikto -h target.com -Format htm -o results.html
nikto -h target.com -Format json -o results.json
# Multiple output formats
nikto -h target.com -Format txt,xml,csv -o results
# Verbose output
nikto -h target.com -verbose
# Display only specific findings
nikto -h target.com -Display 1 # Show redirects
nikto -h target.com -Display 2 # Show cookies received
nikto -h target.com -Display 3 # Show all 200/OK responses
nikto -h target.com -Display 4 # Show URLs which require authentication
nikto -h target.com -Display V # Verbose output
nikto -h target.com -Display E # Debug outputSpecialized Scanning #
SSL/TLS Testing #
# SSL-specific scan
nikto -h https://target.com -ssl
# Test SSL ciphers
nikto -h https://target.com -Plugins "ssl"
# Ignore SSL certificate errors
nikto -h https://target.com -ssl -nossl
# Test specific SSL version
nikto -h https://target.com -ssl -sslversion 3CGI and Script Testing #
# CGI enumeration
nikto -h target.com -Plugins "cgi"
# Test all CGI directories
nikto -h target.com -Plugins "cgi(all)"
# Custom CGI directory
nikto -h target.com -Cgidirs "/scripts/,/cgi/,/custom-cgi/"
# Test for dangerous CGI scripts
nikto -h target.com -Tuning 8Directory and File Discovery #
# Test for common files
nikto -h target.com -Tuning 1,2
# Test for backup files
nikto -h target.com -Plugins "backup_files"
# Test for interesting files
nikto -h target.com -Plugins "interesting_files"
# Custom root directory
nikto -h target.com -root /app/
# Test multiple directories
nikto -h target.com -root /,/app/,/admin/Database and Application Testing #
# SQL injection tests
nikto -h target.com -Tuning 9
# Test for database files
nikto -h target.com -Plugins "database_files"
# Test for application-specific vulnerabilities
nikto -h target.com -Plugins "apache_expect_xss"
nikto -h target.com -Plugins "shellshock"
nikto -h target.com -Plugins "heartbleed"
# Test for outdated software
nikto -h target.com -Plugins "outdated"Automation Scripts #
Batch Scanning Script #
#!/bin/bash
# Batch web server scanning with Nikto
TARGETS_FILE="$1"
OUTPUT_DIR="nikto_scans_$(date +%Y%m%d_%H%M%S)"
if [ -z "$TARGETS_FILE" ]; then
echo "Usage: $0 <targets_file>"
echo "Example targets file format:"
echo "http://target1.com"
echo "https://target2.com:8443"
echo "http://target3.com:8080"
exit 1
fi
if [ ! -f "$TARGETS_FILE" ]; then
echo "Error: Targets file not found: $TARGETS_FILE"
exit 1
fi
mkdir -p "$OUTPUT_DIR"
echo "[+] Starting batch Nikto scan"
echo "[+] Targets file: $TARGETS_FILE"
echo "[+] Output directory: $OUTPUT_DIR"
# Function to scan a single target
scan_target() \\\\{
local target="$1"
local target_name=$(echo "$target"|sed 's|https\?://||'|sed 's|[:/]|_|g')
local output_file="$OUTPUT_DIR/$\\\\{target_name\\\\}"
echo "[+] Scanning: $target"
# Run comprehensive scan
nikto -h "$target" \
-Tuning 1,2,3,4,5,7,8,9,a,b,c \
-Format txt,xml,csv \
-o "$output_file" \
-timeout 10 \
-maxtime 3600 \
2>&1|tee "$\\\\{output_file\\\\}_console.log"
if [ $? -eq 0 ]; then
echo " ✓ Scan completed: $target"
else
echo " ✗ Scan failed: $target"
fi
\\\\}
# Read targets and scan
while IFS= read -r target; do
# Skip empty lines and comments
[[ -z "$target"||"$target" =~ ^#.*$ ]] && continue
scan_target "$target"
# Wait between scans to be respectful
sleep 5
done < "$TARGETS_FILE"
echo "[+] Batch scanning completed"
echo "[+] Results saved in: $OUTPUT_DIR"
# Generate summary report
echo "[+] Generating summary report..."
cat > "$OUTPUT_DIR/summary.html" << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>Nikto Scan Summary</title>
<style>
body \\\\{ font-family: Arial, sans-serif; margin: 20px; \\\\}
table \\\\{ border-collapse: collapse; width: 100%; margin: 20px 0; \\\\}
th, td \\\\{ border: 1px solid #ddd; padding: 8px; text-align: left; \\\\}
th \\\\{ background-color: #f2f2f2; \\\\}
.high \\\\{ color: #d32f2f; font-weight: bold; \\\\}
.medium \\\\{ color: #f57c00; font-weight: bold; \\\\}
.low \\\\{ color: #388e3c; \\\\}
.info \\\\{ color: #1976d2; \\\\}
</style>
</head>
<body>
<h1>Nikto Scan Summary</h1>
<p>Generated on: $(date)</p>
<table>
<tr><th>Target</th><th>Findings</th><th>Status</th></tr>
EOF
for log_file in "$OUTPUT_DIR"/*_console.log; do
if [ -f "$log_file" ]; then
target=$(basename "$log_file" _console.log)
findings=$(grep -c "+" "$log_file" 2>/dev/null||echo "0")
if [ "$findings" -gt 0 ]; then
status="<span class='medium'>Issues Found</span>"
else
status="<span class='info'>Clean</span>"
fi
echo " <tr><td>$target</td><td>$findings</td><td>$status</td></tr>" >> "$OUTPUT_DIR/summary.html"
fi
done
cat >> "$OUTPUT_DIR/summary.html" << 'EOF'
</table>
</body>
</html>
EOF
echo "[+] Summary report created: $OUTPUT_DIR/summary.html"Continuous Monitoring Script #
#!/bin/bash
# Continuous web application monitoring with Nikto
CONFIG_FILE="nikto_monitor.conf"
LOG_DIR="nikto_monitoring"
ALERT_EMAIL="security@company.com"
# Create default config if it doesn't exist
if [ ! -f "$CONFIG_FILE" ]; then
cat > "$CONFIG_FILE" << 'EOF'
# Nikto monitoring configuration
# Format: URL|SCAN_INTERVAL|ALERT_THRESHOLD
https://app1.company.com|86400|5
https://app2.company.com|43200|3
http://internal.app.com:8080|21600|10
EOF
echo "Created default config: $CONFIG_FILE"
echo "Edit the configuration and run again"
exit 1
fi
mkdir -p "$LOG_DIR"
# Function to send alert
send_alert() \\\\{
local target="$1"
local findings="$2"
local threshold="$3"
local report_file="$4"
if [ "$findings" -gt "$threshold" ]; then
echo "ALERT: $target has $findings findings (threshold: $threshold)"|\
mail -s "Nikto Alert: $target" -A "$report_file" "$ALERT_EMAIL" 2>/dev/null||\
echo "Alert: $target has $findings findings (email failed)"
fi
\\\\}
# Function to scan target
monitor_target() \\\\{
local target="$1"
local threshold="$2"
local timestamp=$(date +%Y%m%d_%H%M%S)
local target_name=$(echo "$target"|sed 's|https\?://||'|sed 's|[:/]|_|g')
local report_file="$LOG_DIR/$\\\\{target_name\\\\}_$timestamp.txt"
echo "[$(date)] Scanning $target"
# Run Nikto scan
nikto -h "$target" \
-Tuning 1,2,3,4,5,7,8,9,a,b,c \
-Format txt \
-o "$report_file" \
-timeout 10 \
-maxtime 1800 \
> /dev/null 2>&1
if [ -f "$report_file" ]; then
# Count findings
findings=$(grep -c "+" "$report_file" 2>/dev/null||echo "0")
echo "[$(date)] $target: $findings findings"
# Send alert if threshold exceeded
send_alert "$target" "$findings" "$threshold" "$report_file"
# Keep only last 10 reports per target
ls -t "$LOG_DIR/$\\\\{target_name\\\\}_"*.txt 2>/dev/null|tail -n +11|xargs rm -f 2>/dev/null
return 0
else
echo "[$(date)] $target: Scan failed"
return 1
fi
\\\\}
# Main monitoring loop
echo "[$(date)] Starting Nikto monitoring"
while true; do
while IFS='|' read -r target interval threshold; do
# Skip comments and empty lines
[[ "$target" =~ ^#.*$||-z "$target" ]] && continue
# Check if it's time to scan this target
target_name=$(echo "$target"|sed 's|https\?://||'|sed 's|[:/]|_|g')
last_scan_file="$LOG_DIR/.$\\\\{target_name\\\\}_last_scan"
current_time=$(date +%s)
if [ -f "$last_scan_file" ]; then
last_scan=$(cat "$last_scan_file")
time_diff=$((current_time - last_scan))
if [ "$time_diff" -lt "$interval" ]; then
continue # Not time to scan yet
fi
fi
# Update last scan time
echo "$current_time" > "$last_scan_file"
# Run scan in background
monitor_target "$target" "$threshold" &
done < "$CONFIG_FILE"
# Wait before next check
sleep 300 # Check every 5 minutes
doneVulnerability Correlation Script #
#!/bin/bash
# Correlate Nikto findings with CVE references -> HTML report
# Usage: ./nikto_cve_correlate.sh <nikto_report.txt> [output.html]
NIKTO_REPORT="$1"
OUTPUT_FILE="${2:-nikto_cve_correlation.html}"
TMP_FINDINGS="$(mktemp)"
trap 'rm -f "$TMP_FINDINGS"' EXIT
if [ -z "$NIKTO_REPORT" ] || [ ! -f "$NIKTO_REPORT" ]; then
echo "Usage: $0 <nikto_report.txt> [output.html]"
exit 1
fi
echo "[+] Correlating Nikto findings with CVE references"
# Only real Nikto finding lines start with "+ "
grep '^+ ' "$NIKTO_REPORT" | while IFS= read -r line; do
finding="${line#+ }"
# One line, space-separated, deduplicated
cve_refs=$(grep -oE 'CVE-[0-9]{4}-[0-9]{4,}' <<< "$finding" | sort -u | tr '\n' ' ')
if [ -n "$cve_refs" ]; then
echo "Finding: $finding"
echo "CVE References: $cve_refs"
echo "---"
fi
done > "$TMP_FINDINGS"
FINDINGS_FILE="$TMP_FINDINGS" OUTPUT_FILE="$OUTPUT_FILE" python3 << 'EOF'
import os
import html
from datetime import datetime
findings_file = os.environ["FINDINGS_FILE"]
output_file = os.environ["OUTPUT_FILE"]
findings = []
current = {}
with open(findings_file, "r", encoding="utf-8", errors="replace") as f:
for line in f:
line = line.rstrip("\n")
if line.startswith("Finding: "):
if current:
findings.append(current)
current = {"finding": line[len("Finding: "):], "cves": []}
elif line.startswith("CVE References: "):
current["cves"] = line[len("CVE References: "):].split()
if current:
findings.append(current)
parts = [f"""<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Nikto CVE Correlation Report</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
.finding {{ margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }}
.cve {{ margin: 5px 0; padding: 5px; background-color: #f5f5f5; }}
.cve-link {{ color: #1976d2; text-decoration: none; }}
.cve-link:hover {{ text-decoration: underline; }}
</style>
</head>
<body>
<h1>Nikto CVE Correlation Report</h1>
<p>Generated on: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
<p>Total findings with CVE references: {len(findings)}</p>
"""]
for fd in findings:
parts.append(f'<div class="finding">\n<h3>Finding</h3>\n'
f'<p>{html.escape(fd["finding"])}</p>\n<h4>CVE References</h4>\n')
for cve in fd["cves"]:
c = html.escape(cve)
parts.append(
f'<div class="cve"><strong>{c}</strong><br>'
f'<a href="https://www.cve.org/CVERecord?id={c}" target="_blank" rel="noopener" class="cve-link">CVE.org</a> | '
f'<a href="https://nvd.nist.gov/vuln/detail/{c}" target="_blank" rel="noopener" class="cve-link">NVD Details</a>'
f'</div>\n')
parts.append("</div>\n")
parts.append("</body>\n</html>\n")
with open(output_file, "w", encoding="utf-8") as f:
f.write("".join(parts))
print(f"Found {len(findings)} findings with CVE references")
EOF
echo "[+] CVE correlation completed"
echo "[+] Report saved: $OUTPUT_FILE"Integration Scripts #
Nmap + Nikto Integration #
#!/bin/bash
# Discover web services with Nmap, then scan with Nikto
NETWORK="$1"
OUTPUT_DIR="nmap_nikto_$(date +%Y%m%d_%H%M%S)"
if [ -z "$NETWORK" ]; then
echo "Usage: $0 <network>"
echo "Example: $0 192.168.1.0/24"
exit 1
fi
mkdir -p "$OUTPUT_DIR"
echo "[+] Discovering web services with Nmap"
# Discover web services
nmap -sS -p 80,443,8080,8443,8000,8888,9000,9090 \
--open \
-oG "$OUTPUT_DIR/nmap_web_services.gnmap" \
"$NETWORK"
# Extract web services
grep -E "(80|443|8080|8443|8000|8888|9000|9090)/open" "$OUTPUT_DIR/nmap_web_services.gnmap"|\
awk '\\\\{print $2\\\\}'|sort -u > "$OUTPUT_DIR/web_hosts.txt"
echo "[+] Found $(wc -l < "$OUTPUT_DIR/web_hosts.txt") hosts with web services"
# Scan each host with Nikto
while IFS= read -r host; do
echo "[+] Scanning $host with Nikto"
# Get open ports for this host
ports=$(grep "$host" "$OUTPUT_DIR/nmap_web_services.gnmap"|\
grep -oE '[0-9]+/open'|cut -d'/' -f1|tr '\n' ','|sed 's/,$//')
if [ -n "$ports" ]; then
nikto -h "$host" -p "$ports" \
-Format txt,xml \
-o "$OUTPUT_DIR/$\\\\{host\\\\}_nikto" \
-timeout 10 \
-maxtime 1800
fi
sleep 5 # Be respectful
done < "$OUTPUT_DIR/web_hosts.txt"
echo "[+] Nmap + Nikto scan completed"
echo "[+] Results saved in: $OUTPUT_DIR"Burp Suite Integration #
#!/bin/bash
# Push Nikto findings into Burp Suite's site map.
# 1. Parses the Nikto XML report (nikto -Format xml -o report.xml)
# 2. Writes a deduplicated list of finding URLs + a CSV summary
# 3. Optionally replays each URL through Burp's proxy so it appears
# in Target > Site map, ready for Repeater / active scan.
#
# Usage: ./nikto_to_burp.sh <nikto_report.xml> [--replay] [proxy]
# proxy defaults to http://127.0.0.1:8080
NIKTO_REPORT="$1"
REPLAY="$2"
BURP_PROXY="${3:-http://127.0.0.1:8080}"
URL_FILE="nikto_urls.txt"
CSV_FILE="nikto_findings.csv"
if [ -z "$NIKTO_REPORT" ] || [ ! -f "$NIKTO_REPORT" ]; then
echo "Usage: $0 <nikto_report.xml> [--replay] [proxy_url]"
exit 1
fi
echo "[+] Parsing Nikto XML report"
# Pass paths as real arguments: "python3 - args" makes sys.argv work
if ! python3 - "$NIKTO_REPORT" "$URL_FILE" "$CSV_FILE" << 'EOF'
import csv
import sys
import xml.etree.ElementTree as ET
from urllib.parse import urljoin
report, url_file, csv_file = sys.argv[1:4]
try:
root = ET.parse(report).getroot()
except (ET.ParseError, OSError) as e:
print(f"[-] Could not parse Nikto XML: {e}", file=sys.stderr)
sys.exit(1)
def text(el, tag):
child = el.find(tag)
return (child.text or "").strip() if child is not None else ""
urls, rows = [], []
# Works for both <niktoscan> and multi-host <niktoscans> roots
for sd in root.iter("scandetails"):
sitename = sd.get("sitename", "") # e.g. https://host:443/
for item in sd.iter("item"):
uri = text(item, "uri") or "/"
# namelink is Nikto's full URL; fall back to sitename + uri
url = text(item, "namelink") or urljoin(sitename, uri)
rows.append({
"nikto_id": item.get("id", ""),
"method": item.get("method", "GET"),
"url": url,
"description": text(item, "description"),
"references": text(item, "references"),
})
if url not in urls:
urls.append(url)
if not rows:
print("[-] No <scandetails>/<item> elements found - is this a Nikto -Format xml report?",
file=sys.stderr)
sys.exit(1)
with open(url_file, "w") as f:
f.write("\n".join(urls) + "\n")
with open(csv_file, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=rows[0].keys())
w.writeheader()
w.writerows(rows)
print(f"[+] {len(rows)} findings, {len(urls)} unique URLs")
EOF
then
echo "[-] Conversion failed"
exit 1
fi
echo "[+] URL list: $URL_FILE"
echo "[+] Findings summary: $CSV_FILE"
if [ "$REPLAY" = "--replay" ]; then
echo "[+] Replaying URLs through Burp proxy at $BURP_PROXY"
while IFS= read -r url; do
[ -z "$url" ] && continue
code=$(curl -sk -o /dev/null -w '%{http_code}' --max-time 15 \
--proxy "$BURP_PROXY" "$url")
echo " [$code] $url"
done < "$URL_FILE"
echo "[+] Done - check Target > Site map in Burp"
fiTroubleshooting #
Common Issues #
SSL/TLS Problems #
# Test SSL connectivity
openssl s_client -connect target.com:443
# Force SSL version
nikto -h https://target.com -ssl -sslversion 3
# Ignore SSL certificate errors
nikto -h https://target.com -ssl -nossl
# Debug SSL issues
nikto -h https://target.com -ssl -Display ETimeout Issues #
# Increase timeout
nikto -h target.com -timeout 30
# Set maximum scan time
nikto -h target.com -maxtime 7200
# Reduce scan scope
nikto -h target.com -Tuning 1,2,3
# Use fewer plugins
nikto -h target.com -Plugins "headers,robots"Performance Issues #
# Reduce scan intensity
nikto -h target.com -Pause 5
# Limit concurrent connections
nikto -h target.com -timeout 10 -maxtime 3600
# Use specific tuning to reduce load
nikto -h target.com -Tuning x6 # Exclude DoS tests
# Scan specific directories only
nikto -h target.com -root /app/Database Updates #
# Update Nikto database
nikto -update
# Check database version
nikto -Version
# Manual database update
cd /var/lib/nikto
wget https://cirt.net/nikto/UPDATES/2.1.6/db_testsDebugging and Logging #
# Enable debug output
nikto -h target.com -Display E
# Verbose output
nikto -h target.com -verbose
# Save debug information
nikto -h target.com -Display E -o debug.log
# Check configuration
nikto -config