All posts

Wireshark? Nope, Network Shell (Part 1)

My quest to find a quick and dirty alternative to Wireshark using base Windows components…or as close to it as I can. This is not a tutorial but more of a blog where I show you my thought process and the interesting e…

My quest to find a quick and dirty alternative to Wireshark using base Windows components…or as close to it as I can. This is not a tutorial but more of a blog where I show you my thought process and the interesting encounters I have along the way.

When I learn about a new feature, my curiosity always gets the best of me and I begin to question the limits I can reach with it, how far I can take it, and whether I can get it to do something it wasn’t designed to do. I’ve done that with the JavaScript Fetch API, and now in this article, I’m trying to do the same with the Windows Network Shell utility.

Without diving into the nitty-gritty details of the Windows Network Shell, which I will refer to as NetSh or Net Shell from here on, I want to give a brief overview of its features and how it can be coupled with PowerShell to create some interesting utility scripts, such as capturing network packets and exporting them to a PCAP file or displaying them in our shell.

In brief, NetSh is a Windows command-line utility that allows us to manage multiple network objects and display their statuses. Many of the functions that can be found in the Microsoft Management Console or Control Panel can also be performed using NetSh, but it also contains additional functionality that cannot be done in the GUI, such as managing network bridges, IPv6 objects, and Remote Procedure Calls.

Screenshot of NetSh Help command and its output.

So now what can we do with this information? Well my technical education is in Networking & Security, and one of my favorite tools is Wireshark, a packet capture/analyzer tool, so what if we can build the same tool or similar using what is given to us in default Windows?

That was my goal and this is my journey, from here on things will get very technical and if you’re not strong with PowerShell or at least understand the basics of programming you may not completely understand what's going on here, you have been warned.

My first step was to learn how we could capture packets using NetSh, and very quickly I learned about the trace option. The trace option allows us to capture network packets and export them to a special Event Trace Log file, which will prove to be problematic in the future.

To begin making the script I want to simplify many things for example I don’t want to remember the syntax for running a trace with the reporting enabled, for that, I can create a simple function or in this case a Script Block that contains the command already like below,

$NetshTraceFunction = {
    netsh trace start capture=yes tracefile=capture.etf
}
Start-Job -ScriptBlock $NetshTraceFunction

but now the programmers and experienced scripters may be wondering why I chose a script block over a function and that’s because I want our captures to run Asynchronously. In other words, I would like to perform other tasks in my tool or shell without needing to wait for the capture to finish. Building off of this idea, I would like to add the ability to capture for either a specified amount of time or until I decide it should stop. This is quite simple, we can just add a timeout for a specified amount of time that we input, and that solves that issue. I now had something like below, but there are a few more things that I have in mind.

$time = Read-Host "Packet Capture Duration(Seconds)? "
$NetshTraceFunction = {
    netsh trace start capture=yes tracefile=capture.etf
    Start-Sleep -Seconds $time 
    netsh trace stop
}
Start-Job -ScriptBlock $NetshTraceFunction

I also want this script to have REPL functionality, allowing me to bundle other functions and take advantage of the Async script blocks that have been added. By the time I figured most of that out, I had something like this.

# While Loop provides the REPL
while ($true) {
    $input = Read-Host "PowerShark> "

    # Basic exit command listener to exit the PowerShark REPL. 
    if ($input -eq "exit") {
        break
    }
    # Switch statement to interpret commands that are passed to the REPL script.
    switch ($input) {
        # Main Function Of PowerShark Script That Runs The Packet Capture and rompts For Additional Functions.
        Start-PacketCapture { 
            $time = Read-Host "Packet Capture Duration(Seconds)? "
            # If time is set to 0 seconds then the script will run infinitely, well until the file hits 256 MB.
            if ($time -eq "0") {
                # Notify user that the packet capture is running
                $time = Read-Host "Packet Capture Running..."
                $NetshTraceFunction = {
                    # Network Shell command that captures network data and exports it to a capture.etf file in the same directory where the script is ran.
                    netsh trace start capture=yes tracefile=capture.etl maxsize=256 
                }
                # Start background job
                Start-Job -ScriptBlock $NetshTraceFunction
            }
            else {
                # Notify user that the packet capture is running for specified amount of seconds
                Write-Host "Started The Packet Capture In The Background For ${time} Seconds"
                $NetshTraceFunction = {
                    # Network Shell command that captures network data and exports it to a capture.etf file in the same directory where the script is ran.
                    netsh trace start capture=yes tracefile=capture.etl
                    Start-Sleep -Seconds $time 
                    netsh trace stop
                }
                # Start background job
                Start-Job -ScriptBlock $NetshTraceFunction
            }
        }
        Default {
            Write-Host "Future Help Stuff Goes Here"
        }
    }
}

It’s about here that I began to run into lots of trouble. Network Shell is very powerful, but when running it as a background job, we run into one big issue: the packet capture will run for maybe one or two seconds, if that, and then die. There are no errors, and the job completes successfully when I use the Get-Job cmdlet.

This is incredibly annoying, but it was this issue that led me to learn about the NetEventPacketCapture PowerShell module. This module, and help from Ed Wilson (aka Doctor Scripto), will be displayed in my next blog where I finally get asynchronous packet capture and begin to parse logs in a human-readable format without the need for tools like Wireshark. Until then, I will leave you here with a working script. Maybe you can come up with a better solution?

# While Loop provides the REPL
while ($true) {
    $input = Read-Host "PowerShark> "

    # Basic exit command listener to exit the PowerShark REPL. 
    if ($input -eq "exit") {
        break
    }
    # Switch statement to interpret commands that are passed to the REPL script.
    switch ($input) {
        # Main Function Of PowerShark Script That Runs The Packet Capture and rompts For Additional Functions.
        Start-PacketCapture { 
            $time = Read-Host "Packet Capture Duration(Seconds)? "
            # If time is set to 0 seconds then the script will run infinitely, well until the file hits 256 MB.
            if ($time -eq "0") {
                # Network Shell command that captures network data and exports it to a capture.etf file in the same directory where the script is ran.
                netsh trace start provider=Microsoft-Windows-TCPIP capture=yes tracefile=capture.etl maxsize=256
                # Notify user that the packet capture is running
                $time = Read-Host "Packet Capture Running..."
                netsh trace stop
            }
            else {
                # Notify user that the packet capture is running for specified amount of seconds
                Write-Host "Started The Packet Capture In The Background For ${time} Seconds"
                # Network Shell command that captures network data and exports it to a capture.etf file in the same directory where the script is ran.
                netsh trace start provider=Microsoft-Windows-TCPIP capture=yes tracefile=capture.etl
                Start-Sleep -Seconds $time
                netsh trace stop
            }
        }
        Default {
            Write-Host "Future Help Stuff Goes Here"
        }
    }
}

Discussion

No comments yet