The Ultimate Port Scanning Guide: Part 2 – Practical TCP Port Scans

The Ultimate Port Scanning Guide: Part 2 – Practical TCP Port Scans

Earlier we looked at the theory behind different types of port scans. Here we’ll put the theory into practice and see what we find on a lab network. In this example I have a copy of metasploitable 2 running on IP address If you have a copy of virtualbox, it’s worth playing along with this post.

Before we start, I’d like to share a pentester story with you about knocking systems over. It’s a fact of life that software bugs happen, and are often triggered by edge cases never considered by the software’s author.

A common edge case is something connecting to a service and disconnecting before the conversation starts, or connecting to a service and sending unexpected input. Unfortunately, port scanning more or less relies on these two edge cases.

Thus at some point in your career, it’s almost certain that a port scan will knock something over.

The story of the payroll system that couldn’t

Once upon a time on a test of an SAP HR environment, my colleagues and I accidentally caused a cascade failure of the entire SAP landscape. A cluster service designed to provision and bring up servers on demand had a problem whereby connecting to its listening port then disconnecting without sending anything would cause the heartbeat service to crash.

The heartbeat queries would then fail to respond indicating a failure. The automated clustering service’s follow-on process was to shut down the VM with the dead heartbeat listener and reboot.

That moment on-site when you unintentionally knock over the HR system.
That ‘oh-sh*t’ moment on-site when you knock things over.

Unfortunately when this happened all connections to the other services would die too. The clustering service would then restart the other systems. Within a matter of minutes systems were going up and down and continually restarting as heartbeats were detected, then not detected, then detected again.

It turns out that this all happened by design. A design that was fundamentally flawed.

There’s a certain instinctive response to become defensive in these situations as you might be blamed for the failure. Sometimes it’s you, sometimes it isn’t. Customers usually have a requirement for systems to be up, and they’re not. It’s easy to blame the pentester without looking at the evidence.

Regardless of the customer’s actions, you have a fundamental ethical duty to your customer to help them discover the cause and address it. When these situations occur and are cause by your scans, you have in fact done your job properly and identified a critical availability issue.

If a system is likely to fall over from a port scan, it begs the question what else could cause such problems, and suggests that the customer may want to look at using access control lists to restrict access to services that shouldn’t specifically be exposed to the rest of the network.

Splitting TCP scans by port

I like to split TCP port scans into 3 parts: Low, medium and high TCP ports. As you might suspect, there are reasons for this. The Internet Assigned Numbers Authority (IANA) is responsible for defining reserved port allocations. If you’ve ever port scanned systems before you may be familiar with seeing clusters of open ports around certain areas, particularly around the 1-10000 mark. This is no coincidence. IANA reserves specific ports for specific services, so by scanning the lower range first we’re more likely to get a set of results back in a shorter period of time.

In the real world you only have a certain window within which to conduct your test, so getting results back early will allow you to start testing properly while the remaining results come back.

Splitting scans into different ranges often makes for more efficient testing.
Splitting scans into different ranges often makes for more efficient testing.

I typically use ports 0-1024 for my low range, otherwise known as what IANA call System Ports. These scans cover typical services such as SMTP, Windows File Sharing, HTTP, HTTPS and other commonly found services. Scanning a very small range of ports also allows me to quickly determine the extent of filtering between me and the target.

For medium port scans I use ports 1025-32767. This covers the bulk of what IANA call User Ports, and include the more commonly found services not included in IANA’s System Ports, such as NFS, the Sun RPC Port Mapper, X-Windows, VNC, Microsoft Terminal Services and so on. The use of 32767 as a boundary is simply the to reduce the volume of ports. As you go higher, you’re less likely to find listening services, so having 32767 gives you half the coverage in a smaller amount of time than doing the full 65536 ports in one hit.

Finally, the high port scans covering ports in the range 32768-65535 are least likely to contain useful information and combine the lesser used *User Ports* and *Dynamic or Ephemeral ports*. Dynamic ports are not assigned as they’re typically used for TCP connection source ports. IANA port allocations are summarised below for reference.

  • 0 – 1023: System Ports are commonly reserved ports with allocations managed directly with IANA. These services typically run with superuser privileges on many Operating Systems.
  • 1024-49151: User Ports are IANA ports assigned through IETF review and usually don’t require superuser privileges.
  • 49152 – 65535: Dynamic ports are commonly used as source ports in client connections. Prior to Windows 2008, Microsoft Windows used ports in the range of 1025-5000 for dynamic ports.

Low TCP port scans

Lets have a look at how we could structure our low port scans. In this example, I’m using the following command line:

nmap -sS -PN -p 0-1024 -n -iL iplist.txt -oA nmap/tcp-lo

In this case I’m using Nmap as it’s simply the most accurate scanner out there. The -sS switch specifies a TCP SYN scan. -PN means don’t ping the target. We specify ports 0-1024 mostly because 0-1023 are the System Ports, but port 0 isn’t used and 1024 is a nice round number (in binary and hexadecimal) for heathens counting from one.

