black electronics

Port Scanning

Port Enumeration

Port Enumeration

Port scanning is the method used to identify open ports and services on a network or system. In penetration testing, it helps security professionals detect vulnerabilities, understand the network structure, and pinpoint potential entry points for unauthorized access.

Nmap

Nmap, short for “Network Mapper,” is a powerful open-source tool used for network discovery and security auditing. It’s one of the most popular and widely used network scanning tools in the cybersecurity community. You can find a comprehensive cheat sheet and links to download Nmap.

Port Scanning

The following are some commands I commonly use with the Nmap tool to port scan targets and networks.

Terminal window
sudo nmap -sTCV -O -A 10.1.1.1 -p 1-65535 -oA All_TCP_ports # Performs a TCP connect and default script scan of all ports on a target with output in all formats with advanced scanning techniques enabled
sudo nmap -sTCV -A -O -iL IPs.txt -Pn -p- -oX targets.xml # Performs a TCP connect and default script scan of all ports on a list of targets with no ping and advanced scanning techniques enabled and output to XML file
sudo nmap -sTCV -A -v -Pn -p- 10.1.1.1 # Performs a TCP connect and default script scan of all ports on a target with no ping enabled

Port Sweep

An Nmap port sweep is a technique used to scan a range of IP addresses for specific open ports. This method is useful for identifying which devices on a network are running specific services associated with particular ports.

Terminal window
sudo nmap -p80 10.1.1.1-254 # Performs a ping sweep of port 80 across the specified IP range
sudo nmap -p22 10.1.1.0/24 # Performs a ping sweep of port 22 across the specified CIDR

Masscan

Masscan is known for its speed, making it possible to scan the entire Internet in minutes. It uses asynchronous transmission to achieve high speeds, making it ideal for large-scale scanning operations. You can find Masscan here.

Terminal window
masscan -p1-65535 10.1.1.1 --rate=1000 # Scans all TCP ports on the target IP with a rate of 1000 packets per second
masscan 10.1.1.1/24 -p80,443,22 --rate 5000 # Scans common ports on a subnet
masscan -iL targets.txt -p1-1000 --rate 10000 # Read target IPs from file
masscan 10.1.1.1/24 -p80 --source-ip 10.1.1.1 # Spoof source IP
masscan 10.1.1.1/24 -p80 --spoof-mac 00:11:22:33:44:55 # Spoof MAC address

Here is a list of common commands I use with Masscan and the most common ports I’ve seen on engagements.

Terminal window
sudo masscan -p 21,22,23,53,80,111,135,445,139,443,389,1521,3306,8080,8081,1433,8200,8500,8999,9000,10000,8443 10.1.1.0/24 --rate 1500
sudo masscan 10.1.1.0/22 -p 1-65535 --banners --rate 1000
sudo masscan -iL External_IPs.txt -p 1-65535 --rate 500 --http-user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0"

You can use the following script to take in Masscan results and produce an output which can be fed into Nmap:

