vulnerability management

Performing Web Application Scanning with Nikto

Nikto is an open-source web server and web application scanner that tests against over 7,000 potentially dangerous files/programs, checks for outdated versions of over 1,250 servers, and identifies version-specific problems on over 270 servers. It performs comprehensive tests including XSS, SQL injection, server misconfigurations, default credentials, and known vulnerable CGI scripts.

cveniktoowaspriskvulnerability-managementweb-scanning
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Nikto is an open-source web server and web application scanner that tests against over 7,000 potentially dangerous files/programs, checks for outdated versions of over 1,250 servers, and identifies version-specific problems on over 270 servers. It performs comprehensive tests including XSS, SQL injection, server misconfigurations, default credentials, and known vulnerable CGI scripts.

When to Use

  • When conducting security assessments that involve performing web application scanning with nikto
  • When following incident response procedures for related security events
  • When performing scheduled security testing or auditing activities
  • When validating security controls through hands-on testing

Prerequisites

  • Nikto installed (Perl-based, included in Kali Linux)
  • Written authorization to scan target web servers
  • Network access to target web applications
  • Understanding of HTTP/HTTPS protocols

Core Concepts

What Nikto Detects

  • Server misconfigurations and dangerous default files
  • Outdated server software versions with known CVEs
  • Common CGI vulnerabilities and dangerous scripts
  • Default credentials and admin pages
  • HTTP methods that should be disabled (PUT, DELETE, TRACE)
  • SSL/TLS misconfigurations and weak ciphers
  • Missing security headers (X-Frame-Options, CSP, HSTS)
  • Information disclosure through headers and error pages

Nikto vs Other Web Scanners

Feature Nikto OWASP ZAP Burp Suite Nuclei
License Open Source Open Source Commercial Open Source
Focus Server/Config App Logic Full Pentest Template-Based
Speed Fast Medium Slow Very Fast
False Positives Moderate Low Low Low
Authentication Basic Full Full Template
Active Community Yes Yes Yes Yes

Workflow

Step 1: Basic Scanning

# Basic scan against a target
nikto -h https://target.example.com
 
# Scan specific port
nikto -h target.example.com -p 8443
 
# Scan multiple ports
nikto -h target.example.com -p 80,443,8080,8443
 
# Scan with SSL enforcement
nikto -h target.example.com -ssl
 
# Scan from a host list file
nikto -h targets.txt

Step 2: Advanced Scanning Options

# Comprehensive scan with all tuning options
nikto -h https://target.example.com \
  -Tuning 123456789abcde \
  -timeout 10 \
  -Pause 2 \
  -Display V \
  -output report.html \
  -Format htm
 
# Tuning options control test types:
# 0 - File Upload
# 1 - Interesting File / Seen in logs
# 2 - Misconfiguration / Default File
# 3 - Information Disclosure
# 4 - Injection (XSS/Script/HTML)
# 5 - Remote File Retrieval - Inside Web Root
# 6 - Denial of Service
# 7 - Remote File Retrieval - Server Wide
# 8 - Command Execution / Remote Shell
# 9 - SQL Injection
# a - Authentication Bypass
# b - Software Identification
# c - Remote Source Inclusion
# d - WebService
# e - Administrative Console
 
# Scan with specific tuning (XSS + SQL injection + auth bypass)
nikto -h https://target.example.com -Tuning 49a
 
# Scan with authentication
nikto -h https://target.example.com -id admin:password
 
# Scan through a proxy
nikto -h https://target.example.com -useproxy http://proxy:8080
 
# Scan with custom User-Agent
nikto -h https://target.example.com -useragent "Mozilla/5.0 (Security Scan)"
 
# Scan specific CGI directories
nikto -h https://target.example.com -Cgidirs /cgi-bin/,/scripts/
 
# Evasion techniques (IDS avoidance for authorized testing)
# 1-Random URI encoding, 2-Directory self-reference
# 3-Premature URL ending, 4-Prepend long random string
nikto -h https://target.example.com -evasion 1234

