Capturing TCP/IP packets using PowerShell


When thinking network capture, everybody knows that the Wireshark is one of best solution for capturing. For windows, netsh command and Microsoft Message Analyzer will be another solution. In a restricted situation, however, PowerShell can be alternative.


I was in this kind of situation. There is no internet, no additional software (restricted by organization's policy), no development tools (like VisualStudio or Python)... But I rearized that Windows initially contains powerfull shell, PowerShell. So I tried to code packet capture tool.


At first, create raw socket and bind local-endpoint to it.

    $sock = new-object system.net.sockets.socket(
        [Net.Sockets.AddressFamily]::InterNetwork,
        [Net.Sockets.SocketType]::Raw,
    $sock.bind((new-object system.net.ipendpoint(
        [Net.ipaddress]$script:myip,
        0)) )

Then specify socket option to get TCP/IP header.

    $sock.setSocketOption(
        [Net.Sockets.SocketOptionLevel]::IP,
        [Net.Sockets.SocketOptionName]::HeaderIncluded,
        $true)

And enable promiscas mode.

    $null = $sock.iocontrol(
        [Net.Sockets.IOControlCode]::ReceiveAll,
        [BitConverter]::GetBytes([int]1),

After allocating receive buffer, capture network packets and output to console in loop.

    While($true){
        if($sock.ReceiveBufferSize -gt $buffer.length){
            $buffer = new-object byte[] $sock.ReceiveBufferSize
        }
        $len = $sock.Receive($buffer)
        $packet = new-object byte[] $len
        $packet = $buffer[0..($len - 1)]
        writePacket2Host $packet
    }

NetworkCapture.ps1

[string]$script:myip = [system.net.dns]::GetHostAddresses((hostname)) | where {$_.AddressFamily -eq "InterNetwork"} | select -ExpandProperty IPAddressToString
$script:port = @("80","443","8080")
$script:protocol = @("TCP")

function myWrite2Host($str){
    Write-Host $str
}

function getAscii($array){
    return [system.text.encoding]::GetEncoding("shift_jis").GetString($array)
}

function f_protocol($protocol){
    $result = $false
    foreach($e in $script:protocol){
        $result = $true
        if($e -eq $protocol){
            $result = $false
            break
        }
    }
    return $result
}

function f_port($port){
    $result = $false
    foreach($e in $script:port){
        $result = $true
        if($e -eq $port){
            $result = $false
            break
        }
    }
    return $result
}

function writePacket2Host($packet){
    [string]$protocol = "???"
    [string]$ip_from = "???"
    [string]$ip_to = "???"
    [string]$port_from = "???"
    [string]$port_to = "???"
    
    switch($packet[9]){
        1  {$protocol = "ICMP"}
        6  {$protocol = "TCP"} 
        17 {$protocol = "UDP"}
        default {$protocol = ("#" + $packet[9].ToString())}
    }
    
    $ip_from = ($packet[12].ToString() + "." + $packet[13].ToString() + "." + $packet[14].ToString() + "." + $packet[15].ToString())
    $ip_to   = ($packet[16].ToString() + "." + $packet[17].ToString() + "." + $packet[18].ToString() + "." + $packet[19].ToString())
    $port_from = ($packet[20] * 256 + $packet[21]).ToString()
    $port_to   = ($packet[22] * 256 + $packet[23]).ToString()
 
    if(f_protocol $protocol){
        return
    }
    if((f_port $port_from) -And (f_port $port_to)){
        return
    }
    
    myWrite2Host ((Get-Date).ToString("yyyy/MM/dd HH:mm:ss"))
    myWrite2Host ("Protocol : " + $protocol)
    myWrite2Host ($ip_from + ":" + $port_from + "=>" + $ip_to + ":" + $port_to)
    
    $endOfPacket = $false
    $log_len = 16
    $head = 0
    $tail = $log_len
    While($true){
        $array = $packet[$head..($tail-1)]
        $hexStr = [BitConverter]::ToString($array).Replace("-"," ")
        $hexStr = $hexStr.PadRight($log_len * 3)
        
        myWrite2Host ($hexStr + (getAscii $array))
        
        if($endOfPacket){
            break
        }
        
        $head += $log_len
        if(($tail + $log_len) -le $packet.length){
            $tail += $log_len
        } else {
            $tail += $packet.length
            $endOfPacket = $true
        }
    }
    myWrite2Host ""
}

function main(){
    $sock = new-object system.net.sockets.socket(
        [Net.Sockets.AddressFamily]::InterNetwork,
        [Net.Sockets.SocketType]::Raw,
        [Net.Sockets.ProtocolType]::IP)
    if($sock -eq $null){
        Write-Host "Socket Error"
        return
    }
    $sock.bind((new-object system.net.ipendpoint(
        [Net.ipaddress]$script:myip,
        0)) )
    $sock.setSocketOption(
        [Net.Sockets.SocketOptionLevel]::IP,
        [Net.Sockets.SocketOptionName]::HeaderIncluded,
        $true)
    $null = $sock.iocontrol(
        [Net.Sockets.IOControlCode]::ReceiveAll,
        [BitConverter]::GetBytes([int]1),
        [BitConverter]::GetBytes([int]0))
    $buffer = new-object byte[] 1
    While($true){
        if($sock.ReceiveBufferSize -gt $buffer.length){
            $buffer = new-object byte[] $sock.ReceiveBufferSize
        }
        $len = $sock.Receive($buffer)
        $packet = new-object byte[] $len
        $packet = $buffer[0..($len - 1)]
        writePacket2Host $packet
    }
}

main
Profile
I have technical job experience in enbedded software development and server side infrastructure/application engineering. I'm interested in programming and computer security.
Objective
To write down my technical knowledge in the place where I can access from anywhere. To share my program source code. To train my writing skill.
Link
  • LinkedIn (preparing)

  • Twitter

  • Facebook (preparing)

  • GitHub

  • StackOverFlow (preparing)

Archives