# This script will take in Masscan results and produce an output which can be fed into NMap
# Save your Masscan result as mscan.txt then run this script to produce nmap.txt then you can run:
# while read item; do sudo nmap -sV -sA -sU $item; done < nmap.txt
# If you want to export to .xml file you can use the following command and then later use this script to merge files: https://github.com/sidaf/scripts/blob/master/nmap_merge.py
# while read item; do filename=$(echo $item | grep -o "^\S*"); sudo nmap -sV -sA -sU -vv $item -oX $filename.xml; done < nmap.txt
import re
import socket
regex = re.compile(r"Discovered open port (\d+)\/(udp|tcp) on (\d+\.\d+\.\d+\.\d+)", re.I)
ip_list = {}
with open('mscan.txt') as f:
lines = f.readlines()
for line in lines:
port = regex.match(line).group(1)
protocol = regex.match(line).group(2)
ip = regex.match(line).group(3)
# Add the IP to dictionary if it's not already
try:
ip_list[ip]
except KeyError:
ip_list[ip] = {}
# Add protocol to dictionary if it's not already
try:
ip_list[ip][protocol]
except KeyError:
ip_list[ip][protocol] = []
# Append the port to the list
ip_list[ip][protocol].append(port)
with open('nmap.txt', 'a') as f:
sorted_ips = sorted(ip_list.items(), key=lambda item: socket.inet_aton(item[0]))
for ip, protocols in sorted_ips:
udp_ports = ""
tcp_ports = ""
# Check to see if any UDP ports were found
try:
for port in protocols['udp']:
udp_ports += port + ','
except KeyError:
pass
# Check to see if any TCP ports were found
try:
for port in protocols['tcp']:
tcp_ports += port + ','
except KeyError:
pass
# Print IP and ports to file ready for NMap scan
if udp_ports and tcp_ports:
line = ip + ' -p U:' + udp_ports + 'T:' + tcp_ports
elif udp_ports:
line = ip + ' -p U:' + udp_ports
elif tcp_ports:
line = ip + ' -p T:' + tcp_ports
f.write(line + '\n')

Save your Masscan result as mscan.txt, and then run this script to produce nmap.txt. Then you can run:

Terminal window
while read item; do filename=$(echo $item | grep -o "^\S*"); sudo nmap -sCV -T4 -O --version-light -vv $item -oX $filename.xml; done < ../nmap.txt
while read item; do filename=$(echo $item | grep -o "^\S*"); sudo nmap -sCV -T4 -O -F --version-light -vv $item -oX $filename.xml; done < nmap.txt

Scanning the whole internet

You can scan the whole internet for port 80 for example using the following:

Terminal window
sudo masscan -p 80 0.0.0.0/0 --rate 1000000 --exclude 255.255.255.255 > port80.txt

Once you have a list of IP addresses with port 80 open you can run it through a tool like HTTPX to get the title of the web page running on the port.

Terminal window
httpx -l port80.txt -ports 80 -title -no-color > port80_titles.txt
httpx -list Web_Ports.txt -p 80,443 -silent -sc -location -title -server -mc 200 -fr

ZMap

ZMap is a free, open-source security scanner developed as a faster alternative to Nmap. ZMap can scan the entire IPv4 address space in 44 minutes on a single port using one gigabit per second of network bandwidth. It can complete a scan in under five minutes with a ten-gigabit connection. You can find the details, as well as installation instructions for Zmap, here.

Terminal window
zmap -p 80 10.1.1.0/24 -o results.csv # Scans port 80 across the specified subnet and outputs the results to a CSV file
zmap -p 22,80,443 --target-ip=10.1.1.1 -o output.txt # Scan SSH, HTTP, and HTTPS on a single IP
zmap -p 23 -o telnet_scan.txt --rate=1000000 # Scan the whole internet for open Telnet ports

RustScan

RustScan is a fast port scanner written in Rust that quickly identifies open TCP ports and can automatically pipe the results into Nmap for service enumeration. You can find it here: https://github.com/RustScan/RustScan

Terminal window
rustscan -a 10.1.1.1 # Scan a target for open ports and pass them to Nmap
rustscan -a 10.1.1.1,10.1.1.2 # Scan multiple targets
rustscan -a 10.1.1.0/24 # Scan a CIDR range
rustscan -a 10.1.1.1 -p 22,80,443,445,3389 # Scan a specific list of ports
rustscan -a 10.1.1.1 -r 1-1000 # Scan a specific port range
rustscan -a 10.1.1.1 -r 1-65535 # Scan the full TCP port range

Arguments after -- are passed straight through to Nmap, so any Nmap flags and output options can be used as normal.