Step 3: Output and Reporting

# Generate multiple output formats
nikto -h https://target.example.com -output scan.csv -Format csv
nikto -h https://target.example.com -output scan.xml -Format xml
nikto -h https://target.example.com -output scan.html -Format htm
nikto -h https://target.example.com -output scan.txt -Format txt
 
# JSON output (newer versions)
nikto -h https://target.example.com -output scan.json -Format json
 
# Save to multiple formats simultaneously
nikto -h https://target.example.com \
  -output scan_report \
  -Format htm

Step 4: Scan Multiple Targets

# Create targets file (one per line)
cat > targets.txt << 'EOF'
https://app1.example.com
https://app2.example.com:8443
http://internal-app.corp.local
192.168.1.100:8080
EOF
 
# Scan all targets
nikto -h targets.txt -output multi_scan.html -Format htm
 
# Parallel scanning with GNU parallel
cat targets.txt | parallel -j 5 "nikto -h {} -output {/}_report.html -Format htm"

Step 5: SSL/TLS Assessment

# Comprehensive SSL scan
nikto -h https://target.example.com -ssl \
  -Tuning b \
  -Display V
 
# Check for specific SSL vulnerabilities
# Nikto checks for:
# - Expired certificates
# - Self-signed certificates
# - Weak cipher suites
# - SSLv2/SSLv3 enabled
# - BEAST, POODLE, Heartbleed indicators
# - Missing HSTS header

Step 6: Integration with Other Tools

# Pipe Nmap results into Nikto
nmap -p 80,443,8080 --open -oG - 192.168.1.0/24 | \
  awk '/open/{print $2}' | \
  while read host; do nikto -h "$host" -output "${host}_nikto.html" -Format htm; done
 
# Export to Metasploit-compatible format
nikto -h target.example.com -output msf_import.xml -Format xml
 
