Last active
April 27, 2026 10:18
-
-
Save dreizehnutters/c235ffeb2b4b8e915908e335738381de to your computer and use it in GitHub Desktop.
staggered nmap scan
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -uo pipefail | |
| usage() { | |
| echo "$0 <NET_IN_CIDR>|<FILE> [--check]" | |
| echo "$0 <RESULTS_DIR> --ports" | |
| } | |
| if [ $# -lt 1 ] || [ -z "${1:-}" ]; then | |
| usage | |
| exit 1 | |
| fi | |
| NET=$1 | |
| bold=$(tput bold) | |
| normal=$(tput sgr0) | |
| error="${bold}[!]${normal}" | |
| XMLS="$(command -v xmlstarlet)" || { | |
| echo "${error} Required command 'xmlstarlet' not found" | |
| exit 1 | |
| } | |
| NMAP_BIN="$(command -v nmap)" || { | |
| echo "${error} Required command 'nmap' not found" | |
| exit 1 | |
| } | |
| PROFILE_NMAP_OPTIONS=( | |
| -T5 | |
| --min-rate=500 | |
| --min-hostgroup=16 | |
| ) | |
| SLOW_PROFILE_NMAP_OPTIONS=( | |
| -T2 | |
| --min-rate=200 | |
| --min-hostgroup=4 | |
| ) | |
| COMMON_NMAP_OPTIONS=( | |
| --privileged | |
| -v | |
| -d1 | |
| -Pn | |
| --reason | |
| --stats-every=10 | |
| --open | |
| --script-timeout=90s | |
| ) | |
| NSE_SCRIPTS=( | |
| default version banner vulners | |
| http-title http-server-header http-headers http-methods https-redirect | |
| http-enum http-auth http-cookie-flags http-security-headers http-robots.txt | |
| http-config-backup http-default-accounts http-git http-open-proxy | |
| http-passwd http-webdav-scan http-userdir-enum http-errors http-devframework | |
| ssl-cert ssl-enum-ciphers ssl-date ssl-known-key | |
| smb-os-discovery smb-security-mode smb2-security-mode | |
| smb-enum-shares smb-enum-users smb-enum-domains smb-protocols | |
| smb-enum-groups smb-enum-sessions | |
| snmp-info snmp-interfaces snmp-netstat | |
| snmp-hh3c-logins snmp-win32-users snmp-win32-services snmp-win32-software | |
| rpcinfo nfs-showmount | |
| mysql-info mongodb-info ms-sql-info ms-sql-ntlm-info | |
| smtp-commands smtp-ntlm-info imap-capabilities pop3-capabilities | |
| ldap-rootdse rdp-ntlm-info rdp-enum-encryption | |
| ldap-search ldap-novell-getpass | |
| ssh2-enum-algos ssh-hostkey ssh-auth-methods ssh-publickey-acceptance | |
| ntp-info dns-recursion dns-nsid dns-service-discovery | |
| ftp-anon ftp-syst telnet-encryption | |
| vnc-info vnc-title | |
| rtsp-methods | |
| modbus-discover | |
| sip-methods sip-enum-users | |
| ipmi-version ipmi-cipher-zero | |
| redis-info memcached-info docker-version | |
| s7-info enip-info bacnet-info knx-gateway-discover knx-gateway-info | |
| ajp-methods ajp-request rsync-list-modules x11-access mqtt-subscribe auth-owners amqp-info | |
| openflow-info rmi-dumpregistry nntp-ntlm-info openlookup-info ip-geolocation-geoplugin | |
| ) | |
| NSE_SCRIPT_STRING=$(IFS=,; echo "${NSE_SCRIPTS[*]}") | |
| NMAP_OPTIONS=( | |
| "${COMMON_NMAP_OPTIONS[@]}" | |
| "${PROFILE_NMAP_OPTIONS[@]}" | |
| ) | |
| get_ports_from_XML() { | |
| local nmap_path="${1}" | |
| local result | |
| result="$( | |
| "$XMLS" sel -t \ | |
| -m '//port/state[@state="open"]/parent::port' \ | |
| -v './@portid' -n \ | |
| "${nmap_path}"/*.xml 2>/dev/null \ | |
| | sort -u -V \ | |
| | paste -sd, - | |
| )" | |
| if [ -z "$result" ]; then | |
| return 1 | |
| fi | |
| echo "$result" | |
| } | |
| is_valid_cidr() { | |
| local cidr="${1}" | |
| local cidr_pattern='^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$' | |
| if ! [[ $cidr =~ $cidr_pattern ]]; then | |
| echo "${error} Invalid CIDR notation: ${cidr}" | |
| exit 1 | |
| fi | |
| } | |
| exit_fun() { | |
| local rc="${1:-0}" | |
| local msg="${2:-}" | |
| if [ -n "${SUDO_UID:-}" ] && [ -n "${SUDO_GID:-}" ] && [ -n "${NET_PATH:-}" ]; then | |
| chown -hR "${SUDO_UID}:${SUDO_GID}" "$NET_PATH" 2>/dev/null || true | |
| fi | |
| [ -n "$msg" ] && echo "$msg" | |
| exit "$rc" | |
| } | |
| if [[ -f "${NET}" ]]; then | |
| INPUT=(-iL "${NET}") | |
| VERBOSE="$(tr '\n' ',' < "${NET}")" | |
| elif [[ -d "${NET}" ]]; then | |
| if [ "${2:-}" != "--ports" ]; then | |
| echo "${error} Directory input is only valid with --ports" | |
| exit 1 | |
| fi | |
| INPUT=() | |
| VERBOSE="${NET}" | |
| else | |
| is_valid_cidr "$NET" | |
| INPUT=("${NET}") | |
| VERBOSE="${NET}" | |
| fi | |
| if [ "${2:-}" = "--ports" ]; then | |
| echo "${bold}[[[[ grepping open ports ]]]]${normal}" | |
| get_ports_from_XML "$1" || exit 1 | |
| exit 0 | |
| fi | |
| if [ "$EUID" -ne 0 ]; then | |
| echo "${error} Please run as root (or set capabilities)" | |
| echo "sudo setcap cap_net_raw,cap_net_admin,cap_net_bind_service+eip ${NMAP_BIN}" | |
| exit 1 | |
| fi | |
| NET_PATH="${PWD}/nmap-$(echo "${NET}" | tr '.' '_' | tr '\/' '-')-$(date +%s)" | |
| mkdir -p "${NET_PATH}" | |
| PF=$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c4) | |
| if [ "${2:-}" = "--check" ]; then | |
| echo "${bold}[[[[ max-coverage host discovery on ${VERBOSE} -> hosts_${PF}.xml ]]]]${normal}" | |
| "$NMAP_BIN" \ | |
| -sn \ | |
| -PR \ | |
| -PE -PP \ | |
| -PS22,80,443 \ | |
| -PA80,443 \ | |
| -PU53,161 \ | |
| -v -d1 \ | |
| --stats-every=10 \ | |
| -oA "${NET_PATH}/hosts_${PF}" \ | |
| "${INPUT[@]}" | |
| rc=$? | |
| [ $rc -ne 0 ] && exit_fun "$rc" "${error} host discovery FAILED" | |
| echo "${bold}[[[[ the following hosts are reachable ]]]]${normal}" | |
| "$XMLS" sel -t \ | |
| -m "//host[status/@state='up']" \ | |
| -v "concat(address[@addrtype='ipv4']/@addr, ' ', hostnames/hostname/@name)" -n \ | |
| "${NET_PATH}/hosts_${PF}.xml" \ | |
| | sed '/^[[:space:]]*$/d' \ | |
| | tee "${NET_PATH}/up_hosts_${PF}.txt" | |
| echo "${bold}[[[[ the following hosts did not respond ]]]]${normal}" | |
| "$XMLS" sel -t \ | |
| -m "//host[status/@state='down']" \ | |
| -v "concat(address[@addrtype='ipv4']/@addr, ' ', hostnames/hostname/@name)" -n \ | |
| "${NET_PATH}/hosts_${PF}.xml" \ | |
| | sed '/^[[:space:]]*$/d' \ | |
| | tee "${NET_PATH}/down_hosts_${PF}.txt" | |
| UP_XML_COUNT=$("$XMLS" sel -t -v "count(//host[status/@state='up'])" \ | |
| "${NET_PATH}/hosts_${PF}.xml") | |
| UP_TXT_COUNT=$(wc -l < "${NET_PATH}/up_hosts_${PF}.txt") | |
| if [ "$UP_XML_COUNT" -ne "$UP_TXT_COUNT" ]; then | |
| echo "${error} Host count mismatch! XML=${UP_XML_COUNT}, TXT=${UP_TXT_COUNT}" | |
| fi | |
| exit_fun 0 "${bold}[[[[ finished ${NET_PATH} ]]]]${normal}" | |
| fi | |
| echo "${bold}[[[[ working in ${NET_PATH} ]]]]${normal}" | |
| echo "${bold}[[[[ min tcp scan for ${VERBOSE} ]]]]${normal}" | |
| "$NMAP_BIN" \ | |
| "${NMAP_OPTIONS[@]}" \ | |
| -p- -sS \ | |
| -oA "${NET_PATH}/init_${PF}" \ | |
| "${INPUT[@]}" | |
| rc=$? | |
| [ $rc -ne 0 ] && exit_fun "$rc" "${error} min tcp scan FAILED" | |
| TCP_PORTS="$(get_ports_from_XML "${NET_PATH}")" || exit_fun 1 "${error} No open TCP ports found after pass 1" | |
| echo "${bold}[[[ script='default++' scan on: ${TCP_PORTS} on ${VERBOSE} ]]]${normal}" | |
| "$NMAP_BIN" \ | |
| "${NMAP_OPTIONS[@]}" \ | |
| -p"${TCP_PORTS}" \ | |
| -sV \ | |
| --script "$NSE_SCRIPT_STRING" \ | |
| -O \ | |
| --version-intensity 7 \ | |
| -oA "${NET_PATH}/version_${PF}" \ | |
| "${INPUT[@]}" | |
| rc=$? | |
| [ $rc -ne 0 ] && exit_fun "$rc" "${error} version scan FAILED" | |
| echo "${bold}[[[[ nmap min udp for ${VERBOSE} ]]]]${normal}" | |
| "$NMAP_BIN" \ | |
| "${NMAP_OPTIONS[@]}" \ | |
| --top-ports=100 \ | |
| -sUV \ | |
| --version-intensity 7 \ | |
| -oA "${NET_PATH}/uinit_${PF}" \ | |
| "${INPUT[@]}" | |
| rc=$? | |
| [ $rc -ne 0 ] && exit_fun "$rc" "${error} UDP scan FAILED" | |
| exit_fun 0 "${bold}[[[[ finished ${NET_PATH} ]]]]${normal}" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Automates network scanning tasks using Nmap, extracting information such as open ports and host statuses. Supports scanning a specified CIDR range or input file. Provides options for TCP, UDP, and version detection scans with configurable parameters. Outputs scan results to organized directories for further analysis.
Features
CIDR Range or File Input: The script supports scanning either a specified CIDR range or an input file containing a list of hosts.
Staggered Approach to Scanning: The script employs a staggered approach to scanning, minimizing overhead by setting appropriate options for scanning speed and host group size.
Optional Host Scan: Includes an option to perform a subnet scan to check the reachability of hosts within a specified CIDR range. This generates hosts.xml and provides insights into the status of hosts.
Grepping of Open Ports: Provides an option to extract and list all open ports from existing Nmap XML files, allowing for targeted analysis and exploration of network services.
Automated Directory Organization: Scan results are automatically organized into directories based on the provided input, facilitating easy access and analysis.
Usage
Input Specification:
./network_scan.sh <CIDR>./network_scan.sh <file>Options:
--check: Performs a subnet scan to generatehosts.xmland checks the reachability of hosts.--ports: Extracts and lists open ports from existing Nmap XML files.Prerequisites:
sudo apt install nmap xmlstarlet).Execution:
Example Usage