Network and Service Scanning
#Scan Strategy
- Discover responsive hosts without expanding beyond the supplied target files.
- Run a bounded common-port scan.
- Run all TCP ports only against reviewed live hosts.
- Run a top UDP scan separately.
- Fingerprint discovered services and use targeted, non-destructive NSE scripts.
- Preserve XML output for parsing and reporting.
#Paste-Ready Nmap Orchestrator
Save as network-scan.sh. It reads only the approved ips.txt and cidrs.txt.
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
[[ -n "${ENGAGEMENT_ROOT:-}" ]] || { echo "Load engagement.env first"; exit 1; }
for tool in nmap python3; do
command -v "$tool" >/dev/null 2>&1 || { echo "Missing dependency: $tool"; exit 1; }
done
TARGETS="$NORMALIZED_DIR/approved-network-targets.txt"
OUT="$RAW_DIR/nmap-$(date -u +%Y%m%dT%H%M%SZ)"
mkdir -p "$OUT"
cat "$SCOPE_DIR/ips.txt" "$SCOPE_DIR/cidrs.txt" 2>/dev/null \
| sed -e 's/#.*$//' -e '/^[[:space:]]*$/d' | sort -u > "$TARGETS"
[[ -s "$TARGETS" ]] || { echo "No approved IP or CIDR targets"; exit 1; }
RATE="${SCAN_RATE:-500}"
echo "[*] Discovery against explicit scope"
nmap -sn -PE -PS22,80,443,445,3389 -PA80,443 -iL "$TARGETS" \
--excludefile "$SCOPE_DIR/exclude.txt" -oA "$OUT/01-discovery"
awk '/Status: Up/{print $2}' "$OUT/01-discovery.gnmap" | sort -u > "$OUT/live-hosts.txt"
[[ -s "$OUT/live-hosts.txt" ]] || { echo "No responsive hosts detected"; exit 0; }
echo "[*] Common TCP ports"
nmap -sS -Pn --top-ports 1000 --open --min-rate "$RATE" -T3 \
-iL "$OUT/live-hosts.txt" -oA "$OUT/02-top-tcp"
echo "[*] Full TCP ports"
nmap -sS -Pn -p- --open --min-rate "$RATE" -T3 \
-iL "$OUT/live-hosts.txt" -oA "$OUT/03-full-tcp"
echo "[*] Top UDP ports"
nmap -sU -Pn --top-ports 100 --open -T3 --max-retries 2 \
-iL "$OUT/live-hosts.txt" -oA "$OUT/04-top-udp"
TCP_PORTS="$(
python3 - "$OUT/03-full-tcp.xml" <<'PY'
import sys
import xml.etree.ElementTree as ET
ports = {
int(port.get("portid"))
for port in ET.parse(sys.argv[1]).getroot().findall("./host/ports/port")
if port.get("protocol") == "tcp"
and port.find("state") is not None
and port.find("state").get("state") == "open"
}
print(",".join(str(port) for port in sorted(ports)))
PY
)"
if [[ -n "$TCP_PORTS" ]]; then
echo "[*] Service fingerprinting on discovered TCP ports: $TCP_PORTS"
nmap -sV -sC -Pn -T3 --version-light -p "$TCP_PORTS" \
-iL "$OUT/live-hosts.txt" -oA "$OUT/05-services"
fi
echo "Raw and XML output: $OUT"
BASH
#Parse XML into CSV
python3 - "$OUT/05-services.xml" <<'PY'
import csv
import sys
import xml.etree.ElementTree as ET
root = ET.parse(sys.argv[1]).getroot()
writer = csv.writer(sys.stdout)
writer.writerow(["address", "protocol", "port", "state", "service", "product", "version"])
for host in root.findall("host"):
address = host.find("address").get("addr", "")
for port in host.findall("./ports/port"):
state = port.find("state")
service = port.find("service")
writer.writerow([
address,
port.get("protocol", ""),
port.get("portid", ""),
state.get("state", "") if state is not None else "",
service.get("name", "") if service is not None else "",
service.get("product", "") if service is not None else "",
service.get("version", "") if service is not None else "",
])
PY
BASH
#Targeted Validation Examples
Run only scripts that match a discovered service. Avoid broad --script vuln sweeps against fragile production systems.
nmap -Pn -p 443 --script ssl-cert,ssl-enum-ciphers <approved-ip>
nmap -Pn -p 445 --script smb-protocols,smb2-security-mode,smb2-time <approved-ip>
nmap -Pn -p 161 -sU --script snmp-info <approved-ip>
nmap -Pn -p 631 --script http-title,http-headers <approved-ip>
BASH
See Port Scanning with Nmap for scan flags, timing tradeoffs, and service-specific follow-up.