Minimalistic TCP / UDP Port Scanner – PowerShell

Introducing another addition to our portfolio of minimalistic tools for pentesting. This time we are going to be looking on a minimalistic TCP and UDP port scanner.

Written in pure PowerShell, this small yet powerful port scanner is useful in specific attack simulations where we cannot use any traditional or typical port scanners.

Why another port scanning tool?

There are many network port scanners out there. Some of the most popular ones include NmapMasscanAngry IP ScannerZMap any there are plenty of others.

They are all great, well tested and functional, but they are also big, complex and most importantly flagged by every decent Antivirus or EDR solution. And that can be a deal breaker in some penetration testing scenarios.

In some situations we simply need something small and minimalistic, something that we could write from scratch quickly, if we needed to.

Why writing a port scanner from scratch?

Writing tools from scratch may be necessary, for instance, when we are performing pentest from a heavily restricted environment where we cannot use any typical pentesting tools.

This would be vital while testing of an isolated VDI / Citrix environment where we cannot upload anything or when we are performing a simulation of a disgruntled employee from a workstation with all the security controls in place.

In all these cases we would need to build our own tools in order for us to be able to perform basic operations such as port scanning.

Without port scanning abilities, we would hardly be able to make any progress, discover systems on the network, or perform any lateral movement for that matter.

Port scanner is simply a must and if we cannot use one, we have to make one.

Introducing minimalistic port scanner

For such occasions, we have developed the following quick and easy, but powerful and reliable port scanner.

To keep the size small, we have divided the scanner into two separate independent modules:

So it’s really two port scanners, not one. Both scanners can be found in our dedicated GitHub repository:

List of features

Both port scanners have the following features:

  • Detection of open, closed and filtered ports (both TCP and UDP)
  • Ability to scan a single host, network range or a list of hosts in a file
  • Adjustable timeout values for effective and reliable port scanning
  • Non-malicious – undetected by any Antivirus or EDR solution

From the design point of view:

  • Small and minimalistic – can be typed out by hand (on the keyboard)
  • Written in pure PowerShell – no additional modules needed
  • Practical and smart design:
    • Support resuming, if interrupted
    • Skip already scanned hosts / ports

Typical usage scenario

Since these port scanners are written in PowerShell, we have to be able to run PowerShell commands on the system that we are using. On a restricted workstation this may a be a problem, so..

(1) First step is typically to circumvent the restrictions and spawn a shell. Once we can comfortably run PowerShell commands, we can progress to the next step.

(2) Now we can write up the port scanners somewhere on the file system. For instance, we could place them on our Desktop, but due to various restrictions we may have to place them somewhere else where we can write, e.g.:

  • C:\Users\Public
  • C:\Windows\Tasks
  • C:\Windows\Tracing
  • C:\Windows\System32\Spool\Drivers\Color
  • etc.

And that’s all!

Now we can start doing some port scanning. Here’s a quick intro into how to use them.

TCP port scanner:

Import-Module .\port-scan-tcp.ps1 
# Usage: 
port-scan-tcp <host(s)> <port(s)>

UDP port scanner:

Import-Module .\port-scan-udp.ps1

# Usage:
port-scan-udp <host(s)> <port(s)>

Let’s see some examples on how to use them in practice.

Port scan of a single host

Here’s the simplest example – check if a remote host has port tcp/445 open:

port-scan-tcp 445
Port scanning a single host and port

Here’s an example of port scanning a single host for selected tcp ports:

port-scan-tcp (21,22,23,25,80,443,445,3389)
Port scanning a single host for selected ports

Port scan of a network range

Here’s an example of port scanning a network range for port tcp/445 (port sweeping):

0..255 | foreach { port-scan-tcp 192.168.204.$_ 445 }
Port scanning (sweeping) a network range for a single port

Here’s an example of port scanning a network range for selected tcp ports:

0..255 | foreach { port-scan-tcp 192.168.204.$_ (22,80,445) }
Port scanning a network range for selected ports

List of hosts in a file

We can also provide list of targets as an input file.

For instance, in corporate networks with Active Directory (AD) deployment, we could extract list of computers from AD using PowerShell cmdlets like this:

$a = [adsisearcher]”(objectCategory=computer)”
$a.PropertiesToLoad.add(“dnshostname”) | out-null
$a.PageSize = 1
$a.FindAll() | % { echo $ } > computers.txt

Now we could identify all alive Windows systems by port sweeping on port tcp/445:

port-scan-tcp (gc .\computers.txt) 445
Port scanning of computers found in active directory using input file

Getting the results

Both scanners keep track of everything using a state file (scanresults.txt) which is created in the current working directory. This allows us to check on the results anytime, even during ongoing scans.

For instance, here’s how we can get a list systems with port tcp/445 open:

Get-Content .\scanresults.txt | Select-String "tcp,445,Open"
Port scan results - hosts with port tcp/445 open

If we wanted to list only the first column, we could easily do that with PowerShell like this:

(Get-Content .\scanresults.txt | Select-String "tcp,445,Open") -replace ",.*",""
Extracting list of hosts with open port tcp/445

Now we could feed this list into our SMB login bruteforcer, for instance, and attempt to compromise some of these Windows machines. Or we could employ some other automation, anything we would like.

Requirements and limitations

Compatibility. The TCP scanner comes in two versions with the difference of using the TcpClient.ConnectAsync() method. This method, available in .NET 4.5, gives the scanner ability to discern between ‘Closed’ and ‘Filtered’ ports. The compat version of the scanner (for older systems) cannot discern this and just reports both such cases as ‘Closed’.

Speed. Both port scanners (TCP and UDP) are only a single threaded loops without any parallelization. Thus, the scanning speed is limited. But, in the worst case the speed should be around 1 port scan per second, depending on the timeout values which you can also simply just change.

Speed degradation. Something to also keep in mind is that the scanners may get a bit slow after some time if there are too many results already. To mitigate this issue, we can rotate the results file or use a different one by modifying the modules and reloading:

Import-Module .\port-scan-tcp.ps1 -force 
Import-Module .\port-scan-udp.ps1 -force