X回のWindowsサーバーへのログイン試行が失敗した後にIPアドレスを禁止することは可能ですか?方法を知っている特定のアカウントではなく、マシン全体です。
ユーザー名を推測しようとするブルートフォース攻撃によってかなり大きな打撃を受けるため、サーバーの負荷を軽減するのに役立ちます。
X回のWindowsサーバーへのログイン試行が失敗した後にIPアドレスを禁止することは可能ですか?方法を知っている特定のアカウントではなく、マシン全体です。
ユーザー名を推測しようとするブルートフォース攻撃によってかなり大きな打撃を受けるため、サーバーの負荷を軽減するのに役立ちます。
回答:
これは、powershellおよびタスクマネージャーを使用して実行できます。おそらく完璧なソリューションではありませんが、非常にうまく機能し、2か月で約100個のブロックされたIPアドレスがあります。EventLogから指定されたイベント(「監査失敗」)を選択するスクリプトを作成しました。任意のIPアドレスからの失敗したログインが多数ある場合、指定されたIPアドレスへのトラフィックをブロックする「BlockAttackers」という名前のファイアウォールルール(手動で作成)に追加されます。
PS1スクリプト:
$DT = [DateTime]::Now.AddDays(-1) # check only last 24 hours
$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $DT | Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]} } # select Ip addresses that has audit failure
$g = $l | group-object -property IpAddress | where {$_.Count -gt 20} | Select -property Name # get ip adresses, that have more than 20 wrong logins
$fw = New-Object -ComObject hnetcfg.fwpolicy2 # get firewall object
$ar = $fw.rules | where {$_.name -eq 'BlockAttackers'} # get firewall rule named 'BlockAttackers' (must be created manually)
$arRemote = $ar.RemoteAddresses -split(',') #split the existing IPs into an array so we can easily search for existing IPs
$w = $g | where {$_.Name.Length -gt 1 -and !($arRemote -contains $_.Name + '/255.255.255.255') } # get ip addresses that are not already in firewal rule. Include the subnet mask which is automatically added to the firewall remote IP declaration.
$w| %{$ar.remoteaddresses += ',' + $_.Name} # add IPs to firewall rule
スケジューラーでタスクを作成し、トリガーをイベント4625(ターミナルサービスを含むWindowsログイン)に設定します。ただし、たとえば1時間に2回実行するようにトリガーを設定して、サーバーへの不要なロードを回避できます。
トリガーの後、powershellスクリプトを実行します。このスクリプトを実行するには、より高い権限も設定する必要があります。そうしないと、セキュリティ例外が発生して失敗します。
このスクリプトを他のセキュリティイベントにバインドすることもできます。
私はこの質問が古いことを知っていますが、実際に数週間前にまったく同じことをしようと始めたとき、実際に私が偶然見つけた最初のフォーラム投稿でした。不正なログインイベントログエントリのみについてイベントログを24時間解析し、不正なログインが10個以上あるものを取得し、それを使用してipsecフィルターリストに入れる作業スクリプトを作成しました。 netshコマンド。次に、この行でバッチファイルをpowershell .\*scriptname.ps1*
作成し、24時間ごとにバッチファイルを実行するスケジュールタスクを作成しました(何らかの理由で直接実行されません)。
$DATE = [DateTime]::Now.AddDays(-1)
$EVS = Get-EventLog Security -InstanceId 529 -after $DATE
$EVS | select-string -inputobject {$_.message} -pattern "Source Network Address:(.)*\.*\.*\.*" -allmatches | foreach-object {$_.Matches} | foreach-object {$_.Value} | foreach-object {$_.replace("Source Network Address:", "")} | group-object -property $_ | where-object {$_.count -gt 10} | select-object -property name | format-list | out-file c:\rdpblock.txt
get-content -path c:\rdpblock.txt | foreach-object {$_.replace("Name :", "")} | out-file c:\rdpblockcleaned.txt
get-content -path c:\rdpblockcleaned.txt | select-object -unique | out-file c:\rdpblocknospaces.txt
$RDPIP = get-content -path c:\rdpblocknospaces.txt | select-object -skip 1
$RDPIP | foreach-object {$_.replace(" ", "")} | foreach-object {netsh ipsec static add filter filterlist=RDP_BLOCK srcaddr=$($_) dstaddr=any}
このスクリプトはおそらく非効率的であることを知っていますが、この作業を始めたときは、PowerShellの経験がまったくなかったため、スクリプトを最適化する能力は望まれていません。しかし、この事実にもかかわらず、私はこれを使用できる人と共有すると思いました。
Remundaに最初のアイデアを与えてくれたことに感謝します。このポスターは、powershellを使用してイベントログを検索するというアイデアに私を向けたものです。
このスクリプトはremundaの答えに基づいて構築され、https://serverfault.com/a/397637/155102をさらに進めます。これは、「BlockAttackers」ルールにまだIPが入力されていないことを示します(文字列として「*」を返します)。また、ログファイルにコメントを書き込み、IPがルールに追加された時期を知らせます。
IPアドレスをブロックする「ブロック攻撃者」ルールを作成することをお勧めしますが、最初は無効にします。次に、このスクリプトを手動で1回実行し、「RemoteAddresses」フィールドにブロックする必要のある実際のIPアドレスを入力できるようにします。これらのIPアドレスを調べて、重要なものが何も追加されていないことを確認してから、ファイアウォールルールを有効にします。説明に従って、このルールをファイアウォールに追加します。
#Checks for IP addresses that used incorrect password more than 10 times
#within 24 hours and blocks them using a firewall rule 'BlockAttackers'
#Check only last 24 hours
$DT = [DateTime]::Now.AddHours(-24)
#Select Ip addresses that has audit failure
$l = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $DT | Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]} }
#Get ip adresses, that have more than 10 wrong logins
$g = $l | group-object -property IpAddress | where {$_.Count -gt 10} | Select -property Name
#Get firewall object
$fw = New-Object -ComObject hnetcfg.fwpolicy2
#Get firewall rule named 'BlockAttackers' (must be created manually)
$ar = $fw.rules | where {$_.name -eq 'BlockAttackers'}
#Split the existing IPs into an array so we can search it for existing IPs
$arRemote = $ar.RemoteAddresses -split(',')
#Only collect IPs that aren't already in the firewall rule
$w = $g | where {$_.Name.Length -gt 1 -and !($arRemote -contains $_.Name + '/255.255.255.255') }
#Add the new IPs to firewall rule
$w| %{
if ($ar.RemoteAddresses -eq '*') {
$ar.remoteaddresses = $_.Name
}else{
$ar.remoteaddresses += ',' + $_.Name
}
}
#Write to logfile
if ($w.length -gt 1) {
$w| %{(Get-Date).ToString() + ' ' + $_.Name >> '.\blocked.txt'}
}
この答えは信用できませんが、https://serverfault.com/users/7200/evan-andersonは彼のプロジェクトについて言及していますhttp://opensource.wellbury.com/projects/windows_sshd_block/newest-release/
一般に、ファイアウォールルールを他の誰かに制御させることは、良い考えではありません。それが基本的にあなたがここで求めていることです。
これは古いスレッドです。2014〜2015年にkevinmickeが提供したスクリプトを使用していました。その後、機能しなくなりました。そのため、セキュリティログにIPアドレスを残さないWindowsネットワークセキュリティ認証を採用するには、少し編集する必要がありました。また、通常のFTPを実行していないため、ログフォルダーがなかったためにエラーが発生していたため、その部分を削除しました。主な変更点は、RDPイベントのソースにあります。
$current_date_utc = (Get-Date).ToUniversalTime()
# Set number of failed login attempts after which an IP address will be blocked
$int_block_limit = 10
# Time window during which to check the Security log, which is currently set to check only the last 24 hours
$dat_time_window = [DateTime]::Now.AddDays(-1)
$arr_new_bad_ips_all = (get-winevent -filterhashtable @{ logname='Microsoft-Windows-RemoteDesktopServices-RdpCoreTS/Operational'; starttime=$dat_time_window; id=140 }).message |
% { if ($_ -match "of (.+) failed") { $Matches[1] }} |
Group-Object |
Where {$_.Count -ge $int_block_limit} |
Select -property Name
# Sort the array, selecting only unique IPs (in case one IP shows up in both the Security and FTP logs)
$arr_new_bad_ips_all = $arr_new_bad_ips_all | Foreach-Object { [string]$_.Name } | Select-Object -unique
# Get firewall object
$firewall = New-Object -comobject hnetcfg.fwpolicy2
# Get all firewall rules matching "BlockAttackers*"
$arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}
# If no "BlockAttackers*" firewall rule exists yet, create one and set it to a variable
if ($arr_firewall_rules -eq $null) {
$str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created." enable=yes remoteip="0.0.0.0" | Out-Null
$arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}
}
# Split the existing IPs from current "BlockAttackers*" firewall rule(s) into an array so we can easily search them
$arr_existing_bad_ips = @()
foreach ($rule in $arr_firewall_rules) {
$arr_existing_bad_ips += $rule.RemoteAddresses -split(',')
}
# Clean subnet masks off of IPs that are currently blocked by the firewall rule(s)
$arr_existing_bad_ips_without_masks = $arr_existing_bad_ips | ForEach-Object {$_ -replace "/.*", ""}
# Select IP addresses to add to the firewall, but only ones that...
$arr_new_bad_ips_for_firewall = $arr_new_bad_ips_all | Where {
# contain an IP address (i.e. aren't blank or a dash, which the Security log has for systems that failed FTP logins)
$_.Length -gt 6 -and
# aren't already in the firewall rule(s)
!($arr_existing_bad_ips_without_masks -contains $_) -and
# aren't the local loopback
!($_.StartsWith('127.0.0.1')) -and
# aren't part of the local subnet
!($_.StartsWith('192.168.')) -and
!($_.StartsWith('0.0.'))
}
# If there are IPs to block, do the following...
if ($arr_new_bad_ips_for_firewall -ne $null) {
# Write date and time to script-specific log file
[DateTime]::Now | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt
# Write newly-blocked IP addresses to log file
$arr_new_bad_ips_for_firewall | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt
# Boolean to make sure the new IPs are only added on one rule
$bln_added_to_rule = 0
# Array to hold bad IPs from each rule one at a time, so we can count to make sure adding the new ones won't exceed 1000 IPs
$arr_existing_bad_ips_current_rule = @()
# For each "BlockAttackers*" rule in the firewall, do the following...
foreach ($rule in $arr_firewall_rules) {
if ($bln_added_to_rule -ne 1) {
# Split the existing IPs from the current rule into an array so we can easily count them
$arr_existing_bad_ips_current_rule = $rule.RemoteAddresses -split(',')
# If the number of IPs to add is less than 1000 minus the current number of IPs in the rule, add them to this rule
if ($arr_new_bad_ips_for_firewall.Count -le (1000 - $arr_existing_bad_ips_current_rule.Count)) {
# Add new IPs to firewall rule
$arr_new_bad_ips_for_firewall | %{$rule.RemoteAddresses += ',' + $_}
# Write which rule the IPs were added to to log file
echo "New IP addresses above added to Windows Firewall rule:" $rule.Name | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt
# Set boolean so any other rules are skipped when adding IPs
$bln_added_to_rule = 1
}
}
}
# If there wasn't room in any other "BlockAttackers*" firewall rule, create a new one and add the IPs to it
if ($bln_added_to_rule -ne 1) {
$str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created." enable=yes remoteip="0.0.0.0" | Out-Null
$new_rule = $firewall.rules | Where {$_.Name -eq $str_new_rule_name}
# Add new IPs to firewall rule
$arr_new_bad_ips_for_firewall | %{$new_rule.RemoteAddresses += ',' + $_}
# Write which rule the IPs were added to to log file
echo "New IP addresses above added to newly created Windows Firewall rule:" $new_rule.Name | Out-File -Append -Encoding utf8 C:\Security\blockattackers.txt
}
}
上記のスクリプトはWindows 2012で動作します。Windows2008でネットワークアクセスレベル認証を使用してリモートデスクトップを使用している場合は、次のトリックを行う必要があります。Windows 2008のセキュリティログにはIPアドレスがなく、Microsoft-Windows-RemoteDesktopServices-RdpCoreTSログにもIPアドレスが含まれていないようです。そのため、実際に2つのログを使用する必要がありました。セキュリティログのイベントを、ファイアウォールログのポート3389へのアクセス試行の成功と一致させます。これは推測作業ですが、パスワード攻撃を検出しているようです。違反しているIPを収集する部分は次のとおりです。
$current_date_utc = (Get-Date).ToUniversalTime()
# Set number of failed login attempts after which an IP address will be blocked
$int_block_limit = 10
$dat_time_window = [DateTime]::Now.AddDays(-1)
$logfn = (netsh advfirewall show allprofiles | Select-String Filename | select-object -unique | % { $_ -replace "%systemroot%",$env:systemroot }).substring(10).trimstart().trimend()
$badevts = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $dat_time_window | foreach-object { [datetime]$_.TimeWritten } | sort-object
$fwlog = Select-String -Path $logfn -Pattern "ALLOW TCP" |
% {
if ($_ -match "(201.-..-..) (.+) ALLOW TCP (.+) (.+) (.+) 3389")
{
new-object psobject -property @{
dt = $Matches[1] + ' ' + $Matches[2]
ip = $Matches[3]
}
}
}
$ipa = @()
$j = 0
for ($i=0; $i -lt $fwlog.Count; $i++)
{
$conn = ([datetime]$fwlog[$i].dt).ticks
while (($j -lt $badevts.Count) -and (($badevts[$j]).ticks -lt $conn)) { $j++ }
if ($j -ge $badevts.Count) { break }
if ((($badevts[$j]).ticks - $conn) -le 30000000) { $ipa += ,($fwlog[$i].ip) }
}
$arr_new_bad_ips_all = $ipa |
Group-Object |
Where {$_.Count -ge $int_block_limit} |
Select -property Name
注:ファイアウォールログを有効にすることを忘れないでください。注2:私はPowerShellの専門家ではないので、一部の達人が私のコードを修正/改善できればいいと思います。
基本的には、「無効なターミナルサービスログオンに応答してWindowsによってログに記録されたイベントを受信するWMIイベントシンクとして機能するVBScriptプログラム」です。
完全に動作しているようで、スクリプトを修正する必要がある場合は簡単です。試行回数をログに記録し、許可された試行回数に基づいて禁止するか、アクセス権を付与したくないログイン名をハードコードすることができます。
誤って同じ名前を2回追加すると、1500msごとに再起動する無限ループに入りますが、vbsで問題ない場合は修正/修正が非常に簡単です。
私の現在の設定は1回の再試行だけで、「admin」、「Admin」、「Administrator」、「guest」などのログインが自動的に禁止され、2日間禁止されます。IPに変更するのは簡単ですか?
一晩中どの生物が禁止されているかを確認するためにやみつきになる...
攻撃されているWebサーバーがある場合、動的IP制限拡張をインストールできます。これがサーバーへの標準認証の場合、ドメインに参加しているコンピューターへの攻撃の範囲を制限し、アクセスする必要があるシステムからの試行のみを許可するように設定できるドメインとサーバーの分離を実装できる必要がありますサーバー。Windowsでのブルートフォース攻撃の防止は、アカウントロックアウトポリシーを10分などの設定に設定し、不正なパスワードポリシーを3回の試行に設定することです。つまり、攻撃されているアカウントは3回の試行後10分間ロックされます。IP接続は、デフォルトではWindowsでロックできません。(余談ですが、システムに影響を与えるために1秒間に何回ログオン試行が行われるかについても興味があります)
http://nerderies.blogspot.co.at/2012/12/automatically-banning-ips-with-windows.html
すぐに使えるソリューション(インストールと完了)が必要な場合は、ここで無料のツールを見つけることができます。おそらくこれを読んでください:
現在のバージョン:1.2(.NET Framework 4.0クライアントプロファイル)-> EvlWatcherの現在のバージョンをダウンロードします(個人および商用で無料)
1.2の新機能(ドキュメントの詳細):
- 管理コンソール
- WCFサービスパターン
- ブラックリスト
- 3回の攻撃後のブラックリストへの自動移動(デフォルト)
古いサーバーの場合(.NET Framework 2.0)
-> EvlWatcherの縮小版をダウンロードします(個人および商用での使用は無料)
出発点としてremundaのすばらしいスクリプトを使用して、欠落している1つの主なものを追加しました。失敗したFTPログインからIPアドレスをブロックします。Windows Serverは、誰かがFTP経由でログインに失敗した場合、セキュリティログにIPアドレスを記録しませんが、代わりに「ソースネットワークアドレス」をダッシュに設定します。FTPはブルートフォース攻撃の非常に一般的な攻撃ベクトルであるため、スクリプトに、今日のFTPログで複数のログイン失敗をスキャンし、それらのIPアドレスもブロックする機能を追加しました。
2014/02/07の更新:古いFTPログをすべて処理するためにこれにいくつかの調整を加えたとき、膨大な数の試行(50,000以上)があると、それが作成したアレイが巨大であり、処理が非常に遅くなることに気付きました。それ以来、FTPログを処理する際にはるかに効率的になるように書き直しました。
また、1つのWindowsファイアウォールルールに含めることができるIPの数には、1000の任意のハード制限があることもわかりました。その制限のため、最新のルールがいっぱいになったときに新しいルールを自動的に作成する必要がありました。これを実行し、最初のファイアウォールルールも作成します(独自のルールを作成しない場合)。イベント4625が発生したときに実行するようにスケジューラに追加するだけです。
以下は、Windows Server 2008 R2とWindows 7の両方でテストされたコードです。
# This Windows Powershell script will automatically block IP addresses that attempt to login to the system
# and fail the number of times set below with the $int_block_limit variable or more. Is scans both the Security
# log, which covers Remote Desktop and other attempts, as well as the current day's FTP log. If the $int_block_limit
# limit is hit on either of those logs (separately, not combined), then the IP address will be added to the
# firewall rule.
#
# The script will automatically create a firewall rule named "BlockAttackers (Created yyyy-MM-dd HH:mm:ss UTC)" using
# the current time if one with a name that includes "BlockAttackers" doesn't already exist. Because there's a hard
# limit of 1000 entries (IP addresses) you can block per rule, it will also create similarly-named rules once that
# limit is reached for the latest one.
#
# I recommend setting the script to run as a scheduled task triggered by event 4625 login audit failures from the
# Security log, or alternatively you could set it to run after some amount of time (i.e. every 10 minutes).
#
# Authors:
# Majority of script written by serverfault.com user kevinmicke
# Windows Security Log portion written by serverfault.com user remunda, which provided the starting point for kevinmicke
#
# Details: https://serverfault.com/questions/233222/ban-ip-address-based-on-x-number-of-unsuccessful-login-attempts
# Set number of failed login attempts after which an IP address will be blocked
$int_block_limit = 10
# Time window during which to check the Security log, which is currently set to check only the last 24 hours
$dat_time_window = [DateTime]::Now.AddDays(-1)
# Select from the Security log all IP addresses that have more than $int_block_limit audit failures (event 4625) within $dat_time_window
$arr_new_bad_ips_security_log = @()
$arr_new_bad_ips_security_log = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $dat_time_window |
Select-Object @{n='IpAddress';e={$_.ReplacementStrings[-2]}} |
Group-Object -property IpAddress |
Where {$_.Count -ge $int_block_limit} |
Select -property Name
# Get current time UTC to figure out filename for current FTP log
$current_date_utc = (Get-Date).ToUniversalTime()
# Set path to today's FTP log file
$str_log_file_name = "C:\inetpub\logs\LogFiles\FTPSVC2\u_ex" + $current_date_utc.ToString("yyMMdd") + ".log"
# Search today's FTP log file for "530 1326" to find lines that contain IPs of systems that failed to log in,
# get just the IP from each line, group the IPs by IP to count the attempts from each one, and select only the
# IPs that have $int_block_limit or more bad logins today
$arr_new_bad_ips_ftp = @()
$arr_new_bad_ips_ftp = Select-String $str_log_file_name -pattern "530 1326" |
ForEach-Object {$_.Line.Substring(20,15) -replace " .*", ""} |
Group |
Where {$_.Count -ge $int_block_limit} |
Select -property Name
# Concatenate the two arrays of IPs (one from Security log, one from FTP log)
$arr_new_bad_ips_all = @()
# $arr_new_bad_ips_all = @($arr_new_bad_ips_security_log) + @($arr_new_bad_ips_ftp_over_limit)
$arr_new_bad_ips_all = @($arr_new_bad_ips_security_log) + @($arr_new_bad_ips_ftp)
# Sort the array, selecting only unique IPs (in case one IP shows up in both the Security and FTP logs)
$arr_new_bad_ips_all_sorted = @()
$arr_new_bad_ips_all_sorted = $arr_new_bad_ips_all |
Foreach-Object { [string]$_.Name } |
Select-Object -unique
# Get firewall object
$firewall = New-Object -comobject hnetcfg.fwpolicy2
# Get all firewall rules matching "BlockAttackers*"
$arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}
# If no "BlockAttackers*" firewall rule exists yet, create one and set it to a variable
if ($arr_firewall_rules -eq $null) {
$str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created by BlockAttackers Powershell script written by Kevin Micke." enable=yes remoteip="0.0.0.0" | Out-Null
$arr_firewall_rules = $firewall.Rules | Where {$_.Name -like 'BlockAttackers*'}
}
# Split the existing IPs from current "BlockAttackers*" firewall rule(s) into an array so we can easily search them
$arr_existing_bad_ips = @()
foreach ($rule in $arr_firewall_rules) {
$arr_existing_bad_ips += $rule.RemoteAddresses -split(',')
}
# Clean subnet masks off of IPs that are currently blocked by the firewall rule(s)
$arr_existing_bad_ips_without_masks = @()
$arr_existing_bad_ips_without_masks = $arr_existing_bad_ips | ForEach-Object {$_ -replace "/.*", ""}
# Select IP addresses to add to the firewall, but only ones that...
$arr_new_bad_ips_for_firewall = @()
$arr_new_bad_ips_for_firewall = $arr_new_bad_ips_all_sorted | Where {
# contain an IP address (i.e. aren't blank or a dash, which the Security log has for systems that failed FTP logins)
$_.Length -gt 6 -and
# aren't already in the firewall rule(s)
!($arr_existing_bad_ips_without_masks -contains $_) -and
# aren't the local loopback
!($_.StartsWith('127.0.0.1')) -and
# aren't part of the local subnet
!($_.StartsWith('192.168.')) -and
!($_.StartsWith('10.0.'))
}
# If there are IPs to block, do the following...
if ($arr_new_bad_ips_for_firewall -ne $null) {
# Write date and time to script-specific log file
[DateTime]::Now | Out-File -Append -Encoding utf8 C:\blockattackers.txt
# Write newly-blocked IP addresses to log file
$arr_new_bad_ips_for_firewall | Out-File -Append -Encoding utf8 C:\blockattackers.txt
# Boolean to make sure the new IPs are only added on one rule
$bln_added_to_rule = 0
# Array to hold bad IPs from each rule one at a time, so we can count to make sure adding the new ones won't exceed 1000 IPs
$arr_existing_bad_ips_current_rule = @()
# For each "BlockAttackers*" rule in the firewall, do the following...
foreach ($rule in $arr_firewall_rules) {
if ($bln_added_to_rule -ne 1) {
# Split the existing IPs from the current rule into an array so we can easily count them
$arr_existing_bad_ips_current_rule = $rule.RemoteAddresses -split(',')
# If the number of IPs to add is less than 1000 minus the current number of IPs in the rule, add them to this rule
if ($arr_new_bad_ips_for_firewall.Count -le (1000 - $arr_existing_bad_ips_current_rule.Count)) {
# Add new IPs to firewall rule
$arr_new_bad_ips_for_firewall | %{$rule.RemoteAddresses += ',' + $_}
# Write which rule the IPs were added to to log file
echo "New IP addresses above added to Windows Firewall rule:" $rule.Name | Out-File -Append -Encoding utf8 C:\blockattackers.txt
# Set boolean so any other rules are skipped when adding IPs
$bln_added_to_rule = 1
}
}
}
# If there wasn't room in any other "BlockAttackers*" firewall rule, create a new one and add the IPs to it
if ($bln_added_to_rule -ne 1) {
$str_new_rule_name = "BlockAttackers (Created " + $current_date_utc.ToString("yyyy-MM-dd HH:mm:ss") + " UTC)"
netsh advfirewall firewall add rule dir=in action=block name=$str_new_rule_name description="Rule automatically created by BlockAttackers Powershell script written by Kevin Micke." enable=yes remoteip="0.0.0.0" | Out-Null
$new_rule = $firewall.rules | Where {$_.Name -eq $str_new_rule_name}
# Add new IPs to firewall rule
$arr_new_bad_ips_for_firewall | %{$new_rule.RemoteAddresses += ',' + $_}
# Write which rule the IPs were added to to log file
echo "New IP addresses above added to newly created Windows Firewall rule:" $new_rule.Name | Out-File -Append -Encoding utf8 C:\blockattackers.txt
}
}
Set-ExecutionPolicy RemoteSigned
実行し、ローカルスクリプトを実行できるようにする必要があります。そうしないと、「このシステムではスクリプトの実行が無効になっているため、blockattackers.ps1をロードできません。」というエラーが表示されます。
スクリプトremudaによって編集され、kevinmicke(21時59分で2月7日)は私のシステム(Windows Server 2008のR2)に独自のフォルダを持っているFTPの制御チャネルを、チェックしませんでした。また、- 530 11001
イベントは認識されていません。これは、ハッカーが制御チャネルへのアクセスのみを試みた場合に表示されるようです。そこで、スクリプトにいくつかの行を追加して、2番目のFTP-log-folderを確認します。
#このWindows Powershellスクリプトは、システムへのログインを試みるIPアドレスを自動的にブロックします #そして、$ int_block_limit変数以上で以下に設定された回数に失敗します。スキャンはセキュリティと #ログ。リモートデスクトップやその他の試み、および当日のFTPログをカバーします。$ int_block_limit #これらのログのいずれか(個別に、結合されない)で制限に達すると、IPアドレスが #ファイアウォールルール。 # #スクリプトは、「BlockAttackers(Created yyyy-MM-dd HH:mm:ss UTC)」という名前のファイアウォールルールを自動的に作成します #「BlockAttackers」を含む名前を持つものがまだ存在しない場合、現在の時刻。難しいので #ルールごとにブロックできる1000エントリ(IPアドレス)の制限。同じ名前のルールも一度作成されます #最新の制限に達しました。 # #イベント4625のログイン監査の失敗によってトリガーされるスケジュールされたタスクとして実行するようにスクリプトを設定することをお勧めします #セキュリティログ、または一定時間(10分ごと)後に実行するように設定できます。 # #著者: #serverfault.comユーザーkevinmickeが作成したスクリプトの大半 #kevinmickeの開始点を提供するserverfault.comユーザーremundaによって書き込まれたWindowsセキュリティログの部分 #serverfault.comユーザーUwe Martensによって追加されたFTPの制御チャネルの確認 # #詳細:https://serverfault.com/questions/233222/ban-ip-address-based-on-x-number-of-unsuccessful-login-attempts #失敗したログイン試行の回数を設定すると、IPアドレスがブロックされます $ int_block_limit = 3 #セキュリティログを確認する時間枠。現在は過去24時間のみを確認するように設定されています $ dat_time_window = [DateTime] :: Now.AddDays(-1) #$ dat_time_window内で$ int_block_limitの監査失敗(イベント4625)を超えるすべてのIPアドレスをセキュリティログから選択します $ arr_new_bad_ips_security_log = @() $ arr_new_bad_ips_security_log = Get-EventLog -LogName 'Security' -InstanceId 4625 -After $ dat_time_window | Select-Object @ {n = 'IpAddress'; e = {$ _。ReplacementStrings [-2]}} | Group-Object -property IpAddress | {$ _。Count -ge $ int_block_limit} | -プロパティ名を選択 #現在の時刻を取得して、現在のFTPログのファイル名を把握します。 $ current_date_utc =(Get-Date).ToUniversalTime() #今日のFTPコントロールチャネルログファイルへのパスを設定する $ str_log_file_name_control_channel = "C:\ inetpub \ logs \ LogFiles \ FTPSVC \ u_ex" + $ current_date_utc.ToString( "yyMMdd")+ ".log" #今日のFTPコントロールチャネルログファイルで「530 1」を検索して、ログインに失敗したシステムのIPを含む行を見つけます。 #各行からIPのみを取得し、IPごとにIPをグループ化して、各行からの試行をカウントし、 #$ int_block_limit以上の不正なログインが今日あるIP $ arr_new_bad_ips_ftp_control_channel = @() $ arr_new_bad_ips_ftp_control_channel = Select-String $ str_log_file_name_control_channel -pattern "530 1" | ForEach-Object {$ _。Line.Substring(20,15)-replace "。*"、 ""} | グループ| {$ _。Count -ge $ int_block_limit} | -プロパティ名を選択 #今日のFTPログファイルへのパスを設定する $ str_log_file_name = "C:\ inetpub \ logs \ LogFiles \ FTPSVC * \ u_ex" + $ current_date_utc.ToString( "yyMMdd")+ ".log" #今日のFTPログファイルで「530 1」を検索して、ログインに失敗したシステムのIPを含む行を見つけます。 #各行からIPのみを取得し、IPごとにIPをグループ化して、各行からの試行をカウントし、 #$ int_block_limit以上の不正なログインが今日あるIP #FTPSVC *では、*の代わりにFTPサーバーのIDを追加するか、適切なログフォルダーを取得する必要があります。 $ arr_new_bad_ips_ftp = @() $ arr_new_bad_ips_ftp = Select-String $ str_log_file_name -pattern "530 1" | ForEach-Object {$ _。Line.Substring(20,15)-replace "。*"、 ""} | グループ| {$ _。Count -ge $ int_block_limit} | -プロパティ名を選択 #IPの2つの配列を連結します(1つはセキュリティログから、もう1つはFTPログから) $ arr_new_bad_ips_all = @() #$ arr_new_bad_ips_all = @($ arr_new_bad_ips_security_log)+ @($ arr_new_bad_ips_ftp_over_limit) $ arr_new_bad_ips_all = @($ arr_new_bad_ips_security_log)+ @($ arr_new_bad_ips_ftp_control_channel)+ @($ arr_new_bad_ips_ftp) #一意のIPのみを選択してアレイをソートします(1つのIPがセキュリティログとFTPログの両方に表示される場合) $ arr_new_bad_ips_all_sorted = @() $ arr_new_bad_ips_all_sorted = $ arr_new_bad_ips_all | Foreach-Object {[string] $ _。Name} | Select-Object-ユニーク #ファイアウォールオブジェクトを取得する $ firewall = New-Object -comobject hnetcfg.fwpolicy2 #「BlockAttackers *」に一致するすべてのファイアウォールルールを取得する $ arr_firewall_rules = $ firewall.Rules | ここで{$ _。Name -like 'BlockAttackers *'} #「BlockAttackers *」ファイアウォールルールがまだ存在しない場合は、作成して変数に設定します if($ arr_firewall_rules -eq $ null){ $ str_new_rule_name = "BlockAttackers(作成済み" + $ current_date_utc.ToString( "yyyy-MM-dd HH:mm:ss")+ "UTC)" netsh advfirewallファイアウォールルールの追加dir = in action = block name = $ str_new_rule_name description = "ルールは自動的に作成されました。" enable = yes remoteip = "0.0.0.0" | アウトヌル $ arr_firewall_rules = $ firewall.Rules | ここで{$ _。Name -like 'BlockAttackers *'} } #現在の「BlockAttackers *」ファイアウォールルールから既存のIPをアレイに分割し、簡単に検索できるようにします $ arr_existing_bad_ips = @() foreach($ arr_firewall_rulesの$ rule){ $ arr_existing_bad_ips + = $ rule.RemoteAddresses -split( '、') } #ファイアウォールルールによって現在ブロックされているIPからサブネットマスクを削除する $ arr_existing_bad_ips_without_masks = @() $ arr_existing_bad_ips_without_masks = $ arr_existing_bad_ips | ForEach-Object {$ _ -replace "/.*"、 ""} #サーバーのIP(IPv4およびIPv6)を115行目と116行目に入力します。 #ファイアウォールに追加するIPアドレスを選択しますが、... $ arr_new_bad_ips_for_firewall = @() $ arr_new_bad_ips_for_firewall = $ arr_new_bad_ips_all_sorted | どこ { #IPアドレスを含む(つまり、空白またはダッシュではない。FTPログインに失敗したシステムのセキュリティログにある) $ _。Length -gt 6-そして #ファイアウォールルールにまだ含まれていない !($ arr_existing_bad_ips_without_masks-$ _を含む)-そして #ローカルループバックではない !($ _。StartsWith( '127.0.0.1'))-そして #ローカルサブネットの一部ではない !($ _。StartsWith( '192.168。'))-そして !($ _。StartsWith( '0.0。'))-そして !($ _。StartsWith('10 .0。 '))-そして !($ _。StartsWith( '*。*。*。*'))-そして !($ _。StartsWith( '*:*:*:*:*:*')) } #ブロックするIPがある場合は、次を実行します... if($ arr_new_bad_ips_for_firewall -ne $ null){ #日付と時刻をスクリプト固有のログファイルに書き込む [DateTime] :: Now | Out-File -Append -Encoding utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt #新しくブロックされたIPアドレスをログファイルに書き込む $ arr_new_bad_ips_for_firewall | Out-File -Append -Encoding utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt #新しいIPが1つのルールにのみ追加されることを確認するブール値 $ bln_added_to_rule = 0 #各ルールから不良IPを一度に1つずつ保持するため、新しいIPを追加しても1000 IPを超えないように数えることができます $ arr_existing_bad_ips_current_rule = @() #ファイアウォールの「BlockAttackers *」ルールごとに、次の操作を行います foreach($ arr_firewall_rulesの$ rule){ if($ bln_added_to_rule -ne 1){ #既存のIPを現在のルールから配列に分割し、簡単にカウントできるようにします $ arr_existing_bad_ips_current_rule = $ rule.RemoteAddresses -split( '、') #追加するIPの数が1000から現在のルール内のIPの数を引いた数より少ない場合は、それらをこのルールに追加します if($ arr_new_bad_ips_for_firewall.Count -le(1000-$ arr_existing_bad_ips_current_rule.Count)){ #ファイアウォールルールに新しいIPを追加 $ arr_new_bad_ips_for_firewall | %{$ rule.RemoteAddresses + = '、' + $ _} #IPがログファイルに追加されたルールを記述する echo "上記の新しいIPアドレスがWindowsファイアウォールルールに追加されました:" $ rule.Name | Out-File -Append -Encoding utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt #ブール値を設定して、IPの追加時に他のルールがスキップされるようにします $ bln_added_to_rule = 1 } } } #他の「BlockAttackers *」ファイアウォールルールに空きがない場合は、新しいルールを作成し、IPを追加します if($ bln_added_to_rule -ne 1){ $ str_new_rule_name = "BlockAttackers(作成済み" + $ current_date_utc.ToString( "yyyy-MM-dd HH:mm:ss")+ "UTC)" netsh advfirewallファイアウォールルールの追加dir = in action = block name = $ str_new_rule_name description = "ルールは自動的に作成されました。" enable = yes remoteip = "0.0.0.0" | アウトヌル $ new_rule = $ firewall.rules | ここで{$ _。Name -eq $ str_new_rule_name} #ファイアウォールルールに新しいIPを追加する $ arr_new_bad_ips_for_firewall | %{$ new_rule.RemoteAddresses + = '、' + $ _} #IPがログファイルに追加されたルールを記述する echo "新しく作成されたWindowsファイアウォールルールに追加された上記の新しいIPアドレス:" $ new_rule.Name | Out-File -Append -Encoding utf8 C:\ inetpub \ logs \ LogFiles \ blockattackers.txt } }
FTPSVC*
54行目のFTPのログフォルダーの名前は、完全なものでなければなりません。115行目と116行目には、サーバーのIP(IPv4およびIPv6)を入力する必要があります。入力しない場合、サーバーのIPがファイアウォールルールに100回追加される可能性があります。$int_block_limit
サーバーで変数を1に設定しているため、スクリプトは2秒以内に4625イベントを引き起こすハッカー攻撃をブロックしています。数分の間に4625イベントが発生するのに加えて、スクリプトをさらに実行することを考えています。原因として、スクリプトを分離し、1つのスクリプトで4625イベントによってトリガーされた4625イベントをチェックし、別の1つのスクリプトでFTPのログフォルダーが5分または10分ごとに定期的にチェックするようにすることも可能です。およびログファイル。
私はSQL用に私のものを追加しました
# Select from the Application log (SQL) all IP addresss that have more than $int_block_limit logon failure within $dat_time_window
$arr_new_bad_ips_SQL_log = @()
$arr_new_bad_ips_SQL_log = Get-EventLog -LogName 'Application' -After $dat_time_window |
Where-Object{$_.EventID -eq 18456} |
Select-Object @{n='CLIENT';e={$_.ReplacementStrings[-1]}} |
Group-Object -property CLIENT |
Where {$_.Count -ge $int_block_limit} |
Select -property Name |
{
$_.Name = $_.Name.Replace(" [CLIENT: ", "");
$_.Name = $_.Name.Replace("]", "");
return $_;
}
次に、配列をips_allに追加する必要があります
$arr_new_bad_ips_all = @($arr_new_bad_ips_SQL_log) + @($arr_new_bad_ips_security_log) + @($arr_new_bad_ips_ftp_control_channel) + @($arr_new_bad_ips_ftp)