The -n switch tells nmap not to try DNS resolution at first, which can take a while if we’re scanning a large range. I normally conduct a separate list scan to do DNS resolution, making further DNS requests during port scans redundant.

We then specify the list of target hosts by supplying -iL iplist.txt on the command line. The iplist.txt file contains the target IP address, in this case Later I’ll use a variable instead, but for now lets just go with iplist.txt.

Finally, using -oA nmap/tcp-lo provides us with output in all major formats, stored in a subdirectory called nmap, prefixed with tcp-lo. All of the formats have their uses, but we’ll come to that later.

I don’t ping the target in these scans because I’m unsure of any filtering in place between me and the target. If there is filtering then this could result in pings failing and nmap accidentally thinking that a host is down.

Lets see what it looks like when scan is run against a target system.

Low TCP port scans
Low TCP port scans

As you can see there are 12 open ports, and the scan took a fairly low amount of time to complete. Normally low port scans are quickest but not necessarily very quick due to network latency. You can see that the bulk of the screen output is the open port list, showing the port and protocol, the port’s state and the IANA allocated service for that port. This does not necessarily mean that we can assume that a given port runs a given service. We’ll come back to this later.

Medium TCP port scans

In the next example I’ll use a $TARGETFILE variable instead of specifying a list of targets. On larger multi-segment penetration tests I recommend setting a local TARGETFILE variable pointing to your target file’s the absolute path, then using $TARGETFILE as the -iL value for Nmap. Using a globally sourced environmental variable pointing to the full path to your target list ensures you’re using the correct targets even if you’re in a different directory, and can save you days of headaches on larger tests.

The command line I’ll use is:

 nmap -sS -PN -p 1025-32767 -n -iL $TARGETFILE -oA nmap/tcp-med

Choosing these ports might seem a little strange compared to the allocation ranges, but indulge me.

Medium TCP Port Scans
Medium TCP Port Scan

Did you notice that all the responses for open ports were for TCP ports below 9000? If you did, well done. If not, don’t worry. In production environments there’s a tendency for ports to cluster down towards the lower end. In some environments (most notably environments with Sun RPC, or SAP) you will see ports around 32000, but while it does happen, it’s generally less common to find open TCP ports in the 20000-30000 range.

The purpose of the low port scans is to get decent results to start work on while the other scans finish. The purpose of the medium scans is to drip feed useful information back while we investigate the low port services, speeding things up. By the time medium port scans are finished, you’ll have had enough time to at least have a good look at lower ports and enumerate the underlying services.

I split scans between medium and high ports in order to ensure that I’ll have some results for medium scans when I finish looking at low ports even when there’s filtering in place between me and the target. I just use 32768 as it’s half-way.

You might wonder why I’d choose to split at 32768 when there’s occasionally Sun RPC ports in the 327xxx range. When these services are deliberately exposed you can find the open ports by querying the Sun RPC Port mapper on port 111 with the rpcinfo command.

I highly recommend splitting your scans by ports. How you split it is down to you, but stick to whatever you choose so you can easily find out which port hosted what service where, long after the test has concluded.

Not a risk!In the screenshot above we can see 14 open medium TCP ports, coming to a total of 26 running services on one system. This is unusually high for an internal system and suggests that it’s either being very heavily used for lots of services or that someone hasn’t hardened the system .

Each accessible service presents another opportunity to poke around, but doesn’t always correspond to an increase in vulnerabilities. If all the services there are justified, required and are well secured, it’s as secure as any group of systems with fewer individual services that are equally well secured.

In the real world people tend to configure the services they need for production, lock down services they expect to be exposed to the outside world and ignore the rest, usually by virtue of not being aware of it listening on the network. We often find the worst vulnerabilities in these sorts of gaps. Sadly, “That’s not a risk, it’s internal” is a far too commonly used phrase in the IT sector.

High TCP port scans

Lets take a look at the high TCP port scans. The command line I’ll use is:

nmap -sS -PN -p 32768-65535 -n -iL $TARGETFILE -oA nmap/tcp-hi

As you can see, the only difference to the medium scan is the change of ports and output filename.

High TCP Port Scan
High TCP Port Scan

Here we can see some high ports. To be honest anything from 40,000 onwards could be pretty much anything and may only be temporary. Some operating systems will respond with a SYN/ACK to SYNs sent to ports used for outbound TCP connections, while others won’t. We won’t know what’s running there until we investigate further, which is something for a later post.

Reading port scan output like tea leaves

Divining truth from a port scan is more scientific than this.
Divining truth from a port scan is only slightly more scientific than this.

In most cases the presence of a listening port does not indicate a specific running service. We can have some confidence with respect to IANA allocated ports but it would be foolish to rely upon ports matching IANA allocations. From 1024 onwards to 32767 there are some that you would expect in most cases to match certain conventions.