Terminal window
rustscan -a 10.1.1.1 -- -sC -sV # Run Nmap default scripts and service detection on discovered ports
rustscan -a 10.1.1.1 -- -sC -sV -Pn # Same as above, skipping the ping check for hosts that don't respond to ICMP
rustscan -a 10.1.1.1 -- -sT -sC -sV -T4 -Pn # Use a TCP connect scan instead of a SYN scan
rustscan -a 10.1.1.1 -- --script vuln -sV -Pn # Run Nmap's vulnerability scripts against discovered ports
rustscan -a 10.1.1.1 -r 1-65535 -- -sC -sV -Pn -oA initial # Full port range scan piped into Nmap, saving output in all formats

RustScan scans in batches, and the batch size and connection timeout can be tuned to trade off speed against reliability and the likelihood of triggering defensive controls.

Terminal window
rustscan -a 10.1.1.1 -b 5000 # Increase batch size for faster scanning
rustscan -a 10.1.1.1 -t 5000 # Increase the connection timeout (ms) for slower or higher-latency networks
OptionDescription
-aTarget IP, hostname, or list of addresses
-pSpecific ports
-rPort range
-bBatch size
-tConnection timeout (ms)
--Pass all following arguments to Nmap

Naabu

When pentesting a large number of systems, running detailed Nmap scans against every host can quickly become time-consuming. Naabu is a fast port scanner developed by ProjectDiscovery that’s great at first identifying which hosts and ports are actually reachable, before handing the interesting ones off to a tool like Nmap for detailed enumeration. Its simple output also makes it easy to pipe into other reconnaissance tools. You can find it here: https://github.com/projectdiscovery/naabu

Terminal window
naabu -host 10.1.1.1 # Scan a single host
naabu -host 10.1.1.0/24 # Scan a network range
naabu -list hosts.txt # Scan a list of targets

Combining with Other Tools

Naabu’s output pipes cleanly into other reconnaissance tools, which is particularly useful during external engagements where subdomains discovered via Subfinder need to be checked for exposed services.

Terminal window
subfinder -d example.com -silent | naabu -silent # Feed discovered subdomains straight into Naabu
naabu -list hosts.txt -silent | httpx -silent # Identify which open ports are actually serving HTTP
subfinder -d example.com -silent | naabu -silent | httpx -silent # Chain subdomain enumeration, port discovery and HTTP probing together

Web applications, APIs and admin interfaces aren’t always exposed on 80/443 — non-standard ports such as 8000, 8080, 8081, 8443, 8888, 9000 and 9090 are worth including when scanning for web services.

ASN and Large Range Scanning

Terminal window
echo AS3741 | naabu -p 80,443 -passive -v -rate 10 # Scan the address space associated with an Autonomous System (only within authorised scope)
naabu -host 10.1.0.0/16 -p 80,443 -rate 1000 -silent # Scan a large range for HTTP/HTTPS services, tuning -rate to the target environment

Finding Exposed Configuration Files

Naabu can be chained with httpx and curl to search a large, authorised web estate for exposed configuration files, such as ASP.NET’s web.config or appsettings.json. A 200 response alone isn’t enough to confirm a file exists, since many applications return a 200 on custom error pages, so the response body should be validated too.

Terminal window
naabu -host <authorised-range> -p 80,443 -rate 1000 -silent | httpx -stream -silent -path /web.config -mc 200 | \
while read -r url; do
curl -sk --max-time 10 "$url" | head -c 300 | grep -qiE '<configuration|connectionStrings|system.web|appSettings' && echo "$url"
done
Terminal window
naabu -host <authorised-range> -p 80,443 -rate 1000 -silent | httpx -stream -silent -path /appsettings.json -mc 200 | \
while read -r url; do
body=$(curl -sk --max-time 10 "$url")
printf "%s" "$body" | jq empty 2>/dev/null && echo "$url [$(printf "%s" "$body" | wc -c) bytes]"
done

If a configuration file is found, look for values such as connectionString, password, ApiKey, ClientSecret, machineKey, AWSSecretAccessKey or AzureWebJobsStorage before concluding anything sensitive was actually exposed.

