Port scanning is essential for penetration testers and red teams to identify potential vulnerabilities in networks and systems. It is the process of scanning a range of ports on a target system to determine which ones are open or closed. Attackers can exploit an open port to gain access to a system or network, whereas a closed port is inaccessible to external connections. This article will cover the basics of port scanning on Linux and Windows operating systems and explore some of the commonly used tools and techniques.

Port Scanning on Linux

Linux is one of the most popular operating systems for server and networking environments, making it a prime target for attackers. Here are some of the commonly used tools for port scanning on Linux:

Nmap: The Gold Standard

Nmap is a free and open-source tool for scanning for open ports and discovering network services running on a target system. It is a powerful and versatile tool that supports various scanning techniques, including TCP, UDP, and ICMP scans.

To scan a target system using Nmap, you can use the following command:

nmap <target IP>

Using the default TCP scan, this command will scan the target system for open ports. You can also specify the port range to be scanned using the -p option. For example, to scan for ports 80 and 443 on a target system, you can use the following command:

nmap -p 80,443 <target IP>

Netcat: The Swiss Army Knife

Netcat is a versatile networking tool that can be used for various tasks, including port scanning. It is a command-line tool that allows you to send and receive data across network connections.

To perform a port scan using Netcat, you can use the following command:

nc -zv <target IP> <start port>-<end port>

This command will scan the target system for open ports between the specified range. The -z option specifies no data should be sent, and the -v option provides verbose output.

Masscan: For Internet-Scale Speed

Masscan is a high-speed port scanner that can scan entire networks in minutes. It is designed to be faster and more efficient than other port scanners, making it an ideal tool for large-scale scanning operations. It uses a custom TCP/IP stack to send packets asynchronously.

To scan a network using Masscan, you can use the following command:

masscan -p1-65535 <target IP> --rate 1000

Note: Be careful with the --rate parameter, as high rates can crash network equipment or trigger security alerts.

Tool-less Scanning on Linux

In environments where you cannot install or upload binaries, you must rely on what is already there.

Scanning with Bash Sockets

Bash can provide TCP/UDP client connections via the special paths /dev/tcp/host/port and /dev/udp/host/port when that feature is enabled. This is a Bash feature (not POSIX), and it may not be available in other shells or on every build.

# Simple one-liner to scan ports 1-1024 (best-effort; can hang on filtered networks)
target="${1:-127.0.0.1}"
for i in {1..1024}; do
    # Prefer a timeout if available (Linux commonly has `timeout`; macOS often has `gtimeout` via coreutils).
    if command -v timeout >/dev/null 2>&1; then
        timeout 1 bash -c 'echo >/dev/tcp/"$1"/"$2"' _ "$target" "$i" >/dev/null 2>&1 && echo "Port $i is open"
    elif command -v gtimeout >/dev/null 2>&1; then
        gtimeout 1 bash -c 'echo >/dev/tcp/"$1"/"$2"' _ "$target" "$i" >/dev/null 2>&1 && echo "Port $i is open"
    else
        (echo >/dev/tcp/"$target"/"$i") >/dev/null 2>&1 && echo "Port $i is open"
    fi
done

Scanning with Python

Python is ubiquitous on Linux servers and provides a robust way to script a port scanner.

import socket

def scan_port(ip, port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        sock.settimeout(1)
        # connect_ex returns 0 if successful
        if sock.connect_ex((ip, port)) == 0:
            print(f"Port {port} is open")

target = "127.0.0.1"
for p in range(1, 1025):
    scan_port(target, p)

Port Scanning on Windows

Windows environments require a different set of tools, especially when you are trying to stay below the radar of EDR and AV.

PowerShell: The Ultimate Living-off-the-Land Tool

Modern Windows systems come with PowerShell, which is incredibly powerful for network enumeration.

Test-NetConnection

The simplest way to check a port in PowerShell is the built-in Test-NetConnection cmdlet (available in PowerShell 4.0+).

Test-NetConnection -ComputerName 192.168.1.1 -Port 445

Writing a Full Scanner in PowerShell

For scanning multiple ports efficiently, we can use the System.Net.Sockets.TcpClient .NET class directly:

$target = "192.168.1.1"
$ports = 1..1024

foreach ($port in $ports) {
    $client = New-Object System.Net.Sockets.TcpClient
    try {
        $async = $client.BeginConnect($target, $port, $null, $null)
        $success = $async.AsyncWaitHandle.WaitOne(100, $false) # 100ms timeout
        if ($success -and $client.Connected) {
            $client.EndConnect($async) | Out-Null
            Write-Host "Port $port is open" -ForegroundColor Green
        }
    } catch {
        # Ignore connection failures/timeouts
    } finally {
        if ($null -ne $async) { $async.AsyncWaitHandle.Close() }
        $client.Close()
    }
}

Enumerating Listening Ports (Local)

For local enumeration (not remote scanning), you can list listening TCP ports and correlate them to processes. This is not the same as scanning a remote host, but it is useful post-compromise or during host-based assessment.

Get-NetTCPConnection -State Listen | Select-Object LocalAddress, LocalPort, OwningProcess

Common Port Scanning Techniques

Port scanning can be performed using various techniques, each with strengths and weaknesses. Here are some of the commonly used methods:

  1. TCP Connect Scan (-sT): The most basic technique. It completes the three-way handshake. It is reliable but noisy because it establishes a full connection that will be logged by the application.
  2. SYN Scan (-sS): Also known as “Half-Open” scanning. It sends a SYN and waits for a SYN-ACK. If received, it typically sends a RST to avoid completing the handshake. This can reduce application-level logs, but network devices and host firewalls can still detect and log it.
  3. UDP Scan (-sU): UDP is connectionless. When you send a packet, an open port will usually send no response (or a service-specific response). A closed port will typically send back an ICMP Port Unreachable message. This type of scanning is slow and unreliable due to packet loss and ICMP rate-limiting.
  4. Null Scan (-sN): Sends a packet with no flags set. On many Unix-like stacks, closed ports respond with RST while open ports ignore it. This is less reliable on Windows targets and in the presence of modern firewalls/filters.
  5. Xmas Scan (-sX): Sends a packet with FIN, PUSH, and URG flags set. Similar caveats apply: behavior varies by OS and filtering, and Windows targets often do not respond in the RFC-expected way.

Stealth and Evasion

When scanning as a red teamer, noise is your enemy. Here are some tips to stay stealthy:

  • Slow it down: Use Nmap’s timing templates. -T0 (Paranoid) or -T1 (Sneaky) are much harder to detect than the default -T3 or the aggressive -T4.
  • Randomize targets: Use --randomize-hosts to prevent sequential scanning patterns that trigger IDS alerts.
  • Use Decoys: The -D flag can add decoy source IPs to confuse some logging and attribution. It does not make you invisible to a well-instrumented target, and decoy effectiveness depends heavily on the environment.
nmap -sS -p 80 -D 192.168.1.5,192.168.1.6,ME 192.168.1.100

Conclusion

Port scanning is essential for penetration testers and red teams to identify potential vulnerabilities in networks and systems. This article covers the basics of port scanning on Linux and Windows operating systems and explores some commonly used tools and techniques. Port scanning can be used for both legitimate and malicious purposes, so it’s important to use these techniques responsibly and within legal boundaries. Always ensure you have explicit, written authorization before scanning any network that you do not own.