Ethical Hacking
Port Scanning
Lesson 14 covered the mechanics of Nmap. This lesson goes deeper into the strategy behind port scanning — how to read results under real firewall conditions, why TCP and UDP require completely different approaches, and how experienced testers make scanning decisions that less experienced ones miss entirely.
Ports are doors — scanning tells you which ones are open
Every networked computer manages communication through ports — numbered endpoints, 0 to 65,535, that allow different services to run simultaneously on the same machine. A web server listens on port 80. SSH listens on port 22. The database listens on port 3306. Each service gets its own door. Port scanning is the process of checking which doors are open, what is behind them, and whether any of those doors can be pushed.
The 65,535 available ports split into three bands that you will hear referenced constantly in engagements. Ports 0 to 1023 are called well-known ports — reserved for standard services like HTTP, SSH, FTP, and DNS. Ports 1024 to 49,151 are registered ports — assigned to specific applications but less rigidly controlled. Ports 49,152 to 65,535 are dynamic ports — used temporarily for outgoing connections and rarely interesting for scanning.
The common mistake beginners make is only scanning the default top 1,000 ports and assuming that covers everything worth finding. It does not. Developers regularly run services on non-standard ports — a web admin panel on 8888, an SSH server moved to 2222 to avoid automated scanners, a database exposed on a custom port. Scanning all 65,535 ports, as we did in Lesson 14 with -p-, is the only way to be confident nothing is hiding in the upper ranges.
TCP vs UDP — two fundamentally different conversations
Most pen testers scan TCP ports heavily and barely touch UDP. That is a mistake with real consequences. UDP services — DNS, SNMP, TFTP, NTP, DHCP — run on a significant portion of real-world targets and carry vulnerabilities that are often missed precisely because UDP scanning is slower and less convenient than TCP.
The fundamental difference between the two is that TCP is a handshake protocol — it confirms delivery and waits for acknowledgement at every step. UDP sends packets and moves on, with no built-in confirmation. That makes TCP scanning reliable and fast. It makes UDP scanning slow and ambiguous — because a UDP port that does not respond could be open, closed, or filtered, and you cannot easily tell which from silence alone.
TCP scanning
Three-way handshake gives Nmap clear confirmation of open or closed state. Fast and reliable. Works on the vast majority of services — HTTP, SSH, FTP, databases, email.
Watch for: Firewalls that silently drop SYN packets produce filtered results that need follow-up with different probe types.
UDP scanning
No handshake — Nmap sends a probe and waits. Silence could mean open, closed, or filtered. Rate limiting by the OS means it runs much slower than TCP. Essential for finding DNS, SNMP, TFTP, NTP, and DHCP services.
Watch for: SNMP on UDP 161 is one of the most commonly exploited UDP services — it often leaks configuration data under default community strings.
Scanning behind firewalls — reading filtered results correctly
In a lab environment, Nmap returns clean results because there is nothing between Kali and Metasploitable filtering the traffic. On a real engagement — especially against internet-facing infrastructure — firewalls, intrusion prevention systems, and load balancers all change the picture significantly.
A common real-world pattern is seeing large blocks of ports returned as "filtered" — the firewall is dropping packets silently. When this happens, a standard SYN scan tells you very little about what is actually running behind the firewall. Experienced testers use a combination of techniques to get more information out of a heavily filtered host.
Try ACK scan (-sA) to map firewall rules
ACK scans send packets with the ACK flag set instead of SYN. Firewalls that only block new connections may allow ACK packets through — letting you determine whether a port is filtered at the firewall or simply closed on the host. Useful for understanding firewall rulesets rather than finding open ports directly.
Scan specific high-value ports rather than ranges
When a broad scan returns mostly filtered results, narrow down to the ports that matter most for the target's business — port 443 for web services, 3389 for RDP, 8443 for admin panels. Targeted scans against specific ports often get cleaner results than broad sweeps against a filtered host.
Reduce scan speed to avoid triggering rate limiting
Some IPS devices detect and block aggressive scans by rate-limiting traffic from the source IP. Dropping to -T2 or -T1 slows the scan considerably but reduces the likelihood of triggering automated blocking — which would otherwise cause all results for that host to come back as filtered regardless of the actual state.
Use fragment scanning (-f) to evade basic packet inspection
Fragmenting packets into smaller pieces can bypass older or simpler packet inspection systems that reassemble fragments incorrectly. Modern firewalls handle fragmentation correctly so this is less effective than it once was — but still worth trying when everything else returns filtered and the scope allows it.
The important mindset shift here is recognising that filtered results are not the end of a scan — they are a prompt to try a different technique. Experienced testers treat a wall of filtered ports as a puzzle rather than a dead end.
Targeted port scanning — being precise on a real engagement
On a real engagement, you rarely scan every port on every host in one pass. A more structured approach is to run a quick initial scan to find the most interesting ports, then do deeper targeted scans on the hosts and ports that look most promising. This keeps the scan footprint smaller and the results more actionable.
The scenario: Following on from the Nmap results in Lesson 14, your team lead wants a focused look at the database services on Metasploitable. MySQL on port 3306 and PostgreSQL on port 5432 both showed up open. Before attempting any exploitation, you need to confirm the exact versions, check for anonymous access, and understand what is actually exposed on those ports. You run a targeted version scan combined with specific NSE scripts designed for database reconnaissance.
# Targeted scan against database ports only
# Active recon — requires authorisation and open testing window
# -sV probes the ports to get exact service versions
# -p 3306,5432 scans only the two database ports we already know are open
# no need to rescan all 65,535 — we already have the port list
# --script=mysql-info pulls basic info from the MySQL service
# --script=mysql-empty-password tests if MySQL accepts login with no password
# --script=pgsql-brute attempts to brute force PostgreSQL with default creds
# Note: brute force scripts generate login attempts in target logs
# Always confirm this is within your scope before running them
nmap -sV -p 3306,5432 \
--script=mysql-info,mysql-empty-password,pgsql-brute \
192.168.56.101
PORT STATE SERVICE VERSION 3306/tcp open mysql MySQL 5.0.51a-3ubuntu5 | mysql-info: | Protocol: 10 | Version: 5.0.51a-3ubuntu5 | Thread ID: 8 | Capabilities flags: 43564 | Some Capabilities: Support41Auth, Speaks41ProtocolNew | Status: Autocommit |_ Salt: qZs5YmY]v!WU^Z=n[5lz | mysql-empty-password: |_ root account has empty password 5432/tcp open postgresql PostgreSQL DB 8.3.0 - 8.3.7 | pgsql-brute: | Accounts: | postgres:postgres - Valid credentials |_ Statistics: Performed 3 guesses in 1 seconds, average tps: 3.0
Breaking it down:
The MySQL root account requires no password to log in. On a real engagement this is an immediate critical finding — full administrative access to the database requires zero credentials. Every table, every stored procedure, every user account in the database is now accessible. This goes to the top of the report and gets escalated to the client before the day is out.
PostgreSQL is using its default credentials — the username postgres with the password postgres. Default credentials are one of the most common findings across every type of engagement. The fact that the pgsql-brute script found this in three guesses underlines how predictable default credentials are to an attacker who knows what software is running.
The backslash at the end of the nmap line tells the shell that the command continues on the next line. This keeps long commands readable without breaking them into separate commands. The entire block from "nmap" to the final IP address is a single command — the backslashes are just formatting.
UDP port scanning in practice
UDP scanning deserves its own dedicated run rather than being bolted on to a TCP scan. The reason is practical — a full UDP scan across all 65,535 ports against a remote host can take hours because the OS rate-limits ICMP unreachable responses, which Nmap relies on to determine closed UDP ports. The standard approach is to scan the most important UDP ports specifically rather than the full range.
SNMP on UDP 161 is always worth checking. It is a network management protocol that, under default configuration, uses a community string of "public" that grants read access to a significant amount of system information — running processes, network interfaces, installed software, and sometimes even user account details. Finding SNMP open with the default community string is a reliable route to significant information disclosure.
# UDP scan targeting the most valuable UDP services
# -sU switches to UDP mode — cannot be combined with -sS in the same command
# Always run active scans like this within your authorised scope only
# -p specifies the UDP ports to scan — these are the highest-value targets:
# 53 — DNS (could be queried for zone transfers or used for data exfiltration)
# 69 — TFTP (Trivial File Transfer Protocol — often exposes files with no auth)
# 111 — RPC portmapper (reveals what RPC services are running)
# 161 — SNMP (often leaks system info under default "public" community string)
# 500 — IKE (IPSec VPN — presence confirms a VPN gateway)
# --script=snmp-brute tests common SNMP community strings automatically
# --script=snmp-info dumps system information if SNMP responds
# -sV attempts version detection even on UDP ports
nmap -sU -sV -p 53,69,111,161,500 \
--script=snmp-brute,snmp-info \
192.168.56.101
PORT STATE SERVICE VERSION 53/udp open domain ISC BIND 9.4.2 69/udp open|filtered tftp 111/udp open rpcbind 2 (RPC #100000) 161/udp open snmp SNMPv1 server | snmp-brute: | public - Valid credentials | snmp-info: | enterprise: enterprises.8072.3.2.10 | contactInfo: Root| Name: metasploitable | Location: Sitting on the Dock of the Bay | System uptime: 2 days, 3:44:16.32 |_ Description: Linux metasploitable 2.6.24...
Breaking it down:
This combined state is unique to UDP scanning. It means Nmap received no response — which on UDP is ambiguous. The port could genuinely be open with a service that does not respond to the generic probe Nmap sent, or it could be filtered by a firewall. TFTP specifically often appears as open|filtered because it only responds to valid TFTP request packets, not generic probes.
The default SNMP community string "public" grants read access to system information. The snmp-info script immediately pulled the hostname, system description, location string, uptime, and administrator contact. None of that required a real credential — just the knowledge that the default was never changed.
The SNMP location string is set by the administrator and shows whatever they typed when configuring the service. On real systems this often contains useful information — rack location, data centre name, or physical site. On Metasploitable it is a placeholder. On a real target, take it seriously.
Two UDP ports returned actionable findings — SNMP with default credentials leaking system information, and BIND 9.4.2 on DNS (which you already know from Lesson 11 allowed zone transfers). The TCP-only mindset would have missed the SNMP finding entirely. That is what makes UDP scanning non-optional on a thorough engagement.
Turning scan output into a structured service inventory
By the end of the port scanning phase, the raw Nmap output needs to become a structured document. This is the service inventory — a complete map of everything running on every in-scope host, organised by risk. This is what the vulnerability scanning phase in the next lesson builds on directly.
| Port | Proto | Service and version | Priority |
|---|---|---|---|
| 21 | TCP | vsftpd 2.3.4 — backdoored version, CVE-2011-2523 | Critical |
| 22 | TCP | OpenSSH 4.7p1 — old version, check for weak keys | High |
| 23 | TCP | Telnet — plaintext protocol, credentials transmitted unencrypted | Critical |
| 80 | TCP | Apache 2.2.8 — outdated, check for directory listing and known CVEs | High |
| 445 | TCP | Samba 3.0.20 — CVE-2007-2447, unauthenticated RCE | Critical |
| 3306 | TCP | MySQL 5.0.51a — root login with empty password confirmed | Critical |
| 5432 | TCP | PostgreSQL 8.3 — default credentials (postgres:postgres) | Critical |
| 161 | UDP | SNMP — default "public" community string, system info exposed | High |
| 8180 | TCP | Apache Tomcat — check /manager/html for default credentials | High |
That inventory is the output of the scanning phase and the input to vulnerability scanning. Every finding above came from public-facing services running on a single host. Four of them are critical and could each independently provide full system access. Producing this document cleanly — with version numbers, confirmed findings, and priority ratings — is what the rest of the engagement is built on.
Teacher's Note: Save your Nmap output with the -oN flag (saves to a plain text file) or -oX (saves to XML, importable into tools like Metasploit). Running a two-hour scan and not saving the output is a habit that will cost you dearly when you need to reference a result three days later during the exploitation phase.
Practice questions
Scenario:
Scenario:
Scenario:
Quiz
Scenario:
Scenario:
Scenario:
Up Next · Lesson 16
Service Enumeration
Taking version numbers further — interacting with individual services to extract banners, identify configurations, and build a precise picture of each attack surface.