PowerShell : loguer l’activité réseau des process Windows

Je vous ai parlé de Salwa, doctorante à l’université de Lorient dont la thèse porte sur la cybersécurité des équipements connectés industriels. Je lui ai fourni toute une liste d’outils pour monitorer les process sous Windows. Je lui ai promis l’écriture d’un script en PowerShell, afin de loguer l’activité réseau des process sous Windows. Ça tombe bien : la semaine prochaine, je donne une formation de 3 jours sur le PowerShell ! J’avais besoin de me refaire un peu la main.

Activer l’audit de l’accès aux objets

La condition pour que le script présenté ci-dessous fonctionne est d’auditer l’accès aux objets, à partir de la console gpedit.msc :

Configuration ordinateur > Paramètre Windows > Paramètres de sécurité > Stratégies locales > Stratégie d'audit > Auditer l'accès aux objets

Gpedit.msc > Stratégie d'audit > Auditer l'accès aux objets

Dès lors, le journal de sécurité – dans le journal d’événements accessibles à partir de la console eventvwr.msc – consigne l’activité du pare-feu Windows, à la condition qu’il soit activé ! Les événements à tracer sont le 5156 pour un paquet accepté et le 5157 pour un paquet refusé.

Journal d'événements > Sécurité

Loguer l’activité réseau des process par un script PowerShell

Les deux paramètres de ce script sont le nombre de lignes – $rows – à remonter lors de la 1ère exécution de la cmdlet Get-EventLog et la fréquence – $timer – de lecture du journal. Le script est une boucle infinie qui envoie dans un fichier CSV – par défaut c:\windows\processnetwork.log – selon la valeur de $timer, la date, le process, le statut (bloqué/pas bloqué), la direction du paquet, les ports et adresses sortants et entrants.