# Parse Nikto XML output with Python for custom reporting
python3 -c "
import xml.etree.ElementTree as ET
tree = ET.parse('scan.xml')
for item in tree.findall('.//item'):
    print(f\"[{item.get('id')}] {item.findtext('description', '')[:100]}\")
"

Interpreting Results

Severity Classification

  • OSVDB/CVE References: Cross-reference with NVD for CVSS scores
  • Server Information Disclosure: Version banners, technology stack
  • Dangerous HTTP Methods: PUT, DELETE, TRACE enabled
  • Default/Backup Files: .bak, .old, .swp, web.config.bak
  • Admin Interfaces: /admin, /manager, /console exposed
  • Missing Security Headers: CSP, X-Frame-Options, HSTS

Common False Positives

  • Generic checks triggered by custom 404 pages
  • Anti-CSRF tokens flagged as form vulnerabilities
  • CDN/WAF responses misidentified as vulnerable
  • Load balancer health check pages

Best Practices

  1. Always obtain written authorization before scanning
  2. Run Nikto in conjunction with application-level scanners (ZAP, Burp)
  3. Use -Pause flag to reduce load on production servers
  4. Validate findings manually before reporting
  5. Combine with SSL testing tools (testssl.sh, sslyze) for comprehensive coverage
  6. Schedule regular scans as part of continuous vulnerability management
  7. Keep Nikto database updated for latest vulnerability checks
  8. Use appropriate evasion settings only for authorized IDS testing

Common Pitfalls

  • Running Nikto without authorization (legal liability)
  • Treating Nikto as a complete web application scanner (it focuses on server/config issues)
  • Not validating results leading to false positive reports
  • Scanning too aggressively against production systems
  • Ignoring SSL/TLS findings as "informational"
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 3

api-reference.md1.7 KB

API Reference: Web Application Scanning with Nikto

Nikto CLI Options

Flag Description
-h <host> Target hostname or IP
-port <ports> Target ports (comma-separated)
-ssl Force SSL/TLS connection
-Format xml|json|csv|htm Output format
-output <file> Save results to file
-Tuning <options> Scan tuning categories
-Plugins <list> Specific plugins to run
-maxtime <seconds>s Maximum scan duration
-nointeractive Disable interactive prompts
-useproxy <url> Use HTTP proxy
-id <user:pass> HTTP Basic auth credentials

Tuning Categories

Code Category
1 Interesting File / Seen in logs
2 Misconfiguration / Default File
3 Information Disclosure
4 Injection (XSS/Script/HTML)
5 Remote File Retrieval - Inside Web Root
6 Denial of Service
7 Remote File Retrieval - Server Wide
8 Command Execution / Remote Shell
9 SQL Injection
0 File Upload

XML Output Structure

Element Description
<niktoscan> Root element
<scandetails> Scan metadata
<item> Individual finding
<item id="..." osvdbid="..."> Finding with OSVDB reference
<uri> Affected URI path
<description> Finding description

Python Libraries

Library Version Purpose
subprocess stdlib Execute Nikto CLI
xml.etree.ElementTree stdlib Parse Nikto XML output
json stdlib Report generation

References

standards.md2.1 KB

Standards and References - Web Application Scanning with Nikto

Industry Standards

  • OWASP Testing Guide v4.2: Web application security testing methodology
  • NIST SP 800-115: Technical Guide to Information Security Testing and Assessment
  • PCI DSS v4.0 Req 6.4: Address common coding vulnerabilities in development
  • PCI DSS v4.0 Req 11.3.3: Perform external vulnerability scans via ASV

Nikto Resources

Complementary Web Scanning Tools

Tool Purpose URL
OWASP ZAP Application-level scanning https://www.zaproxy.org/
Nuclei Template-based scanning https://github.com/projectdiscovery/nuclei
testssl.sh SSL/TLS assessment https://testssl.sh/
Wapiti Web application fuzzer https://wapiti-scanner.github.io/
WhatWeb Web technology fingerprinting https://github.com/urbanadventurer/WhatWeb

Nikto Tuning Reference

Code Category Description
0 File Upload Checks for file upload vulnerabilities
1 Interesting File Files commonly seen in server logs
2 Misconfiguration Default files and misconfigurations
3 Information Disclosure Information leakage through headers/pages
4 Injection (XSS) Cross-site scripting and HTML injection
5 Remote File Retrieval Inside web root file access
6 Denial of Service DoS vulnerability checks
7 Remote File Retrieval Server-wide file access
8 Command Execution RCE and remote shell vulnerabilities
9 SQL Injection SQL injection vulnerability checks
a Authentication Bypass Authentication bypass techniques
b Software Identification Server and software version detection
c Remote Source Inclusion RFI/LFI vulnerability checks
d WebService Web service specific vulnerabilities
e Administrative Console Admin interface discovery
workflows.md2.1 KB

Workflows - Web Application Scanning with Nikto

Workflow 1: Standard Web Server Assessment

┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ Enumerate    │──>│ Run Nikto    │──>│ Parse XML    │
│ Web Servers  │   │ Scan         │   │ Results      │
│ (Nmap/DNS)   │   │ (-Format xml)│   │              │
└──────────────┘   └──────────────┘   └──────────────┘

       ┌───────────────────────────────────┘
       v
┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ Validate     │──>│ Cross-ref    │──>│ Generate     │
│ Findings     │   │ with NVD     │   │ Report       │
│ (Manual)     │   │ (CVE/CVSS)   │   │              │
└──────────────┘   └──────────────┘   └──────────────┘

Workflow 2: CI/CD Integration

Code Push → Build → Deploy to Staging

                    Run Nikto Scan

                 ┌───────┴───────┐
                 │               │
            No Findings    Findings Found
                 │               │
            Deploy to       Block Deploy
            Production      Notify Team

Workflow 3: Multi-Tool Web Assessment

  1. Nikto: Server configuration and known vulnerability checks
  2. OWASP ZAP: Application logic and dynamic analysis
  3. testssl.sh: Comprehensive SSL/TLS assessment
  4. Nuclei: Template-based CVE validation
  5. Manual Testing: Validate and verify all findings
  6. Consolidated Report: Merge results from all tools

Scripts 2

agent.py5.3 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for web application scanning with Nikto.

Runs Nikto via subprocess for web server vulnerability scanning,
parses XML/JSON output, classifies findings by OSVDB/CVE, and
generates a structured security assessment report.
"""

import subprocess
import json
import sys
import xml.etree.ElementTree as ET
from datetime import datetime
from pathlib import Path


class NiktoScanAgent:
    """Automates Nikto web vulnerability scanning and reporting."""

    def __init__(self, target, output_dir="./nikto_scans"):
        self.target = target
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)
        self.findings = []

    def run_scan(self, ports="80,443", tuning=None, plugins=None,
                 ssl_mode=False, timeout=600):
        """Execute Nikto scan against the target."""
        xml_output = self.output_dir / f"nikto_{self.target.replace('/', '_')}.xml"
        cmd = ["nikto", "-h", self.target, "-port", ports,
               "-Format", "xml", "-output", str(xml_output), "-nointeractive"]
        if ssl_mode:
            cmd.extend(["-ssl"])
        if tuning:
            cmd.extend(["-Tuning", tuning])
        if plugins:
            cmd.extend(["-Plugins", plugins])

        try:
            result = subprocess.run(cmd, capture_output=True, text=True,
                                    timeout=timeout)
            return {"return_code": result.returncode,
                    "xml_output": str(xml_output),
                    "stderr": result.stderr[:500] if result.stderr else ""}
        except FileNotFoundError:
            return {"error": "nikto not installed. Install: apt install nikto"}
        except subprocess.TimeoutExpired:
            return {"error": f"Scan timed out after {timeout}s"}

    def parse_xml_results(self, xml_path=None):
        """Parse Nikto XML output into structured findings."""
        if xml_path is None:
            xml_path = self.output_dir / f"nikto_{self.target.replace('/', '_')}.xml"
        try:
            tree = ET.parse(xml_path)
            root = tree.getroot()
        except (ET.ParseError, FileNotFoundError) as exc:
            return {"error": str(exc)}

        for item in root.iter("item"):
            finding = {
                "id": item.get("id", ""),
                "osvdb": item.get("osvdbid", ""),
                "method": item.get("method", "GET"),
                "uri": "",
                "description": "",
                "references": [],
            }
            uri_elem = item.find("uri")
            if uri_elem is not None:
                finding["uri"] = uri_elem.text or ""
            desc_elem = item.find("description")
            if desc_elem is not None:
                finding["description"] = desc_elem.text or ""

            desc_lower = finding["description"].lower()
            if any(kw in desc_lower for kw in ["remote code", "rce", "command injection"]):
                finding["severity"] = "Critical"
            elif any(kw in desc_lower for kw in ["sql injection", "xss", "file inclusion"]):
                finding["severity"] = "High"
            elif any(kw in desc_lower for kw in ["directory listing", "information disclosure"]):
                finding["severity"] = "Medium"
            else:
                finding["severity"] = "Low"

            self.findings.append(finding)
        return self.findings

    def run_quick_scan(self, timeout=300):
        """Run a fast Nikto scan with essential checks only."""
        cmd = ["nikto", "-h", self.target, "-Tuning", "123", "-maxtime",
               str(timeout) + "s", "-nointeractive"]
        try:
            result = subprocess.run(cmd, capture_output=True, text=True,
                                    timeout=timeout + 30)
            lines = result.stdout.splitlines()
            for line in lines:
                if "+ " in line and "OSVDB" in line:
                    self.findings.append({
                        "description": line.strip().lstrip("+ "),
                        "severity": "Medium", "source": "stdout",
                    })
            return {"lines": len(lines), "findings": len(self.findings)}
        except (FileNotFoundError, subprocess.TimeoutExpired) as exc:
            return {"error": str(exc)}

    def generate_report(self):
        """Generate scan report with severity distribution."""
        severity_counts = {}
        for f in self.findings:
            sev = f.get("severity", "Info")
            severity_counts[sev] = severity_counts.get(sev, 0) + 1

        report = {
            "target": self.target,
            "scan_date": datetime.utcnow().isoformat(),
            "total_findings": len(self.findings),
            "severity_distribution": severity_counts,
            "findings": self.findings[:100],
        }
        report_path = self.output_dir / "nikto_report.json"
        with open(report_path, "w") as f:
            json.dump(report, f, indent=2)
        print(json.dumps(report, indent=2))
        return report


def main():
    target = sys.argv[1] if len(sys.argv) > 1 else "http://localhost"
    agent = NiktoScanAgent(target)
    result = agent.run_scan()
    if "error" not in result:
        agent.parse_xml_results()
    else:
        agent.run_quick_scan()
    agent.generate_report()


if __name__ == "__main__":
    main()
process.py12.0 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""
Nikto Web Application Scanning Automation

Automates Nikto scanning across multiple targets, parses results,
and generates consolidated vulnerability reports.

Requirements:
    pip install pandas defusedxml jinja2
    System: nikto installed and in PATH

Usage:
    python process.py scan --targets targets.txt --output-dir ./results
    python process.py parse --xml-dir ./results --report report.html
"""

import argparse
import os
import subprocess
import sys
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime
from pathlib import Path
from urllib.parse import urlparse

import defusedxml.ElementTree as ET
import pandas as pd


class NiktoScanner:
    """Automated Nikto web scanning manager."""

    def __init__(self, output_dir: str = "./nikto_results", timeout: int = 600):
        self.output_dir = Path(output_dir)
        self.output_dir.mkdir(parents=True, exist_ok=True)
        self.timeout = timeout
        self.results = []

    def scan_target(self, target: str, tuning: str = "123456789abc",
                    pause: int = 1, ssl: bool = False) -> dict:
        """Run Nikto scan against a single target."""
        parsed = urlparse(target if "://" in target else f"http://{target}")
        safe_name = parsed.netloc.replace(":", "_").replace("/", "_")
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        xml_output = self.output_dir / f"{safe_name}_{timestamp}.xml"

        cmd = [
            "nikto",
            "-h", target,
            "-Tuning", tuning,
            "-Pause", str(pause),
            "-timeout", "10",
            "-nointeractive",
            "-output", str(xml_output),
            "-Format", "xml",
        ]

        if ssl or parsed.scheme == "https":
            cmd.append("-ssl")

        result = {
            "target": target,
            "status": "unknown",
            "output_file": str(xml_output),
            "findings": [],
            "start_time": datetime.now().isoformat(),
        }

        print(f"[*] Scanning {target}...")
        try:
            proc = subprocess.run(
                cmd, capture_output=True, text=True, timeout=self.timeout
            )
            result["status"] = "completed"
            result["end_time"] = datetime.now().isoformat()
            result["stdout"] = proc.stdout[-2000:] if proc.stdout else ""
            result["stderr"] = proc.stderr[-500:] if proc.stderr else ""

            if xml_output.exists():
                result["findings"] = self.parse_xml(str(xml_output))
                finding_count = len(result["findings"])
                print(f"[+] {target}: {finding_count} findings")
            else:
                print(f"[!] {target}: No XML output generated")
                result["status"] = "no_output"

        except subprocess.TimeoutExpired:
            result["status"] = "timeout"
            print(f"[-] {target}: Scan timed out after {self.timeout}s")
        except FileNotFoundError:
            result["status"] = "error"
            result["error"] = "nikto not found in PATH"
            print("[-] Error: nikto not found. Install with: apt install nikto")
        except Exception as e:
            result["status"] = "error"
            result["error"] = str(e)
            print(f"[-] {target}: Error - {e}")

        self.results.append(result)
        return result

    def scan_targets(self, targets: list, max_parallel: int = 3, **kwargs) -> list:
        """Scan multiple targets with optional parallelism."""
        self.results = []

        with ThreadPoolExecutor(max_workers=max_parallel) as executor:
            futures = {
                executor.submit(self.scan_target, target, **kwargs): target
                for target in targets
            }
            for future in as_completed(futures):
                try:
                    future.result()
                except Exception as e:
                    target = futures[future]
                    print(f"[-] {target}: Scan failed - {e}")

        return self.results

    @staticmethod
    def parse_xml(xml_path: str) -> list:
        """Parse Nikto XML output into structured findings."""
        findings = []
        try:
            tree = ET.parse(xml_path)
            root = tree.getroot()

            for scan_details in root.findall(".//scandetails"):
                target_ip = scan_details.get("targetip", "")
                target_host = scan_details.get("targethostname", "")
                target_port = scan_details.get("targetport", "")
                target_banner = scan_details.get("targetbanner", "")

                for item in scan_details.findall("item"):
                    finding = {
                        "target_ip": target_ip,
                        "target_host": target_host,
                        "target_port": target_port,
                        "server_banner": target_banner,
                        "nikto_id": item.get("id", ""),
                        "osvdb_id": item.get("osvdbid", ""),
                        "osvdb_link": item.get("osvdblink", ""),
                        "method": item.get("method", "GET"),
                        "uri": item.findtext("uri", ""),
                        "description": item.findtext("description", ""),
                        "name_link": item.findtext("namelink", ""),
                        "ip_link": item.findtext("iplink", ""),
                    }

                    # Classify severity based on description keywords
                    desc_lower = finding["description"].lower()
                    if any(w in desc_lower for w in ["remote code", "command execution", "backdoor", "rce"]):
                        finding["severity"] = "Critical"
                    elif any(w in desc_lower for w in ["sql injection", "xss", "cross-site", "file inclusion"]):
                        finding["severity"] = "High"
                    elif any(w in desc_lower for w in ["directory listing", "information disclosure", "version"]):
                        finding["severity"] = "Medium"
                    elif any(w in desc_lower for w in ["header", "cookie", "x-frame"]):
                        finding["severity"] = "Low"
                    else:
                        finding["severity"] = "Info"

                    findings.append(finding)

        except Exception as e:
            print(f"[!] XML parse error for {xml_path}: {e}")

        return findings

    def generate_report(self, output_path: str):
        """Generate consolidated HTML report from all scan results."""
        all_findings = []
        for result in self.results:
            for finding in result.get("findings", []):
                finding["scan_target"] = result["target"]
                finding["scan_status"] = result["status"]
                all_findings.append(finding)

        if not all_findings:
            print("[-] No findings to report")
            return

        df = pd.DataFrame(all_findings)

        # Severity counts
        sev_counts = df["severity"].value_counts().to_dict()

        # Target summary
        target_summary = (df.groupby(["scan_target", "target_port"])
                          .agg(findings=("nikto_id", "count"),
                               critical=("severity", lambda x: (x == "Critical").sum()),
                               high=("severity", lambda x: (x == "High").sum()))
                          .reset_index())

        html = f"""<!DOCTYPE html>
<html>
<head>
    <title>Nikto Scan Report - {datetime.now().strftime('%Y-%m-%d')}</title>
    <style>
        body {{ font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }}
        .header {{ background: #16213e; color: white; padding: 20px; border-radius: 8px; }}
        .cards {{ display: flex; gap: 15px; margin: 20px 0; }}
        .card {{ background: white; padding: 20px; border-radius: 8px; flex: 1; text-align: center;
                 box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        .card h3 {{ margin: 0; font-size: 2em; }}
        table {{ width: 100%; border-collapse: collapse; background: white; margin: 15px 0;
                 border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        th {{ background: #2c3e50; color: white; padding: 10px; text-align: left; }}
        td {{ padding: 8px 10px; border-bottom: 1px solid #eee; font-size: 0.9em; }}
        .sev-critical {{ color: #e74c3c; font-weight: bold; }}
        .sev-high {{ color: #e67e22; font-weight: bold; }}
        .sev-medium {{ color: #f39c12; }}
        .sev-low {{ color: #3498db; }}
    </style>
</head>
<body>
    <div class="header">
        <h1>Nikto Web Scan Report</h1>
        <p>Targets: {len(self.results)} | Generated: {datetime.now().strftime('%Y-%m-%d %H:%M')}</p>
    </div>

    <div class="cards">
        <div class="card" style="border-top:4px solid #e74c3c"><h3>{sev_counts.get('Critical', 0)}</h3><p>Critical</p></div>
        <div class="card" style="border-top:4px solid #e67e22"><h3>{sev_counts.get('High', 0)}</h3><p>High</p></div>
        <div class="card" style="border-top:4px solid #f39c12"><h3>{sev_counts.get('Medium', 0)}</h3><p>Medium</p></div>
        <div class="card" style="border-top:4px solid #3498db"><h3>{sev_counts.get('Low', 0)}</h3><p>Low</p></div>
    </div>

    <h2>Target Summary</h2>
    <table>
        <tr><th>Target</th><th>Port</th><th>Total</th><th>Critical</th><th>High</th></tr>
        {''.join(f"<tr><td>{r.scan_target}</td><td>{r.target_port}</td><td>{r.findings}</td><td>{r.critical}</td><td>{r.high}</td></tr>" for r in target_summary.itertuples())}
    </table>

    <h2>All Findings</h2>
    <table>
        <tr><th>Target</th><th>Severity</th><th>URI</th><th>Description</th><th>OSVDB</th></tr>
        {''.join(f'<tr><td>{r.scan_target}</td><td class="sev-{r.severity.lower()}">{r.severity}</td><td>{r.uri}</td><td>{r.description[:150]}</td><td>{r.osvdb_id}</td></tr>' for r in df.sort_values("severity").itertuples())}
    </table>
</body>
</html>"""

        with open(output_path, "w", encoding="utf-8") as f:
            f.write(html)
        print(f"[+] Report saved to: {output_path}")


def main():
    parser = argparse.ArgumentParser(description="Nikto Web Scanning Automation")
    subparsers = parser.add_subparsers(dest="command")

    scan_p = subparsers.add_parser("scan", help="Scan web targets with Nikto")
    scan_p.add_argument("--targets", required=True, help="File with target URLs")
    scan_p.add_argument("--output-dir", default="./nikto_results")
    scan_p.add_argument("--report", default=None, help="HTML report output path")
    scan_p.add_argument("--tuning", default="123456789abc", help="Nikto tuning options")
    scan_p.add_argument("--parallel", type=int, default=3, help="Max parallel scans")
    scan_p.add_argument("--timeout", type=int, default=600, help="Per-target timeout")
    scan_p.add_argument("--pause", type=int, default=1, help="Pause between requests")

    parse_p = subparsers.add_parser("parse", help="Parse existing Nikto XML results")
    parse_p.add_argument("--xml-dir", required=True, help="Directory with Nikto XML files")
    parse_p.add_argument("--report", required=True, help="HTML report output path")

    args = parser.parse_args()

    if args.command == "scan":
        with open(args.targets) as f:
            targets = [line.strip() for line in f if line.strip() and not line.startswith("#")]

        scanner = NiktoScanner(args.output_dir, args.timeout)
        scanner.scan_targets(targets, max_parallel=args.parallel,
                             tuning=args.tuning, pause=args.pause)

        report_path = args.report or os.path.join(args.output_dir, "nikto_report.html")
        scanner.generate_report(report_path)

    elif args.command == "parse":
        scanner = NiktoScanner()
        xml_dir = Path(args.xml_dir)

        for xml_file in xml_dir.glob("*.xml"):
            findings = scanner.parse_xml(str(xml_file))
            scanner.results.append({
                "target": xml_file.stem,
                "status": "parsed",
                "findings": findings,
            })

        scanner.generate_report(args.report)

    else:
        parser.print_help()


if __name__ == "__main__":
    main()

Assets 1

template.mdtext/markdown · 1.0 KB
Keep exploring