2018-06-27

Exchange Auth Login Failed Ban Powershell Script

Exchange 是公開對外服務
難免遭受 Try 帳號的攻擊, 除了 IPS 設備以外
窮人也可以透過查詢 Transport Role Log 的方式將驗證失敗紀錄中的來源 IP 加到 Windows Advanced Firewall 來進行阻擋
因 PowerShell 版本差異, 舊版 OS 有些 cmdlet 不能用
故根據作業系統版本分別寫了兩個不同的 Script

程式尚有許多未盡之處, 比如只查最後一個 Log File 的最後多少行
不是按照時間來查詢, 可能會有遺漏或重複的情況, 不過暫時先這樣用吧!

Update: 2023.03.10 文末附上最近用的 Script

Windows Server 2012:


===== 程式開始 =====

# in Hours
$BlockTime = 24;
$SearchTailLines = 10000;
$LogFullPath = "C:\Program Files\Microsoft\Exchange Server\V14\TransportRoles\Logs\ProtocolLog\SmtpReceive\"
$RuleGroupName = "ExchangeAuthFailBlockIPs"

#-----------------------------------------------------------------
$RemoteAddress = @();
$NewBlockIP = @();

$LastLogFile = Get-ChildItem $LogFullPath | sort LastWriteTime | select -last 1
write-host "Working on File: $LastLogFile"
$AuthFailedLog = Get-Content -Path $LastLogFile.FullName -Tail $SearchTailLines | where-object {$_ -Like '*Inbound AUTH LOGIN failed*'}
foreach ($Item in $AuthFailedLog) {
Clear-variable -Name "RemoteAddress";
Clear-variable -Name "NewBlockIP";
$Elements = $Item.Split(",");
if (([DateTime]$Elements[0]) -gt $(Get-Date).AddHours(-$BlockTime)) {
$FirewallRuleName  = ('{0:yyyy-MM-dd HH}' -f [DateTime]$Elements[0])+':00:00';
$IPTemp = $Elements[5].Split(":");
$AddBlockIP = $IPTemp[0];
$RemoteAddress = @();
$NewBlockIP = @();

$CheckRuleExist = Get-NetFirewallRule -DisplayName $FirewallRuleName;
if ($CheckRuleExist) {
# Firewall Rule Exist
$RemoteAddress = $($CheckRuleExist | Get-NetFirewallAddressFilter).RemoteAddress;
$NewBlockIP = $RemoteAddress.Split(',');
$NewBlockIP += $AddBlockIP;
$NewBlockIP = $NewBlockIP | select -uniq;
if ($NewBlockIP -ne $RemoteAddress) {
Get-NetFirewallRule -DisplayName $FirewallRuleName | Get-NetFirewallAddressFilter | Set-NetFirewallAddressFilter -RemoteAddress $NewBlockIP
write-host "Update $FirewallRuleName"
write-host "$NewBlockIP";
};
} else {
# Firewall Rule Not Exist
New-NetFirewallRule -DisplayName $FirewallRuleName -Group "ExchangeAuthFailBlockIPs" -Direction Inbound -Action Block -RemoteAddress $AddBlockIP
write-host "Add $FirewallRuleName"
write-host "$AddBlockIP";
};
};
};

#Remove Rules Two Hours Ago
Get-NetFirewallRule -Group "ExchangeAuthFailBlockIPs" | where-object {[DateTime]$_.DisplayName -lt $(Get-Date).AddHours(-$BlockTime)} | Remove-NetFirewallRule

===== 程式結束 =====


Windows Server 2008 R2:


必須安裝 PowerShell 4.0 以上
安裝參考: Windows Management Framework 5.1

===== 程式開始 =====

# in Hours
$BlockTime = 24;
$SearchTailLines = 10000;
$LogFullPath = "C:\Program Files\Microsoft\Exchange Server\V14\TransportRoles\Logs\ProtocolLog\SmtpReceive\"
$RuleGroupName = "ExchangeAuthFailBlockIPs"

