courses

Vulnerability Management

Finding and fixing weaknesses, continuously

Vulnerability management is the continuous process of identifying, classifying, prioritizing, remediating, and reporting on security vulnerabilities in systems and software. It spans the full lifecycle from dependency scanning in CI to runtime scanning of production infrastructure.

ℹ️ The hard part is rarely finding vulnerabilities — scanners produce more findings than any team can fix. The discipline is prioritization: using CVSS, exploitability, and asset value to fix the few that matter before attackers reach them. Most critical CVEs are exploited within days of disclosure, so this connects directly to threat modeling and patch cadence.

Vulnerability Scanning Fundamentals

A vulnerability scanner probes systems and software against databases of known weaknesses (CVEs, misconfigurations, CIS benchmarks). Scanners fall into several categories:

Category What it scans Examples
Network scanner Open ports, running services, banners Nmap, Nessus, OpenVAS
Web application scanner HTTP endpoints, forms, parameters Burp Suite, OWASP ZAP, Nikto
Container/image scanner OS packages, language libraries in images Trivy, Grype, Clair
Infrastructure scanner Cloud configurations, IaC files Checkov, tfsec, Prowler
Dependency scanner Language package dependencies Safety, Dependabot, Snyk

Vulnerability scanning is a point-in-time activity. Continuous scanning — integrated into CI/CD and scheduled against production — is required for an effective program.

Nmap

Nmap is the standard open-source network discovery and security auditing tool. It discovers hosts, open ports, running services, and their versions.

Basic scanning

# Host discovery (ping scan — no port scan)
nmap -sn 192.168.1.0/24

# TCP SYN scan (default; requires root/sudo)
sudo nmap -sS 192.168.1.100

# Full TCP connect scan (no root required)
nmap -sT 192.168.1.100

# UDP scan (slow; important — many services run on UDP)
sudo nmap -sU 192.168.1.100

# Scan specific ports
nmap -p 22,80,443,8080 192.168.1.100

# Scan all 65535 ports
nmap -p- 192.168.1.100

Service and version detection

# Service version detection
nmap -sV 192.168.1.100

# OS detection (requires root)
sudo nmap -O 192.168.1.100

# Aggressive scan: OS, version, scripts, traceroute
sudo nmap -A 192.168.1.100

# Default NSE scripts (safe reconnaissance)
nmap -sC 192.168.1.100

Nmap Scripting Engine (NSE)

# Run specific NSE scripts
nmap --script http-title 192.168.1.100
nmap --script ssl-enum-ciphers -p 443 192.168.1.100
nmap --script vuln 192.168.1.100        # run all vulnerability scripts

# Check for specific vulnerabilities
nmap --script smb-vuln-ms17-010 192.168.1.100   # EternalBlue
nmap --script http-shellshock 192.168.1.100
nmap --script ssh-brute --script-args userdb=users.txt 192.168.1.100

# List available scripts
ls /usr/share/nmap/scripts/
ls /usr/share/nmap/scripts/ | grep http

Output formats

# Normal output to file
nmap -oN scan-results.txt 192.168.1.0/24

# XML output (for parsing and import into tools)
nmap -oX scan-results.xml 192.168.1.0/24

# Grepable output
nmap -oG scan-results.gnmap 192.168.1.0/24

# All formats simultaneously
nmap -oA scan-results 192.168.1.0/24
# Parse Nmap XML output with python-nmap
import nmap

nm = nmap.PortScanner()
nm.scan('192.168.1.0/24', '22,80,443', arguments='-sV')

for host in nm.all_hosts():
    print(f"\nHost: {host} ({nm[host].hostname()})")
    print(f"State: {nm[host].state()}")
    for proto in nm[host].all_protocols():
        ports = nm[host][proto].keys()
        for port in ports:
            state = nm[host][proto][port]['state']
            service = nm[host][proto][port]['name']
            version = nm[host][proto][port].get('version', '')
            print(f"  {proto}/{port}: {state} ({service} {version})")

Worked example — audit a web server for security issues:

# Comprehensive web server assessment
sudo nmap -sV -sC -p 80,443,8080,8443 \
    --script "http-*,ssl-*" \
    -oA webserver-audit \
    192.168.1.100

# Key things to check in output:
# - SSL/TLS protocol versions (reject SSLv3, TLS 1.0, TLS 1.1)
# - Cipher suite strength (reject RC4, DES, 3DES, EXPORT)
# - HTTP methods allowed (DELETE, PUT, TRACE should be disabled)
# - Server version disclosure (hide with server_tokens off in nginx)
# - Missing security headers

OpenVAS / Greenbone

OpenVAS (Open Vulnerability Assessment System) is a full-featured network vulnerability scanner, now part of the Greenbone Community Edition. It maintains a continuously updated database of Network Vulnerability Tests (NVTs).