NFS for example, can run on any port, but the Linux NFS Kernel server implementation always runs on port 2049 by default. If we’re confident that this is a Linux system, we would expect NFS to be found on port 2049, if available.

VNC clients typically specify offsets from port 5900 as their server screen values, so we can be somewhat confident, or at least suspicious that VNC is running on port 5900. If port 5901 was open as well that would indicate the presence of two listening VNC services. However, if port 5901 was open and 5900 was closed, I wouldn’t necessarily draw the same conclusion.

Likewise, if TCP port 8080 was open, it could be a proxy server, or it could be something like Apache Tomcat, both of which often rely on TCP port 8080. In all cases, further investigation is needed before we can categorically state that given services are there, but open port patterns can be used to at least gain an idea of what to expect.

We can also use open ports as an indicator of system function and OS family. Windows and Unix-like systems tend to have very different patterns of open ports, mostly down to the way Windows implements it’s own RPC services, and how Unix-like systems tend to use individual ports for individual services. You can also identify a little about the system from it’s open IANA-allocated ports.

For example, a modern Windows Active Directory controller should have TCP ports 53 (DNS), 88 (Kerberos), 389 (LDAP), 636 (LDAP/S) and of course the common NetBIOS and Windows File Sharing ports 135 (used for RPC comms for AD replication), 139 (Authentication) and 445 (used for a whole host of services including file sharing and authentication). An older Active Directory controller that was used in a mixed NT or Windows 2000 network may have TCP port 42 open (used for the Windows Internet Naming System, WINS – a travesty of a protocol that’s best consigned to history).

Windows systems also tend to use TCP port 3389 for Microsoft Remote Desktop Protocol access. Unix-like systems on the other hand use text-based protocols on TCP ports 22 (SSH), 23 (Telnet) and 514 (RSH), or network-based Windowing protocols on TCP ports such as 590x (VNC) or 600x (X11). That’s not to say that if you see these open ports that the systems are always as described here, but they do tend to add weight to an argument that a system is running Windows or a more Unix-like OS, or that a system is an AD controller or Exchange server.

What’s actually happening under the hood?

So far we’ve covered the intensely theoretical and intensely practical aspects of TCP port scanning, but what actually happens on the wire when you kick off a TCP port scan. In my previous post, we looked at the theory behind a TCP port scan, but while you might have an idea of the abstract concept of a SYN packet and a SYN/ACK response, it might help you understand what’s going on by looking at the physical packets themselves.

I decided to conduct a low port scan against an OSX El Capitan system I had lying around. I used the same Nmap command lines as shown earlier, and used Wireshark to look at the packets. Lets start with Nmap’s original SYN:

TCP SYNIf you look at the bottom of the screenshot above, you’ll see the actual raw hexadecimal values for the full Ethernet frame sent across the wire. The part highlighted in blue ’60 02′ refers to the two bytes reserved in the TCP header for the SYN flag. As you can see, the presence of the SYN flag is indicated by the second to last bit in the header being set to 1. An unset, or ‘cleared’ flag would have a bit set to 0. Incidentally, the 12 bits shown under flags are known as control bits. The first 3 bits are reserved for future use and should be set to zero, while the remaining 9 are used to manage control flow.

tcp-ackIf the TCP port is open, then we should see the ACK and SYN flags set in a corresponding packet along with an acknowledgement number, in this case 1 as it’s the first acknowledgement. Because we’re performing a TCP SYN scan and not trying to create a genuine connection, our Operating System should reject the received SYN/ACK packet.


Here we can see the Reset flag is set on the packet, and also that the Acknowledgement number is set to 0. The relative sequence number is set to 1, so the target knows which TCP session we’re referring to (in case there are multiple TCP connections on the same port). Note that there’s no acknowledgement flag set. When we send a TCP SYN packet to a closed port, something different happens.


Here you can see that the response contains an acknowledgement and sequence number of 1, but this time the Reset and Acknowledgement flags are both set. Why do you think this is?


Understanding the way your chosen port scanner works is an essential part of being a good penetration tester. Knowing what options to use, why and when you would use them can be the difference between accurate results and garbage. Splitting your scans can also make a huge difference to your productivity, freeing you up to focus on getting things done instead of waiting for scans to come back.

In this post we looked at:

  • Splitting port scans by port range
  • Low TCP port scans, specifying a target file
  • Medium TCP port scans and using an environmental variable
  • High Port Scans
  • Interpreting results
  • What’s actually happening in a TCP port scan

In part three, I’ll cover UDP practical port scanning, looking at strategies, problems with UDP port scanning and workarounds. As always, you’re most welcome to send me your thoughts, comments or suggestions on twitter @stevelord. If you’d like to be notified of new posts and other useful pentesty things I find on the web, sign up to my mailing list below.

What others are reading on Raw Hex

Tagged , , , .

Steve is a full-time penetration tester and founder at Mandalorian and co-founded UK Information Security Conference 44CON in 2011. He is also the author of upcoming penetration testing guide Breaking In.