#-----------------------------------------------------------------
$RemoteAddress = @();
$NewBlockIP = @();

$FirewallObject = New-Object -ComObject HNetCfg.FwPolicy2;

$LastLogFile = Get-ChildItem $LogFullPath | sort LastWriteTime | select -last 1
write-host "Working on File: $LastLogFile"
$AuthFailedLog = Get-Content -Path $LastLogFile.FullName -Tail $SearchTailLines | where-object {$_ -Like '*Inbound AUTH LOGIN failed*'}
foreach ($Item in $AuthFailedLog) {
Clear-variable -Name "RemoteAddress";
Clear-variable -Name "NewBlockIP";
$Elements = $Item.Split(",");
if (([DateTime]$Elements[0]) -gt $(Get-Date).AddHours(-$BlockTime)) {
$FirewallRuleName  = ('{0:yyyy-MM-dd HH}' -f [DateTime]$Elements[0])+':00:00';
$IPTemp = $Elements[5].Split(":");
$AddBlockIP = $IPTemp[0];
$RemoteAddress = @();
$NewBlockIP = @();

$CheckRuleExist = $FirewallObject.rules | where {$_.Name -eq $FirewallRuleName};
if ($CheckRuleExist) {
$RemoteAddress = $($CheckRuleExist.RemoteAddresses).Replace('/255.255.255.255','');
$NewBlockIP = $RemoteAddress.Split(',');
$NewBlockIP += $AddBlockIP;
$NewBlockIP = $NewBlockIP | select -uniq;
$AddBlockIP = '';
foreach ($IP in $NewBlockIP) {
if ($AddBlockIP -ne '') {
$AddBlockIP += ',';
};
$AddBlockIP += $IP;
};
if ($AddBlockIP -ne $RemoteAddress) {
$CheckRuleExist.RemoteAddresses = $AddBlockIP;
$CheckRuleExist.update;
write-host "Update $FirewallRuleName"
write-host "$AddBlockIP";
};
} else {
$Rule = New-Object -ComObject HNetCfg.FWRule;
$Rule.Name = $FirewallRuleName;
$Rule.Enabled = $True;
$Rule.Direction = 1;
$Rule.Grouping = $RuleGroupName;
$Rule.Profiles = 7;
$Rule.Action = 0;
$Rule.EdgeTraversal = $false;
$Rule.RemoteAddresses = $AddBlockIP;
$FirewallObject.Rules.Add($Rule);
write-host "Add $FirewallRuleName"
write-host "$AddBlockIP";
};
};
};

#Delete Rules
$CheckRuleToDelete = $FirewallObject.rules | where {$_.Grouping -eq $RuleGroupName} | where-object {[DateTime]$_.Name -lt $(Get-Date).AddHours(-$BlockTime)};
foreach ($Rule in $CheckRuleToDelete) {
write-host "Delete Rule: ""$($Rule.Name)"""
netsh advfirewall firewall delete rule name=($Rule.Name)

};


===== 程式結束 =====

--------------------

Update: 2023.03.10 最近用的 Script for Exchange 2016

===== 程式開始 =====
# in Hours
$BlockTime = 720;
$LookBackHours = 8;
$SearchTailLines = 10000;
$LogFullPath = "C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd\ProtocolLog\SmtpReceive\"
$RuleGroupName = "ExchangeAuthFailBlockIPs"

#-------------------------------------------------------------------------------------------------------------------------------------------
$RemoteAddress = @();
$NewBlockIP = @();

$FirewallObject = New-Object -ComObject HNetCfg.FwPolicy2;

$LastLogFile = Get-ChildItem $LogFullPath | sort LastWriteTime | select -last 1
write-host "Working on File: $LastLogFile"
$AuthFailedLog = Get-Content -Path $LastLogFile.FullName -Tail $SearchTailLines | where-object {$_ -Like '*Inbound AUTH LOGIN failed*' -or $_ -Like '*Unrecognized authentication type*'}
$ProcessType = "";
$Processindex = 0;