# Install Greenbone Community Edition (Docker-based)
curl -f -L https://greenbone.github.io/docs/latest/_static/setup-and-start-greenbone-community-edition.sh \
    | bash

# Or with docker compose directly
docker compose -f greenbone-community-edition.yml up -d

# Access the web interface
# https://localhost:9392
# Default credentials: admin / admin (change immediately)
# gvm-cli: command-line interface to OpenVAS/Greenbone
pip install gvm-tools

# List available scan configurations
gvm-cli --gmp-username admin --gmp-password admin socket \
    --xml "<get_scan_configs/>"

# Create and start a scan via XML GMP protocol
gvm-cli socket --xml "
<create_task>
  <name>Weekly Scan</name>
  <config id='daba56c8-73ec-11df-a475-002264764cea'/>
  <target id='TARGET-UUID'/>
</create_task>"
# Python: interact with OpenVAS via python-gvm
from gvm.connections import UnixSocketConnection
from gvm.protocols.gmp import Gmp
from gvm.transforms import EtreeTransform

connection = UnixSocketConnection(path='/run/gvmd/gvmd.sock')
transform = EtreeTransform()

with Gmp(connection, transform=transform) as gmp:
    gmp.authenticate('admin', 'admin')

    # List all tasks
    tasks = gmp.get_tasks()
    for task in tasks.findall('task'):
        name = task.find('name').text
        status = task.find('status').text
        print(f"{name}: {status}")

Nessus / Qualys

Nessus (Tenable) and Qualys are commercial vulnerability scanners widely used in enterprise environments. They provide the same core function as OpenVAS with vendor support, compliance reporting, and cloud integrations.

Nessus basics

# Nessus runs as a web service
# Access: https://localhost:8834

# Nessus CLI via the API
curl -k -X POST https://localhost:8834/session \
    -H "Content-Type: application/json" \
    -d '{"username":"admin","password":"password"}' \
    | python3 -m json.tool
# Python: automate Nessus scans via REST API
import requests
import json

NESSUS_URL = 'https://localhost:8834'
SESSION = requests.Session()
SESSION.verify = False   # self-signed cert on Nessus server

# Authenticate
resp = SESSION.post(f'{NESSUS_URL}/session',
                    json={'username': 'admin', 'password': 'password'})
token = resp.json()['token']
SESSION.headers.update({'X-Cookie': f'token={token}'})

# List scans
scans = SESSION.get(f'{NESSUS_URL}/scans').json()
for scan in scans.get('scans', []):
    print(f"{scan['id']}: {scan['name']}{scan['status']}")

# Get vulnerabilities from a completed scan
scan_id = 5
detail = SESSION.get(f'{NESSUS_URL}/scans/{scan_id}').json()
for vuln in detail.get('vulnerabilities', []):
    print(f"CVSS {vuln['severity']}: {vuln['plugin_name']} ({vuln['count']} hosts)")

Qualys integration

# Python: Qualys VMDR API
import requests
from base64 import b64encode

QUALYS_URL = 'https://qualysapi.qualys.com'
credentials = b64encode(b'username:password').decode()
headers = {
    'Authorization': f'Basic {credentials}',
    'X-Requested-With': 'Python',
}

# Launch a vulnerability scan
resp = requests.post(
    f'{QUALYS_URL}/api/2.0/fo/scan/',
    headers=headers,
    data={
        'action': 'launch',
        'scan_title': 'Weekly Production Scan',
        'target_from': 'assets',
        'asset_group_ids': '12345',
        'option_id': '67890',
    }
)

Burp Suite

Burp Suite is the professional-grade web application security testing platform. The Community Edition is free; Pro adds an automated scanner and more tools.

Setting up Burp as a proxy

# Launch Burp Suite (GUI)
java -jar burpsuite_community.jar

# Configure browser to use Burp proxy: 127.0.0.1:8080

# Install Burp's CA certificate in browser to intercept HTTPS:
# Navigate to: http://burpsuite (while proxy is active)
# Download and install the cacert.der

# Command-line: use Burp with curl
curl -x http://127.0.0.1:8080 --proxy-insecure https://target.example.com

Burp Suite tools

Tool Purpose
Proxy Intercept, inspect, and modify HTTP/HTTPS traffic
Repeater Replay and modify individual requests
Intruder Automated payload injection (brute force, fuzzing)
Scanner Automated vulnerability scanning (Pro only)
Decoder Encode/decode Base64, URL, HTML, hex, etc.
Comparer Diff two requests or responses
Logger Full traffic log with filtering

Burp REST API (Pro)

# Burp Suite Professional REST API
import requests

BURP_API = 'http://localhost:1337/v0.1'

# Start a scan
resp = requests.post(f'{BURP_API}/scan', json={
    'urls': ['https://target.example.com'],
    'scan_configurations': [{'name': 'Audit checks - all issues'}],
    'application_logins': [{
        'username': 'testuser',
        'password': 'testpass',
    }],
})
task_id = resp.json()['task_id']

