Introduction
You may be shocked to find how often you don't have the right tool for the job. Fortunately, with a hammer everything looks like a nail, and with PowerShell? Well we'll just have to make do. This post will dive into a number of techniques geared towards hammering out network enumeration with PowerShell for those situations when Nmap is not available. Once on network, the first step attackers need to make before they can move laterally is to determine what exactly is out there. While importing tools might be an option, depending on your level of access, operating environment, and goals, PowerShell is an inherent component of Windows that we can use to operate more efficiently and covertly.
Methods Covered in this Section
PS ping sweeper:
1..255 | % {echo "192.168.1.$_"; ping -n 1 -w 100 192.168.1.$_} | Select-String ttl
PS command metrics:
Measure-Command {}
PS parallel ping sweeper:
workflow ParallelSweep { foreach -parallel -throttlelimit 4 ($i in 1..255) {ping -n 1 -w 100 10.0.0.$i}}; ParallelSweep | Select-String ttl
PS multi-subnet ping sweeper with OS Detection:
0..10 | % { $a = $_; 1..255 | % { $b = $_; ping -n 1 -w 10 "10.0.$a.$b" | select-string TTL | % { if ($_ -match "ms") { $ttl = $_.line.split('=')[2] -as [int]; if ($ttl -lt 65) { $os = "Linux" } ElseIf ($ttl -gt 64 -And $ttl -lt 129) { $os = "Windows" } else { $os = "Cisco"}; write-host "10.0.$a.$b OS: $os"; echo "10.0.$a.$b" >> scan_results.txt }}} }
PS test egress filtering:
1..1024 | %{echo ((new-object Net.Sockets.TcpClient).Connect("allports.exposed",$_)) "Port $_ is open" } 2>$null
Because of object pipelining in PowerShell, implementing a simple ping sweep utility is quick and easy.
PS ping sweeper:
1..255 | % {echo "192.168.1.$_"; ping -n 1 -w 100 192.168.1.$_} | Select-String ttl
This command attempts to ping each IP address in the loop in sequence. It filters out IPs which do not respond with the | Select-String cmdlet thereby only displaying lines that include the text "TTL".
Command Breakdown
1..255 | % {echo "192.168.1.$_"; ping -n 1 -w 100 192.168.1.$_} | Select-String ttl
1. 1..255 - Produce a list of numbers from 1 to 255</pre> 2. | - Pass each number as an object into the loop 3. % - The % operator in PowerShell is an alias for foreach-object, and is used to start a loop. The loop executes the content between {} in sequence 4. echo "192.168.1.$_"; - Prints out the IP address. $_ is a variable that means current object. The current object relates to number (1..255) that the loop is currently on. 5. ping - Packet internet groper utility tests for ICMP connectivity between two nodes. 6. -n 1 - The number of pings to send manual set to stop after 1 7. -w 100 - Number of milliseconds to wait before timeout. This may need to be adjusted depending on the latency of the target environment 8. 192.168.1.$_ - The IP address to ping 9. | Select-String ttl - Pipe all output from the loop into Select-String. Filters all lines not having ttl in them.
Using a feature added into PowerShell versions 3.0 and newer, the workflow, we can parallelize the ping sweep in order to make it run substantially faster.
PS command metrics:
Measure-Command {}
By way of the parallelized execution demonstrated below, the ping sweeper is able to enumerate the network an increased rate. While limited to 4 parallel threads, we achieved results that were 62% faster than single-threaded. Spawning additional threads could increase enumeration speed even farther.
PS parallel ping sweeper:
workflow ParallelSweep { foreach -parallel -throttlelimit 4 ($i in 1..255) {ping -n 1 -w 100 10.0.0.$i}}; ParallelSweep | Select-String ttl
That one line of Powershell does the following:
1. Declares a workflow called ParallelSweep which executes a ping sweep limited to 4 simultaneous threads
2. Sweeps through a CIDR /24 range of addresses
3. Calls the workflow and filters out any response which does not have TTL in it
Command Breakdown
workflow ParallelSweep { foreach -parallel -throttlelimit 4 ($i in 1..255) {ping -n 1 -w 100 10.0.0.$i}}; ParallelSweep | Select-String ttl
1. workflow ParallelSweep {} - Declare a workflow called Parallel-Sweep
2. foreach - Begin a loop
3. -parallel - Parallelize execution of loop
4. -throttlelimit 4 - Limit # of concurrent threads to 4
5. ($i in 1..255) - Run loop 1 through 255 times
6. ping -n 1 -w 100 10.0.0.$i - Ping IP address
7. ParallelSweep - Call the workflow ParallelSweep
8. | Select-String ttl - Filter the output of Parallel-Sweep. Only print lines containing "ttl"
Bonus Command - Multi-Subnet ping sweeper with OS detection
On a recent assessment, we gained access to the internal environment, but were limited to software already installed on a Windows laptop. This environment utilized a large address space to cloak its limited number of clients. We could have implemented the PowerShell ping sweepers above, and manually adjusted the value in the third octet each time we finished sweeping a class C address space. Instead we used a multi-subnet sweeper to build a report of accessible hosts overnight. In the morning we had all the targets we could ever hope for. You can even accomplish very rudimentary OS fingerprinting by evaluating TTL values to aid in triaging attack targets.
PS multi-subnet ping sweeper with OS detection:
0..10 | % { $a = $_; 1..255 | % { $b = $_; ping -n 1 -w 10 "10.0.$a.$b" | select-string TTL | % { if ($_ -match "ms") { $ttl = $_.line.split('=')[2] -as [int]; if ($ttl -lt 65) { $os = "Linux" } ElseIf ($ttl -gt 64 -And $ttl -lt 129) { $os = "Windows" } else { $os = "Cisco"}; write-host "10.0.$a.$b OS: $os"; echo "10.0.$a.$b" >> scan_results.txt }}} }
Conclusion
There are many ways to extend these simple scripts to glean even more information about the network. These alone are a great way to begin exploring a network after gaining an initial foothold. These techniques prove especially useful during target identification in post compromise scenarios.
Matthew Toussain
https://twitter.com/0sm0s1z