$DateTimeString = (Get-Date).ToUniversalTime().AddHours(8).ToString('yyyy-MM-dd HH:mm:ss')
$SMTPServer = '192.168.0.10';
$NotifierEmailAddress = 'Notifier@contoso.com';
$SystemManagerRecipients = @('Dino9021 <Dino9021@contoso.com>', 'Dino9022 <Dino9022@contoso.com>');
$MailSubject = ('Exchange Attack Detected @' + $env:computername + ' @' + $DateTimeString);
$MailBody = '';

write-host ('Found ' + $AuthFailedLog.Count + 'Records');
foreach ($Item in $AuthFailedLog) {
write-host ('Processindex: ' + $Processindex);
Clear-variable -Name "RemoteAddress";
Clear-variable -Name "NewBlockIP";
$Elements = $Item.Split(",");
if (([DateTime]$Elements[0]) -gt $(Get-Date).AddHours(-$LookBackHours)) {
$FirewallRuleName  = ('ExchangeAuthFailBlockIPs ' + '{0:yyyy-MM-dd HH}' -f ([DateTime]($Elements[0] + ' ' + $Elements[1])).AddHours(8))+':00:00';
$IPTemp = $Elements[5].Split(":");
$AddBlockIP = $IPTemp[0];
$RemoteAddress = @();
$NewBlockIP = @();

$CheckRuleExist = $FirewallObject.rules | where {$_.Name -eq $FirewallRuleName};
if ($CheckRuleExist) {
$RemoteAddress = $($CheckRuleExist.RemoteAddresses).Replace('/255.255.255.255','');
$NewBlockIP = $RemoteAddress.Split(',');
if (($NewBlockIP -Contains($AddBlockIP)) -eq $False) {
write-host ('AddBlockIP: ' + $AddBlockIP);
$NewBlockIP += $AddBlockIP;
$NewBlockIP = $NewBlockIP | select -uniq;
$AddBlockIP = '';
foreach ($IP in $NewBlockIP) {
if ($AddBlockIP -ne '') {
$AddBlockIP += ',';
};
$AddBlockIP += $IP;
};
if ($AddBlockIP -ne $RemoteAddress) {
$CheckRuleExist.RemoteAddresses = $AddBlockIP;
$CheckRuleExist.update;
$ProcessType = "Update";
};
};
$MailBody = $NewBlockIP.Replace(',',"`r`n")
} else {
$Rule = New-Object -ComObject HNetCfg.FWRule;
$Rule.Name = $FirewallRuleName;
$Rule.Enabled = $True;
$Rule.Direction = 1;
$Rule.Grouping = $RuleGroupName;
$Rule.Profiles = 7;
$Rule.Action = 0;
$Rule.EdgeTraversal = $false;
$Rule.RemoteAddresses = $AddBlockIP;
$FirewallObject.Rules.Add($Rule);
$ProcessType = "Add";
$MailBody = $AddBlockIP;
};
};
$Processindex++;
};

if ($MailBody -ne '') {
$MailBody = ('Add the Follow IP(s) to Firewall to Block inBound Connection for ' + $BlockTime + " Hours`r`n`r`n") + $MailBody;
Send-MailMessage -From $NotifierEmailAddress -To $SystemManagerRecipients -Subject $MailSubject -Body $MailBody -Encoding utf8 -SmtpServer $SMTPServer;
};

write-host "$ProcessType $FirewallRuleName"
write-host "$AddBlockIP";

#Delete Rules
$CheckRuleToDelete = $FirewallObject.rules | where {$_.Grouping -eq $RuleGroupName} | where-object {[DateTime]$_.Name -lt $(Get-Date).AddHours(-$BlockTime)};
foreach ($Rule in $CheckRuleToDelete) {
write-host "Delete Rule: ""$($Rule.Name)"""
netsh advfirewall firewall delete rule name=($Rule.Name)
};
===== 程式結束 =====

沒有留言:

張貼留言