PoshC2_Python/Modules/Invoke-Sniffer.ps1

455 lines
14 KiB
PowerShell

function Invoke-Sniffer
{
<#
.SYNOPSIS
Generates a packet capture into an output file
Author: Matthew Graeber (@mattifestation) A .Net based PowerShell packet sniffer ("promiscuous mode" must be supported by hardware/driver)
.DESCRIPTION
Invoke-Sniffer writes a capture dump file.
This is similar to tcpdump or windump but only ascii txt
.EXAMPLE
Invoke-Sniffer -OutputFile C:\Temp\Output.txt -MaxSize 500MB
.LINK
https://raw.githubusercontent.com/sperner/PowerShell/master/Sniffer.ps1
#>
param( [String]$LocalIP = "NotSpecified", [String]$ScanIP="all", [String]$Protocol = "all", `
[String]$Port="all", [Int]$Seconds = 0, [switch]$ResolveHosts, [switch]$Help, [String]$OutputFile, $MaxSize)
# Help / display usage
if( $Help )
{
Write-Output "usage: $($MyInvocation.MYCommand) [-OutputFile <String>] [-LocalIP <String>] [-ScanIP <String>] [-Protocol <String>] [-Port <String>] [-Seconds <Int32>] [-ResolveHosts]"
exit -1
}
# Params
if (!$OutputFile){
if (!(Test-Path -Path C:\Temp))
{
New-Item C:\Temp -type directory
}
$OutputFile = "C:\Temp\Dump.txt"
}
if (!$MaxSize)
{
$MaxSize = 100MB
}
$starttime = Get-Date
$byteIn = New-Object Byte[] 4 # source
$byteOut = New-Object Byte[] 4 # destination
$byteData = New-Object Byte[] 4096 # size of data
$byteIn[0] = 1 # enable promiscuous mode
$byteIn[1-3] = 0
$byteOut[0-3] = 0
# TCP Flags
$TCPFIN = [Byte]0x01
$TCPSYN = [Byte]0x02
$TCPRST = [Byte]0x04
$TCPPSH = [Byte]0x08
$TCPACK = [Byte]0x10
$TCPURG = [Byte]0x20
# Convert from big to little endian & convert to uint16
Function NetworkToHostUInt16( $address )
{
[Array]::Reverse( $address )
return [BitConverter]::ToUInt16( $address, 0 )
}
# Convert from big to little endian & convert to uint32
Function NetworkToHostUInt32( $address )
{
[Array]::Reverse( $address )
return [BitConverter]::ToUInt32( $address, 0 )
}
# Convert from big to little endian & convert to string
Function ByteToString( $address )
{
$AsciiEncoding = New-Object System.Text.ASCIIEncoding
return $AsciiEncoding.GetString( $address )
}
# Get IP-address <-> hostname
$hosts = @{} # array for hostnames
Function resolve( $IPAddress )
{
if( $data = $hosts."$($IPAddress.IPAddressToString)" )
{
if( $IPAddress.IPAddressToString -eq $data )
{
return [System.Net.IPAddress]$IPAddress
}
else
{
return $data
}
}
else
{ # much faster than [System.Net.DNS]::GetHostEntry()
$null,$null,$null,$data = nslookup $IPAddress.IPAddressToString 2>$null
$data = $data -match "Name:"
if( $data -match "Name:" )
{
$data = $data[0] -replace "Name:\s+",""
$hosts."$($IPAddress.IPAddressToString)" = "$data"
return $data
}
else
{
$hosts."$($IPAddress.IPAddressToString)" = "$($IPAddress.IPAddressToString)"
return $IPAddress
}
}
}
# Read "services" file
$servicesFilePath = "$env:windir\System32\drivers\etc\services"
# <service name> <port number>/<protocol> [aliases...] [#<comment>]
$serviceFile = [IO.File]::ReadAllText("$env:windir\System32\drivers\etc\services") -split
# filter out all comment lines
([Environment]::NewLine) -notlike "#*"
# Read protocols from services
Function getService( $port )
{
$protocols = foreach( $line in $serviceFile )
{
# not empty lines
if( -not $line ) { continue }
# split lines into name, port+proto, alias+comment
$serviceName, $portAndProtocol, $aliasesAndComments = $line.Split(' ', [StringSplitOptions]'RemoveEmptyEntries')
# split port+proto into port, proto
$portNumber, $protocolName = $portAndProtocol.Split("/")
if( $portNumber -eq $port )
{
return $serviceName
}
}
}
# Get local IP-Address
if( $LocalIP -eq "NotSpecified" )
{
route print 0* |
%{
if( $_ -match "\s{2,}0\.0\.0\.0" )
{
$null,$null,$null,$LocalIP,$null = [regex]::replace($_.trimstart(" "),"\s{2,}",",").split(",")
}
}
}
Write-Output "Local IP: $LocalIP" | Out-File $outputfile -Append
Write-Output "ProcessID: $PID" | Out-File $outputfile -Append
Write-Output "" | Out-File $outputfile -Append
# Open a raw ip socket
$Socket = New-Object System.Net.Sockets.Socket( [Net.Sockets.AddressFamily]::InterNetwork, [Net.Sockets.SocketType]::Raw, [Net.Sockets.ProtocolType]::IP )
# Include the ip header
$Socket.SetSocketOption( "IP", "HeaderIncluded", $true )
# Big packet buffer
$Socket.ReceiveBufferSize = 1024000
# Create ip endpoint
$Endpoint = New-Object System.Net.IPEndpoint( [Net.IPAddress]"$LocalIP", 0 )
$Socket.Bind( $Endpoint )
# Enable promiscuous mode
[void]$Socket.IOControl( [Net.Sockets.IOControlCode]::ReceiveAll, $byteIn, $byteOut )
Write-Output "Press ESC to stop the packet sniffer ..." | Out-File $outputfile -Append
Write-Output "" | Out-File $outputfile -Append
$escKey = 27
$running = $true
# Start sniffing
$packets = @() # array for packets
while( $running )
{
# when a key was pressed...
if( $host.ui.RawUi.KeyAvailable )
{
$key = $host.ui.RawUI.ReadKey( "NoEcho,IncludeKeyUp,IncludeKeyDown" )
# if ESC was pressed, stop sniffing
if( $key.VirtualKeyCode -eq $ESCkey )
{
$running = $false
}
}
# timeout after $Seconds...
if( $Seconds -ne 0 -and ($([DateTime]::Now) -gt $starttime.addseconds($Seconds)) )
{
exit
}
# no packets in card buffer...
if( -not $Socket.Available )
{
start-sleep -milliseconds 300
continue
}
# receive data
$rData = $Socket.Receive( $byteData, 0, $byteData.length, [Net.Sockets.SocketFlags]::None )
# decode the packet
$MemoryStream = New-Object System.IO.MemoryStream( $byteData, 0, $rData )
$BinaryReader = New-Object System.IO.BinaryReader( $MemoryStream )
# b1 - version & header length
$VerHL = $BinaryReader.ReadByte( )
# b2 - type of service
$TOS= $BinaryReader.ReadByte( )
# b3,4 - total length
$Length = NetworkToHostUInt16 $BinaryReader.ReadBytes( 2 )
# b5,6 - identification
$Ident = NetworkToHostUInt16 $BinaryReader.ReadBytes( 2 )
# b7,8 - flags & offset
$FlagsOff = NetworkToHostUInt16 $BinaryReader.ReadBytes( 2 )
# b9 - time to live
$TTL = $BinaryReader.ReadByte( )
# b10 - protocol
$ProtocolNumber = $BinaryReader.ReadByte( )
# b11,12 - header checksum
$Checksum = [Net.IPAddress]::NetworkToHostOrder( $BinaryReader.ReadInt16() )
# b13-16 - source ip address
$SourceIP = $BinaryReader.ReadUInt32( )
$SourceIP = [System.Net.IPAddress]$SourceIP
# b17-20 - destination ip address
$DestinationIP = $BinaryReader.ReadUInt32( )
$DestinationIP = [System.Net.IPAddress]$DestinationIP
# get ip version (bits 0-3)
$ipVersion = [int]"0x$(('{0:X}' -f $VerHL)[0])"
# get header length (bits 4-7)
$HeaderLength = [int]"0x$(('{0:X}' -f $VerHL)[1])" * 4
# header includes Options...
if($HeaderLength -gt 20)
{
[void]$BinaryReader.ReadBytes( $HeaderLength - 20 ) # should probably do something with this later
}
$Data = ""
$TCPFlagsString = @() # make this an array
$TCPWindow = ""
$SequenceNumber = ""
switch( $ProtocolNumber )
{
1 { # ICMP
$ProtocolDesc = "ICMP"
$sourcePort = [uint16]0
$destPort = [uint16]0
$ICMPType = $BinaryReader.ReadByte()
$ICMPCode = $BinaryReader.ReadByte()
switch( $ICMPType )
{
0 { $ICMPTypeDesc = "Echo reply"; break }
3 { $ICMPTypeDesc = "Destination unreachable"
switch( $ICMPCode )
{
0 { $ICMPCodeDesc = "Network not reachable"; break }
1 { $ICMPCodeDesc = "Host not reachable"; break }
2 { $ICMPCodeDesc = "Protocol not reachable"; break }
3 { $ICMPCodeDesc = "Port not reachable"; break }
4 { $ICMPCodeDesc = "Fragmentation needed"; break }
5 { $ICMPCodeDesc = "Route not possible"; break }
13 { $ICMPCodeDesc = "Administratively not possible"; break }
default { $ICMPCodeDesc = "Other ($_)" }
}
break
}
4 { $ICMPTypeDesc = "Source quench"; break }
5 { $ICMPTypeDesc = "Redirect"; break }
8 { $ICMPTypeDesc = "Echo request"; break }
9 { $ICMPTypeDesc = "Router advertisement"; break }
10 { $ICMPTypeDesc = "Router solicitation"; break }
11 { $ICMPTypeDesc = "Time exceeded"
switch( $ICMPCode )
{
0 { $ICMPCodeDesc = "TTL exceeded"; break }
1 { $ICMPCodeDesc = "While fragmenting exceeded"; break }
default { $ICMPCodeDesc = "Other ($_)" }
}
break
}
12 { $ICMPTypeDesc = "Parameter problem"; break }
13 { $ICMPTypeDesc = "Timestamp"; break }
14 { $ICMPTypeDesc = "Timestamp reply"; break }
15 { $ICMPTypeDesc = "Information request"; break }
16 { $ICMPTypeDesc = "Information reply"; break }
17 { $ICMPTypeDesc = "Address mask request"; break }
18 { $ICMPTypeDesc = "Address mask reply"; break }
30 { $ICMPTypeDesc = "Traceroute"; break }
31 { $ICMPTypeDesc = "Datagram conversion error"; break }
32 { $ICMPTypeDesc = "Mobile host redirect"; break }
33 { $ICMPTypeDesc = "Where-are-you"; break }
34 { $ICMPTypeDesc = "I-am-here"; break }
35 { $ICMPTypeDesc = "Mobile registration request"; break }
36 { $ICMPTypeDesc = "Mobile registration reply"; break }
37 { $ICMPTypeDesc = "Domain name request"; break }
38 { $ICMPTypeDesc = "Domain name reply"; break }
39 { $ICMPTypeDesc = "SKIP"; break }
40 { $ICMPTypeDesc = "Photuris"; break }
41 { $ICMPTypeDesc = "Experimental mobility protocol"; break }
default { $ICMPTypeDesc = "Other ($_)" }
}
$ICMPChecksum = [System.Net.IPAddress]::NetworkToHostOrder($BinaryReader.ReadInt16())
$Data = ByteToString $BinaryReader.ReadBytes($Length - ($HeaderLength - 32))
break
}
2 { # IGMP
$ProtocolDesc = "IGMP"
$sourcePort = [uint16]0
$destPort = [uint16]0
$IGMPType = $BinaryReader.ReadByte()
$IGMPMaxRespTime = $BinaryReader.ReadByte()
$IGMPChecksum = [System.Net.IPAddress]::NetworkToHostOrder($BinaryReader.ReadInt16())
$Data = ByteToString $BinaryReader.ReadBytes($Length - ($HeaderLength - 32))
break
}
6 { # TCP
$ProtocolDesc = "TCP"
$sourcePort = NetworkToHostUInt16 $BinaryReader.ReadBytes(2)
$destPort = NetworkToHostUInt16 $BinaryReader.ReadBytes(2)
$serviceDesc = getService( $destPort )
$SequenceNumber = NetworkToHostUInt32 $BinaryReader.ReadBytes(4)
$AckNumber = NetworkToHostUInt32 $BinaryReader.ReadBytes(4)
$TCPHeaderLength = [int]"0x$(('{0:X}' -f $BinaryReader.ReadByte())[0])" * 4
$TCPFlags = $BinaryReader.ReadByte()
switch( $TCPFlags )
{
{ $_ -band $TCPFIN } { $TCPFlagsString += "<FIN>" }
{ $_ -band $TCPSYN } { $TCPFlagsString += "<SYN>" }
{ $_ -band $TCPRST } { $TCPFlagsString += "<RST>" }
{ $_ -band $TCPPSH } { $TCPFlagsString += "<PSH>" }
{ $_ -band $TCPACK } { $TCPFlagsString += "<ACK>" }
{ $_ -band $TCPURG } { $TCPFlagsString += "<URG>" }
}
$TCPWindow = NetworkToHostUInt16 $BinaryReader.ReadBytes(2)
$TCPChecksum = [System.Net.IPAddress]::NetworkToHostOrder($BinaryReader.ReadInt16())
$TCPUrgentPointer = NetworkToHostUInt16 $BinaryReader.ReadBytes(2)
if( $TCPHeaderLength -gt 20 ) # get to start of data...
{
[void]$BinaryReader.ReadBytes($TCPHeaderLength - 20)
}
# if SYN flag is set, sequence number is initial, then first data octet is ISN + 1
if ($TCPFlags -band $TCPSYN)
{
$ISN = $SequenceNumber
#$SequenceNumber = $BinaryReader.ReadBytes(1)
[void]$BinaryReader.ReadBytes(1)
}
$Data = ByteToString $BinaryReader.ReadBytes($Length - ($HeaderLength + $TCPHeaderLength))
break
}
17 { # UDP
$ProtocolDesc = "UDP"
$sourcePort = NetworkToHostUInt16 $BinaryReader.ReadBytes(2)
$destPort = NetworkToHostUInt16 $BinaryReader.ReadBytes(2)
$serviceDesc = getService( $destPort )
$UDPLength = NetworkToHostUInt16 $BinaryReader.ReadBytes(2)
[void]$BinaryReader.ReadBytes(2)
# subtract udp header length (2 octets) and convert octets to bytes
$Data = ByteToString $BinaryReader.ReadBytes(($UDPLength - 2) * 4)
break
}
default {
$ProtocolDesc = "Other ($_)"
$sourcePort = 0
$destPort = 0
}
}
$BinaryReader.Close( )
$memorystream.Close( )
$Data = $Data.toCharArray( 0, $Data.length )
# resolve IP addresses to hostnames...
if( $ResolveHosts )
{
# $DestinationHostName = ([System.Net.DNS]::GetHostEntry($DestinationIP.IPAddressToString)).Hostname
$DestinationHostName = resolve( $DestinationIP )
# $SourceHostName = ([System.Net.DNS]::GetHostEntry($SourceIP.IPAddressToString)).Hostname
$SourceHostName = resolve( $SourceIP )
}
if( ($Protocol -eq "all") -or ($Protocol -eq $ProtocolDesc) )
{
if( ($Port -eq "all") -or ($Port -eq $sourcePort) -or ($Port -eq $destPort) )
{
if( ($ScanIP -eq "all") -or ($ScanIP -eq $SourceIp) -or ($ScanIP -eq $DestinationIP) )
#if( $ScanIP -eq $SourceIp -and $ScanIP -eq $DestinationIP )
{
if ((get-item $outputfile).length -gt $MaxSize)
{
$running = $false
}
Write-Output "Time:`t`t$(get-date)" | Out-File $outputfile -Append
Write-Output "Version:`t$ipVersion`t`t`tProtocol:`t$ProtocolNumber = $ProtocolDesc" | Out-File $outputfile -Append
Write-Output "Destination:`t$DestinationIP`t`tSource:`t`t$SourceIP" | Out-File $outputfile -Append
if( $ResolveHosts )
{
Write-Output "DestinationHostName`t$DestinationHostName`tSourceHostName`t$SourceHostName" | Out-File $outputfile -Append
}
Write-Output "DestPort:`t$destPort`t`t`tSourcePort:`t$sourcePort" | Out-File $outputfile -Append
switch( $ProtocolDesc )
{
"ICMP" {
Write-Output "Type:`t`t$ICMPType`t`t`tDescription:`t$ICMPTypeDesc" | Out-File $outputfile -Append
Write-Output "Code:`t`t$ICMPCode`t`t`tDescription:`t$ICMPCodeDesc" | Out-File $outputfile -Append
break
}
"IGMP" {
Write-Output "Type:`t`t$IGMPType`t`t`tMaxRespTime:`t$($IGMPMaxRespTime*100)ms" | Out-File $outputfile -Append
break
}
"TCP" {
Write-Output "Sequence:`t$SequenceNumber`t`tAckNumber:`t$AckNumber" | Out-File $outputfile -Append
Write-Output "Window:`t`t$TCPWindow`t`t`tFlags:`t`t$TCPFlagsString" | Out-File $outputfile -Append
Write-Output "Service:`t$serviceDesc" | Out-File $outputfile -Append
break
}
"UDP" {
Write-Output "Service:`t$serviceDesc" | Out-File $outputfile -Append
break
}
}
for( $index = 0; $index -lt $Data.length; $index++ )
{
# eliminate non ascii characters...
if( $Data[$index] -lt 33 -or $Data[$index] -gt 126 )
{
$Data[$index] = '.'
}
}
$OFS="" # eliminate spaces from output of char array
Write-Output "Data: $Data" | Out-File $outputfile -Append
"Data: $Data" |select-string -Pattern "username="
Write-Output "----------------------------------------------------------------------" | Out-File $outputfile -Append
}
}
}
}
}