$path=$env:SystemRoot+"\processnetwork.log"
#Liste des protocoles indexés par leur numéro
$protocols=@{'0'='HOPOPT';'1'='ICMP';'2'='IGMP';'3'='GGP';'4'='IP-in-IP';'5'='ST';'6'='TCP';'7'='CBT';'8'='EGP';'9'='IGP';'10'='BBN-RCC-MON';'11'='NVP-II';'12'='PUP';'13'='ARGUS';'14'='EMCON';'15'='XNET';'16'='CHAOS';'17'='UDP';'18'='MUX';'19'='DCN-MEAS';'20'='HMP';'21'='PRM';'22'='XNS-IDP';'23'='TRUNK-1';'24'='TRUNK-2';'25'='LEAF-1';'26'='LEAF-2';'27'='RDP';'28'='IRTP';'29'='ISO-TP4';'30'='NETBLT';'31'='MFE-NSP';'32'='MERIT-INP';'33'='DCCP';'34'='3PC';'35'='IDPR';'36'='XTP';'37'='DDP';'38'='IDPR-CMTP';'39'='TP++';'40'='IL';'41'='IPv6';'42'='SDRP';'43'='IPv6-Route';'44'='IPv6-Frag';'45'='IDRP';'46'='RSVP';'47'='GREs';'48'='DSR';'49'='BNA';'50'='ESP';'51'='AH';'52'='I-NLSP';'53'='SWIPE';'54'='NARP';'55'='MOBILE';'56'='TLSP';'57'='SKIP';'58'='IPv6-ICMP';'59'='IPv6-NoNxt';'60'='IPv6-Opts';'62'='CFTP';'64'='SAT-EXPAK';'65'='KRYPTOLAN';'66'='RVD';'67'='IPPC';'69'='SAT-MON';'70'='VISA';'71'='IPCU';'72'='CPNX';'73'='CPHB';'74'='WSN';'75'='PVP';'76'='BR-SAT-MON';'77'='SUN-ND';'78'='WB-MON';'79'='WB-EXPAK';'80'='ISO-IP';'81'='VMTP';'82'='SECURE-VMTP';'83'='VINES';'84'='TTP/IPTM';'85'='NSFNET-IGP';'86'='DGP';'87'='TCF';'88'='EIGRP';'89'='OSPF';'90'='Sprite-RPC';'91'='LARP';'92'='MTP';'93'='AX.25';'94'='OS';'95'='MICP';'96'='SCC-SP';'97'='ETHERIP';'98'='ENCAP';'100'='GMTP';'101'='IFMP';'102'='PNNI';'103'='PIM';'104'='ARIS';'105'='SCPS';'106'='QNX';'107'='A/N';'108'='IPComp';'109'='SNP';'110'='Compaq-Peer';'111'='IPX-in-IP';'112'='VRRP';'113'='PGM';'115'='L2TP';'116'='DDX';'117'='IATP';'118'='STP';'119'='SRP';'120'='UTI';'121'='SMP';'122'='SM';'123'='PTP';'124'='IS-IS over IPv4';'125'='FIRE';'126'='CRTP';'127'='CRUDP';'128'='SSCOPMCE';'129'='IPLT';'130'='SPS';'131'='PIPE';'132'='SCTP';'133'='FC';'134'='RSVP-E2E-IGNORE';'135'='Mobility Header';'136'='UDPLite';'137'='MPLS-in-IP';'138'='manet';'139'='HIP';'140'='Shim6';'141'='WESP';'142'='ROHC'}
#Nombre de lignes sur lesquelles porte l'exécution du 1er Get-EventLog
$rows=10000
#Intervalle d'exécution en secondes. Plus elle est longue, plus le nombre de lignes à analyser est importante
#Un trop grand intervalle risque de faire perdre le processus
$timer=5
#Pour extraire des Logs au delà de cette valeur
$limite=Get-Date
#Boucle infinie
while($true)
{
    #On attend en fonction de la valeur $timer
    Start-Sleep -Seconds $timer
    #On extrait les logs
    $logs=Get-EventLog -LogName Security -Newest $rows|Select EventId,TimeGenerated,CategoryNumber, Message|Where {$_.EventId -in 5156,5157 -and $_.CategoryNumber -eq 12810}
    #S'il y a quelque chose dans les logs, on traite
    If($logs)
    {
        #$max, $min servent à ajuster le nombre de lignes
        $max=($logs|Measure TimeGenerated -Maximum).Maximum
        $min=($logs|Measure TimeGenerated -Minimum).Minimum
        #Ajustement du nombre de lignes
        $temps=((Get-Date $max) - (Get-Date $min)).TotalSeconds
        If($temps -eq 0)
        {
            $temps=1
        }
        $rows=[int]($rows/$temps*$timer/0.8)
        #Filtrage sur la limite
        $logs=$logs |Select TimeGenerated,EventId,Message| Where TimeGenerated -gt $limite
        #passe de limite à Max
        $limite=$max
        ForEach($log in $logs)
        {
            $datetime=Get-Date $log.TimeGenerated -format 'dd/MM/yyyy HH:mm:ss'
            #Statut pass/block fonction de la valeur de EventId 5156/5157
            $statut=$log.EventId
            If($statut -eq 5156)
            {
                $statut='pass'
            }
            ElseIf($statut -eq 5157)
            {
                $statut='block'
            }
            $message=$log.Message
            #Récupération du nom de l'application à partir du corps du message
            $application=''
            If($message -match "Nom de l’application[^:]+:[ \t]+([^\r]+)[\r]")
            {
                $application=$Matches[1]
            }
            #Détermination de la direction du paquet : in/out
            $direction=''
            If($message -match "Direction[^:]+:[^%]+%%(1459[23])[\r]")
            {
                $direction=$Matches[1]
                If($direction -eq 14593)
                {
                    $direction='out'
                }
                ElseIf($direction -eq 14592)
                {
                    $direction='in'
                }
            }
            #Protocole indicé par le numéro déclaré dans le tableau associatif $protocols
            $protocole=''
            If($message -match "Protocole[^:]+:[^0-9]+([0-9]+)[\r]")
            {
                $protocole=$Matches[1]
                $protocole=$protocols["$protocole"]
            }
            #Port source
            $srcport=''
            If($message -match "Port source[^:]+:[^0-9]+([0-9]+)[\r]")
            {
                $srcport=$Matches[1]
            }
            #Port destination
            $dstport=''
            If($message -match "Port de destination[^:]+:[^0-9]+([0-9]+)[\r]")
            {
                $dstport=$Matches[1]
            }
            #Ip Source
            $srcip=''
            If($message -match "Adresse source[^:]+:[^0-9a-f:\.]+([0-9a-f:\.]+)[\r]")
            {
                $srcip=$Matches[1]
            }
            #Ip Destination
            $dstip=''
            If($message -match "Adresse de destination[^:]+:[^0-9a-f:\.]+([0-9a-f:\.]+)[\r]")
            {
                $dstip=$Matches[1]
            }
            #Ajout au fichier de log
            $row="$datetime`t$application`t$statut`t$direction`t$protocole`t$srcip`t$srcport`t$dstip`t$dstport"
            Add-Content -Path $path -value $row
        }
    }
}
 

Scripting / ,