# Poll for completion
import time
while True:
    status = requests.get(f'{BURP_API}/scan/{task_id}').json()
    if status['scan_metrics']['crawl_and_audit_progress'] == 100:
        break
    time.sleep(30)

# Get issues
issues = requests.get(f'{BURP_API}/scan/{task_id}/issues').json()
for issue in issues:
    print(f"{issue['severity']}: {issue['issue_type']['name']} at {issue['path']}")

Infrastructure as Code Security Scanning

IaC files (Terraform, Kubernetes manifests, Dockerfile, CloudFormation) contain configuration that can introduce security vulnerabilities.

Checkov

Checkov scans IaC files for misconfigurations against hundreds of built-in checks aligned to CIS Benchmarks and cloud provider best practices:

# Install
pip install checkov

# Scan a Terraform directory
checkov -d infrastructure/

# Scan a specific file
checkov -f kubernetes/deployment.yaml

# Scan a Docker file
checkov -f Dockerfile

# Output as JSON
checkov -d infrastructure/ -o json > checkov-report.json

# Fail on HIGH severity only
checkov -d infrastructure/ --compact --soft-fail-on MEDIUM,LOW

# Skip specific checks (with documented justification)
checkov -d infrastructure/ --skip-check CKV_AWS_18,CKV_AWS_21
# Parse Checkov JSON output
import subprocess
import json

result = subprocess.run(
    ['checkov', '-d', 'infrastructure/', '-o', 'json'],
    capture_output=True, text=True
)
data = json.loads(result.stdout)

passed = data['summary']['passed']
failed = data['summary']['failed']
print(f"Passed: {passed}, Failed: {failed}")

for check in data.get('results', {}).get('failed_checks', []):
    print(f"FAIL {check['check_id']}: {check['check_result']['result']} — "
          f"{check['resource']} in {check['file_path']}:{check['file_line_range']}")

tfsec

tfsec is a Terraform-specific security scanner. Aqua has folded tfsec into Trivy, which now performs the same checks via trivy config <dir> (or trivy fs); tfsec itself is in maintenance mode, so prefer Trivy for new work and treat the commands below as legacy:

# Install
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash

# Scan Terraform files
tfsec .

# Show only HIGH and CRITICAL
tfsec . --minimum-severity HIGH

# JSON output
tfsec . --format json > tfsec-report.json

# Ignore a specific rule inline
resource "aws_s3_bucket" "logs" {
  bucket = "my-logs"
  # tfsec:ignore:aws-s3-enable-bucket-logging
}

Automated patching

Keeping systems and dependencies patched is the single most effective vulnerability management activity. Most critical vulnerabilities are exploited in the wild within days of public disclosure.

# Debian/Ubuntu: configure unattended security upgrades
apt install unattended-upgrades
dpkg-reconfigure --priority=low unattended-upgrades

# /etc/apt/apt.conf.d/50unattended-upgrades
# Unattended-Upgrade::Allowed-Origins {
#     "${distro_id}:${distro_codename}-security";
# };
# Unattended-Upgrade::Automatic-Reboot "false";
# Unattended-Upgrade::Mail "ops@example.com";

# Check what would be upgraded
unattended-upgrade --dry-run --debug

# FreeBSD: apply security patches
freebsd-update fetch && freebsd-update install

# Python dependencies: use Dependabot or Renovate
# .github/dependabot.yml
# version: 2
# updates:
#   - package-ecosystem: pip
#     directory: /
#     schedule:
#       interval: weekly
#     open-pull-requests-limit: 10
# Python: check for outdated packages and CVEs
import subprocess
import json

# List outdated pip packages
result = subprocess.run(
    ['pip', 'list', '--outdated', '--format', 'json'],
    capture_output=True, text=True
)
outdated = json.loads(result.stdout)
for pkg in outdated:
    print(f"{pkg['name']}: {pkg['version']}{pkg['latest_version']}")

# Check for CVEs with safety
result = subprocess.run(
    ['safety', 'check', '--json'],
    capture_output=True, text=True
)
vulns = json.loads(result.stdout)
for v in vulns.get('vulnerabilities', []):
    print(f"CVE {v['vulnerability_id']}: {v['package_name']} {v['analyzed_version']} "
          f"— fix in {v['safe_versions']}")

Key takeaways

References


Related course pages: Introduction to Recon · Threat Modeling · DevSecOps Fundamentals

🛠️ Maintenance note: scanner tooling churns — Nessus/Qualys API shapes shift between versions, and the Python safety CLI now requires account auth (safety check was replaced by safety scan). Re-verify the install commands and JSON field names against current releases each term, and note CVSS v4.0 now coexists with v3.1 in the NVD.