Si vous laissez une machine connectée à Internet avec le protocole RDP ouvert, vous pourrez constater que dans le journal d’évènement énormément de machines essaient de se connecter en utilisant divers comptes.
L’idée est de bloquer ces attaques de manière automatique.
On va donc créer un script PowerShell qui sera déclencha dès la détection d’attaque au travers des journaux d’évènements et puis modifiera une règle du firewall Windows afin de stopper l’attaque.
Étape 1
Sur Windows 2012 R2, Microsoft ne nous a pas spécialement aidé car dans le journal de sécurité on détecte bien la tentative de connexion, en revanche l’ip source n’est pas spécifiée (ce n’est plus le cas dans Windows 2016):
On sait donc juste que une attaque a eu lieu…
Mais si l’on regarde dans le journal Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational on retrouve un évènement 140 nous fournissant l’adresse du coupable.
Malheureusement, cet evenement n’est déclanché que lorque le nom utilisé est inconnu. Si le nom existe alors cet évenement n’est pas déclanché.
La solution consiste donc a corréler 2 évènement:
L’événement 131 du journal Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational qui signale une connexion:
et l’évènement du journal de sécurité
Ainsi l’on connaît l’adresse source d’où proviens la tentative de connexion !
Étape 2
Créer le script qui va récupérer l’adresse IP pour la mettre dans une règle Firewall
Petit prérequis, créer un règle de blocage pour le rdp 3389:
1 |
New-NetFirewallRule -DisplayName "BLACK LIST" -Direction Inbound -LocalPort 3389 -Protocol TCP -RemoteAddress "8.8.8.8" -Action Block |
Ensuite ile faut créer un PowerShell pour alimenter cette règle:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
Import-Module PSSQLite $regex = [regex] "\d+\.\d+\.\d+\.\d+" $logfile = "E:\Firewall\blocked.log" (Get-Date).ToString() + ' Start Script' >> $logfile $Database = "E:\Firewall\IPTable.SQLite" $MaxFailedLogon = 1 # NB d'echec d'authentification MAX $Unban = 48 # NB d'heure avant débannissement $query_insert = "INSERT INTO IP (IP, Timestamp) VALUES (@IP, @TS)" $query_MaxFailed = "SELECT IP,Timestamp, COUNT(*) FROM IP GROUP BY IP HAVING COUNT(*) > @MAXFAILED" $query_purge = "DELETE FROM IP where TimeStamp < @TS" $DT = [DateTime]::Now.AddSeconds(-120) (Get-Date).ToString() + ' requete Event ' + ($DT).ToString() >> $logfile $af = Get-WinEvent -FilterHashTable @{ LogName = "Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational"; ID = 131 ;StartTime = $DT } -MaxEvents 1 | select-string -inputobject {$_.message} -Pattern $regex |% { $_.Matches } |Select-Object @{n='IpAddress';e={$_.Value} } $getip = $af | group-object -property IpAddress | Select -property Name # Purge des IP bannies (Get-Date).ToString() + ' Purge des IP' >> $logfile Invoke-SqliteQuery -DataSource $Database -Query $query_purge -SqlParameters @{TS = ((get-date).AddHours((-$Unban)))} Invoke-SqliteQuery -DataSource $Database -Query "DELETE FROM IP WHERE ip is null" $fw = New-Object -ComObject hnetcfg.fwpolicy2 $BlackListRule = $fw.rules | where {$_.name -eq 'MY BLACKLIST'} $IPValue = $getip | where {$_.Name.Length -gt 1 } #Ajout des IPs dans Sqlite (Get-Date).ToString() + ' Ajout IP Base' >> $logfile if (($IPValue.name).Length -gt 1) {Invoke-SqliteQuery -DataSource $Database -Query $query_insert -SqlParameters @{ IP = $IPValue.name TS = (get-date) } } #Mise a jour de la regle FireWall $csv="" (Get-Date).ToString() + ' Construction de la liste IP' >> $logfile $collection = Invoke-SqliteQuery -DataSource $Database -Query $query_MaxFailed -SqlParameters @{MAXFAILED = $MaxFailedLogon} foreach ($item in $collection) { if ($csv.Length -gt 0 ) {$csv= $csv += ',' + $item.IP} else { $csv= $item.IP} } if ($csv.length -gt 1) {$csv= $csv += ',127.0.0.1' # Anti lockout $BlackListRule.RemoteAddresses = $csv $csv| %{(Get-Date).ToString() + ' Ajout de IP Firewall ' + $IPValue.name >> $logfile} } Exit |
On utilise PSSQLite afin de stocker les adresses Ip ainsi que l’heure de stockage. Cela permet 2 choses:
- Savoir si une adresse récurrente essaie de se connecter et donc de la bloquer après x tentatives
- Permettre au script de dé bannir une adresse après un certain temps.
Il ne reste plus qu’a attacher l’exécution de ce script a l’évent 4625 au sein du Task Scheduler:
Les adresse IP avec des connexions échouée se retrouvent dans la base :
Et la règle de Firewall est mise a jour:
Bonjour,
Merci pour ce script, il fonctionne impec sur notre serveur.
Anthony
Merci !!
Bonjour,
J’ai découvert votre solution et je voulais faire des tests mais impossible d’installer un module dans powershell … et impossible de trouver le module d’installation de module sur le web…
Si vous auriez un lien a partager….
Je suis sur un serveur en 2012 avec powershell en version 4.
Voila : https://github.com/RamblingCookieMonster/PSSQLite
Bonjour,
Merci pour ce super script ! il va nous être très utile prochainement et les premiers résultats sont très concluants !
J’ai cependant une petite question : La ligne 46 ({$csv= $csv += ‘,127.0.0.1’ # Anti lockout) permet logiquement d’inscrire des adresses à ne pas bloquer ?
Chez nous elle fait exactement l’inverse… 127.0.0.1 est directement bloqué.
Ai-je oublié quelque chose ?
Bonjour,
La ligne 46 contient toutes les ip à bloquer.
De mémoire ,j’ai ajouté le loop-back car si la variable $csv est vide alors la règle de blocage s’applique a toutes les IP sans distinction
Bonjour
Serait-il possible d’avoir le script pour créer la DB « IPTable.SQLite » ?
(oui je sais 1 an après, mais fallait pas faire un script intéressant :p )
Alors je me réponds à moi-même :
– l’erreur ne vient pas de la DB qui se génère automatiquement, mais de mes journaux sous Windows Server 2016
Bonjour à tous,
merci pour l’astuce en revanche j’ai une erreur sur le script :
La propriété « RemoteAddresses » est introuvable dans cet objet. Vérifiez qu’elle existe et qu’elle peut être définie.
Je comprends pas le problème, quelqu’un à une idée ?
Vous avez bien créé la regle avec la commande New-NetFirewallRule -DisplayName « BLACK LIST » -Direction Inbound -LocalPort 3389 -Protocol TCP -RemoteAddress « 8.8.8.8 » -Action Block ??
Bonjour,
Merci pour le script, par contre je reçois une erreur à chaque commande « Invoke-SqliteQuery ».
Merci de votre aide !!!
Invoke-SqliteQuery : Exception calling « Fill » with « 1 » argument(s): « SQL logic error or missing database
no such table: IP »
At C:\scriptipblock\rdp-block.ps1:18 char:1
+ Invoke-SqliteQuery -DataSource $Database -Query $query_purge -SqlParameters @{TS …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Invoke-SqliteQuery
A priori il n’y a pas de table IP dans la base SQLite: La base est elle créé (vérifier son chemin…) ?
La base se crée mais elle reste vide.
Aucune table n’est créée
Mon log event 131 ressemble à ceci
The server accepted a new TCP connection from client 185.156.177.230:45419.
Est-ce que le fait d’avoir un port au bout de l’adresse ip pourrais changer quelque chose ???
Merci !!!
Oui, effectivement, il faut créer la table IP dans SQLite 🙂
Import-Module PSSQLite
$Database = « E:\Firewall\IPTable.SQLite »
$Query = « CREATE TABLE IP (IP VARCHAR(20),Timestamp DATETIME) »
Invoke-SqliteQuery -Query $Query -DataSource $Database
Merci pour ce script ..c est exactement ce que je recherchais ..et depuis un moment …
Bonjour
J’essaye de reproduire sur 2022 server : dans le planificateur de taches je cherche le déclencheur adéquat : sur un évènement de base, journal, mais quel journal ? la liste contenant « Microsoft-Windows-Security-…. » je ne retrouve pas les infos telles que décrites ici comment faire ? merci