søndag 30. desember 2012

Automatically block RDP attacks on your Windows Server 2008

Having your Windows Server 2008 exposed on the internet is a security risk. The minimum requried actions is to rename your "administrator" account, make sure you have a secure password and change the default RDP-port.

A guide on how to change the RDP port and firewall rules can be found here: http://www.iteezy.com/change-rdp-3389-port-on-windows-2008-server/qc/10098

Commercial tools for preventing RDP attacks also exists, like RdpGuard or Syspeace. Lately, a free alternative named EvlWatcher has been released.

I wanted to take a different approach. In Windows Server 2008 you can attach tasks to be executed on particular logged events. Adding an attacking IP to the Windows firewall is actually an easy task. I had Windows execute this script whenever event ID 4625 occured:

fail2ban.vbs:

  1. If wscript.arguments.count = 2 then  
  2.     Dim firewall, rule, rulename, ip, re, account  
  3.     'Change this value! This rule must already exist in your inbound firewall rules  
  4.     rulename = "Fail2Ban"  
  5.       
  6.     account = wscript.arguments.item(0)  
  7.     ip = wscript.arguments.item(1)  
  8.     'MsgBox "Debug message: Invalid login with account " & account & " from IP " & ip  
  9.     Set re = new regexp  
  10.     re.Pattern = "\b(([01]?\d?\d|2[0-4]\d|25[0-5])\.){3}([01]?\d?\d|2[0-4]\d|25[0-5])\b"  
  11.   
  12.     If re.Test(ip) And Not IsException(account, ip) Then  
  13.         Set firewall  = CreateObject("HNetCfg.FwPolicy2")  
  14.         Set rule = firewall.Rules.Item(rulename)  
  15.         If Not (rule Is NothingThen  
  16.             If InStr(1,rule.RemoteAddresses,ip,1) = 0 Then  
  17.                 rule.RemoteAddresses = rule.RemoteAddresses & "," & ip  
  18.             End If  
  19.         End If  
  20.         Set firewall = Nothing  
  21.     Else  
  22.         'Invalid IP or excemption from rule  
  23.     End If  
  24. end If  
  25.   
  26. 'Handle exception cases here, you don't want to ban your own IP, for instance...Customize to your needs  
  27. Function IsException(account, ip)  
  28.     
  29.   Dim exip   
  30.   exip = "My.IP"  
  31.   IsException = False  
  32.     
  33.   If ip = exip Then  
  34.     IsException = True  
  35.   End If  
  36. End Function   

For creating the script above I used this blog for inspiration.
  
For creating the event based task I used this blog for reference. Essential parts of the task xml configuration I changed to fit my needs:

  1. <Triggers>  
  2.     <EventTrigger>  
  3.         <Enabled>true</Enabled>  
  4.         <Subscription>...omitted for layout purposes...</Subscription>  
  5.         <ValueQueries>  
  6.             <Value name="AccountDomain">Event/EventData/Data[@Name='TargetDomainName']</Value>  
  7.             <Value name="AccountName">Event/EventData/Data[@Name='TargetUserName']</Value>  
  8.             <Value name="ClientAddress">Event/EventData/Data[@Name='IpAddress']</Value>  
  9.             <Value name="Computer">Event/System/Computer</Value>  
  10.             <Value name="EventID">Event/System/EventID</Value>  
  11.         </ValueQueries>  
  12.     </EventTrigger>  
  13. </Triggers>   
  14.   
  15. ...  
  16.   
  17. <Actions Context="Author">  
  18.     <Exec>  
  19.       <Command>D:\Scripts\fail2ban.vbs</Command>  
  20.       <Arguments>"$(AccountName)" "$(ClientAddress)"</Arguments>  
  21.     </Exec>  
  22.   </Actions>   
Edit: Powershell has some more functionality allowing a little more flexibility that can detect hammering instead of ocasional failed logins. This script let's you decide that an IP address must exceed X number of failed logins within a Y hour time span before the IP is added to the Windows firewall.
Fail2Ban.vbs:
  1. Dim objShell, scriptpath, args, ip, acc  
  2.   
  3. scriptpath = "D:\Scripts\fail2ban.ps1"  
  4. acc = wscript.arguments.item(0)  
  5. ip = wscript.arguments.item(1)  
  6.   
  7. args = chr(34) & acc & chr(34) & " " & chr(34) & ip & chr(34)  
  8.   
  9. Set objShell = CreateObject("WScript.Shell")  
  10. 'Run powershell hidden  
  11. objShell.Run ("powershell " & scriptpath & " " & args), 0, true  
  12. Set objShell = Nothing  
Fail2ban.ps1:
  1. $targetaccount = $args[0]  
  2. $sourceip = $args[1]  
  3.   
  4. #Filter/Threshold options  
  5. $datefilter = [DateTime]::Now.AddHours(-1) # check only last x hours  
  6. $countfilter = 3  
  7. $rulename ="MyRule" #Firewall rule name  
  8.   
  9. $TargetUserName = @{n='TargetUserName';e={$_.ReplacementStrings[5]}}  
  10. $IpAddress = @{n='IpAddress';e={$_.ReplacementStrings[19]}}  
  11.   
  12. #return IP if number of failed logins for specifed IP has exceeded x tries within specified timeframe  
  13. $IP2Ban = Get-Eventlog security -InstanceId 4625 -After $datefilter | where {$_.ReplacementStrings[19] -eq $sourceip} | select-object $IpAddress | Group-Object -Property IPAddress | where Count -gt $countfilter | Select-Object -Property Name  
  14.   
  15. if ( $IP2Ban -ne $null)  
  16. {  
  17.     #Add IP to firewall  
  18.     #$IP2Ban.Name is same as $sourceip  
  19.   
  20.     $fw = New-object –comObject HNetCfg.FwPolicy2  
  21.     $myrule = $fw.Rules | where {$_.Name -eq $rulename}  
  22.   
  23.     if (-not ($myrule.RemoteAddresses -match $sourceip) -and -not ($sourceip -like "my.ip"))  
  24.     {  
  25.         $myrule.RemoteAddresses += (","+$sourceip)  
  26.     }  
  27.     $fw = $null  
  28. }