The below adds parallelisation and additional keywords for sensitive files that I have come accross in real tests.

Terminal window
naabu -host <authorised-range> -p 80,443 -rate 5000 -silent | \
httpx -stream -silent -threads 300 -path /web.config -mc 200 | \
xargs -P 100 -I{} sh -c '
url="{}";
body=$(curl -sk --max-time 10 "$url");
printf "%s" "$body" | head -c 300 | grep -qiE "<configuration|connectionStrings|system.web|appSettings" || exit 0;
match=$(printf "%s" "$body" | grep -Eio "connectionString|password|pwd|User ID|uid=|ApiKey|ClientSecret|machineKey|validationKey|decryptionKey|StorageAccountKey|AccountKey|AccessKey|SecretKey|AWSAccessKeyId|AWSSecretAccessKey|AzureWebJobsStorage|smtp|mailSettings|appSettings|connectionStrings" | sort -fu | paste -sd "," -);
[ -n "$match" ] && echo "$url [$(printf "%s" "$body" | wc -c) bytes] [$match]"
'

This reports not only that a configuration file was found, but its approximate size and which sensitive keywords were present, for example:

https://example.com/web.config [2841 bytes] [connectionString,password]

PowerShell Port Scanning

If you are in a Windows environment or only have access to a compromised Windows host, an excellent set of scripts for native Windows PowerShell port scanning is Minimalistic TCP and UDP port scanners, which can be found here.

Terminal window
Import-Module .\port-scan-tcp.ps1
port-scan-tcp 10.1.1.1 8080 # Scanning a single IP and Port
port-scan-tcp 10.1.1.1 (21,22,23,25,80,443,445,3389) # Scanning a single IP for a list TCP ports
port-scan-tcp (gc .\targets.txt) 22 # Scanning a list of IPs in a file for port 22
1..255 | foreach { port-scan-tcp 10.1.1.$_ 8080} # Scanning a range of IPs for a single Port

If you have no script execution, you can try using the Test-NetConnection cmdlet, which displays diagnostic information for a connection.

Terminal window
80,3601|%{ Test-NetConnection -Port $_ 10.1.1.1 -WA SilentlyContinue} | ?{$_.TCPTestSucceeded -eq $true} | select ComputerName,RemoteAddress,RemotePort # Single IP with a list of ports
1..254 | % {"10.1.1.$($_): $(Test-Connection -count 1 -comp 10.1.1.$($_) -quiet)"} # Test if a range of IPs are alive

Another native PowerShell script you can use to scan for hosts on a network is:

Terminal window
1..254 | ForEach-Object {
$ip = "10.1.1.$_"
$hostname = [System.Net.Dns]::GetHostEntry($ip).HostName
if ($hostname -ne $null) { Write-Host "IP: $ip, Hostname: $hostname" }
}

You can also use Test-Connection to perform a PowerShell Ping on a network to test for live hosts and return if they are reachable or not:

Terminal window
$baseIP = "10.1.1."
for ($i = 1; $i -le 254; $i++) {
$ip = $baseIP + $i
$result = Test-Connection -ComputerName $ip -Count 1 -Quiet
if ($result -eq $true) {
Write-Host "$ip is reachable"
} else {
Write-Host "$ip is unreachable"
}
}

The above script can be used to take a file of IPs and write the results to a file:

Terminal window
$file = "IPs.txt"
$outputFile = "Ping_Responded.txt"
$ips = Get-Content $file
foreach ($ip in $ips) {
$result = Test-Connection -ComputerName $ip -Count 1 -Quiet
if ($result) {
Write-Output "$ip is live" | Out-File -FilePath $outputFile -Append
} else {
Write-Output "$ip is dead" | Out-File -FilePath $outputFile -Append
}
}
Useful LinksPentest PayloadsCheat Sheets