O script do remuda , editado por kevinmicke (7 de fevereiro às 21:59), não verificou o canal de controle do FTP, que possui uma pasta própria no meu sistema (Windows Server 2008 R2). Os 530 11001
eventos também não foram reconhecidos, o que parece aparecer quando o hacker tenta apenas acessar o canal de controle. Então, acrescentei algumas linhas no script para verificar uma segunda pasta de log de FTP:
# Esse script do Windows Powershell bloqueará automaticamente os endereços IP que tentam fazer login no sistema
# e falha o número de vezes definido abaixo com a variável $ int_block_limit ou mais. É varre tanto a Segurança
# log, que abrange a Área de trabalho remota e outras tentativas, bem como o log FTP do dia atual. Se o $ int_block_limit
# limit for atingido em um desses logs (separadamente, não combinados), o endereço IP será adicionado ao
# regra de firewall.
#
# O script criará automaticamente uma regra de firewall chamada "BlockAttackers (criado aaaa-MM-dd HH: mm: ss UTC)" usando
# a hora atual se um com um nome que inclui "BlockAttackers" ainda não existe. Porque há uma difícil
# limite de 1000 entradas (endereços IP) que você pode bloquear por regra, ele também criará regras com nomes semelhantes assim que
# limite é atingido para o mais recente.
#
# Eu recomendo definir o script para ser executado como uma tarefa agendada acionada por falhas de auditoria de logon do evento 4625 do diretório
# Log de segurança ou, alternativamente, você pode configurá-lo para executar após um certo período de tempo (ou seja, a cada 10 minutos).
#
# Autores:
# Maioria do script escrito pelo usuário serverfault.com kevinmicke
# Parte do Log de Segurança do Windows escrita pelo usuário do serverfault.com remunda, que forneceu o ponto de partida para o kevinmicke
# Verificação do canal de controle do FTP adicionado pelo usuário serverfault.com Uwe Martens
#
# Detalhes: https://serverfault.com/questions/233222/ban-ip-address-based-on-x-number-of-unsuccessful-login-attempts
# Defina o número de tentativas falhas de login, após as quais um endereço IP será bloqueado
$ int_block_limit = 3
# Janela de tempo durante a qual verificar o log de segurança, atualmente definido para verificar apenas as últimas 24 horas
$ dat_time_window = [DateTime] :: Now.AddDays (-1)
# Selecione no log de segurança todos os endereços IP com mais de $ int_block_limit falhas de auditoria (evento 4625) em $ dat_time_window
$ arr_new_bad_ips_security_log = @ ()
$ arr_new_bad_ips_security_log = Get-EventLog -LogName 'Security' -InstanceId 4625 -Depois de $ dat_time_window |
Objeto Select @ {n = 'IpAddress'; e = {$ _. ReplacementStrings [-2]}} |
IpAddress de propriedade de objeto de grupo |
Onde {$ _. Count -ge $ int_block_limit} |
Selecione o nome da propriedade
# Obter o horário atual do UTC para descobrir o nome do arquivo do log FTP atual
$ current_date_utc = (Get-Date) .ToUniversalTime ()
# Defina o caminho para o arquivo de log do canal de controle FTP de hoje
$ str_log_file_name_control_channel = "C: \ inetpub \ logs \ LogFiles \ FTPSVC \ u_ex" + $ current_date_utc.ToString ("yyMMdd") + ".log"
# Pesquise o arquivo de log do canal de controle FTP de hoje por "530 1" para encontrar linhas que contêm IPs de sistemas que não logaram,
# obtenha apenas o IP de cada linha, agrupe os IPs por IP para contar as tentativas de cada uma e selecione apenas o
# IPs que possuem $ int_block_limit ou mais logins inválidos hoje
$ arr_new_bad_ips_ftp_control_channel = @ ()
$ arr_new_bad_ips_ftp_control_channel = Cadeia de seleção $ str_log_file_name_control_channel - padrão "530 1" |
ForEach-Object {$ _. Line.Substring (20,15) - substitua ". *", ""} |
Grupo |
Onde {$ _. Count -ge $ int_block_limit} |
Selecione o nome da propriedade
# Definir caminho para o arquivo de log FTP de hoje
$ str_log_file_name = "C: \ inetpub \ logs \ LogFiles \ FTPSVC * \ u_ex" + $ current_date_utc.ToString ("yyMMdd") + ".log"
# Pesquise o arquivo de log FTP de hoje por "530 1" para encontrar linhas que contêm IPs de sistemas que não logaram,
# obtenha apenas o IP de cada linha, agrupe os IPs por IP para contar as tentativas de cada uma e selecione apenas o
# IPs que possuem $ int_block_limit ou mais logins inválidos hoje
# No FTPSVC * deve ser adicionado o ID do servidor FTP em vez de *, ou apenas pegue a pasta de log correta
$ arr_new_bad_ips_ftp = @ ()
$ arr_new_bad_ips_ftp = Selecionar cadeia de caracteres $ str_log_file_name - padrão "530 1" |
ForEach-Object {$ _. Line.Substring (20,15) - substitua ". *", ""} |
Grupo |
Onde {$ _. Count -ge $ int_block_limit} |
Selecione o nome da propriedade
# Concatene as duas matrizes de IPs (uma do log de segurança e outra do log de 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)
# Classifique a matriz, selecionando apenas IPs exclusivos (caso um IP apareça nos logs de segurança e FTP)
$ arr_new_bad_ips_all_sorted = @ ()
$ arr_new_bad_ips_all_sorted = $ arr_new_bad_ips_all |
Objeto Foreach {[string] $ _. Nome} |
Select-Object -unique
# Obter objeto de firewall
$ firewall = New-Object -comobject hnetcfg.fwpolicy2
# Obtenha todas as regras de firewall correspondentes a "BlockAttackers *"
$ arr_firewall_rules = $ firewall.Rules | Onde {$ _. Name-like 'BlockAttackers *'}
# Se ainda não existir uma regra de firewall "BlockAttackers *", crie uma e defina-a como uma variável
if ($ arr_firewall_rules -eq $ null) {
$ str_new_rule_name = "BlockAttackers (criado" + $ current_date_utc.ToString ("aaaa-MM-dd HH: mm: ss") + "UTC)"
netsh advfirewall firewall adicionar regra dir = em ação = nome do bloco = $ str_new_rule_name description = "Regra criada automaticamente." enable = yes remoteip = "0.0.0.0" | Out-Null
$ arr_firewall_rules = $ firewall.Rules | Onde {$ _. Name-like 'BlockAttackers *'}
}
# Divida os IPs existentes das atuais regras de firewall "BlockAttackers *" em um array para que possamos pesquisá-los facilmente
$ arr_existing_bad_ips = @ ()
foreach (regra de $ em $ arr_firewall_rules) {
$ arr_existing_bad_ips + = $ rule.RemoteAddresses -split (',')
}
# Limpe as máscaras de sub-rede dos IPs atualmente bloqueados pelas regras de firewall
$ arr_existing_bad_ips_without_masks = @ ()
$ arr_existing_bad_ips_without_masks = $ arr_existing_bad_ips | ForEach-Object {$ _ -replace "/.*", ""}
# Digite o IP do seu servidor (IPv4 e IPv6) nas linhas 115 e 116.
# Selecione os endereços IP a serem adicionados ao firewall, mas apenas os que ...
$ arr_new_bad_ips_for_firewall = @ ()
$ arr_new_bad_ips_for_firewall = $ arr_new_bad_ips_all_sorted | Onde {
# contém um endereço IP (ou seja, não está em branco ou é um traço, que o log de segurança possui para sistemas com falha no logon FTP)
$ _. Length -gt 6 - e
# ainda não estão nas regras do firewall
! ($ arr_existing_bad_ips_without_masks -contains $ _) -e
# não são o loopback local
! ($ _. Inicia com ('127.0.0.1')) - e
# não fazem parte da sub-rede local
! ($ _. Inicia com ('192.168.')) - e
! ($ _. Inicia com ('0.0.')) - e
! ($ _. Inicia com ('10 .0. ')) - e
! ($ _. Inicia com ('*. *. *. *')) - e
! ($ _. StartsWith ('*: *: *: *: *: *'))
}
# Se houver IPs para bloquear, faça o seguinte ...
if ($ arr_new_bad_ips_for_firewall -ne $ null) {
# Grava data e hora no arquivo de log específico do script
[DateTime] :: Agora | Arquivo de saída - Anexar - Codificação utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
# Grava endereços IP recém-bloqueados no arquivo de log
$ arr_new_bad_ips_for_firewall | Arquivo de saída - Anexo - Codificação utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
# Booleano para garantir que os novos IPs sejam adicionados apenas a uma regra
$ bln_added_to_rule = 0
# Matriz para manter IPs inválidos de cada regra, um de cada vez, para que possamos contar para garantir que a adição de novos não exceda 1000 IPs
$ arr_existing_bad_ips_current_rule = @ ()
# Para cada regra "BlockAttackers *" no firewall, faça o seguinte ...
foreach (regra de $ em $ arr_firewall_rules) {
if ($ bln_added_to_rule -ne 1) {
# Divida os IPs existentes da regra atual em uma matriz para que possamos contá-los facilmente
$ arr_existing_bad_ips_current_rule = $ rule.RemoteAddresses -split (',')
# Se o número de IPs a serem adicionados for menor que 1000 menos o número atual de IPs na regra, adicione-os a esta regra
if ($ arr_new_bad_ips_for_firewall.Count -le (1000 - $ arr_existing_bad_ips_current_rule.Count)) {
# Adicione novos IPs à regra do firewall
$ arr_new_bad_ips_for_firewall | % {$ rule.RemoteAddresses + = ',' + $ _}
# Escreva a qual regra os IPs foram adicionados ao arquivo de log
echo "Novos endereços IP acima adicionados à regra do Firewall do Windows:" $ rule.Name | Arquivo de saída - Anexar - Codificação utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
# Defina booleano para que outras regras sejam ignoradas ao adicionar IPs
$ bln_added_to_rule = 1
}
}
}
# Se não houver espaço em nenhuma outra regra de firewall "BlockAttackers *", crie uma nova e adicione os IPs a ela
if ($ bln_added_to_rule -ne 1) {
$ str_new_rule_name = "BlockAttackers (criado" + $ current_date_utc.ToString ("aaaa-MM-dd HH: mm: ss") + "UTC)"
netsh advfirewall firewall adicionar regra dir = em ação = nome do bloco = $ str_new_rule_name description = "Regra criada automaticamente." enable = yes remoteip = "0.0.0.0" | Out-Null
$ new_rule = $ firewall.rules | Onde {$ _. Name -eq $ str_new_rule_name}
# Adicione novos IPs à regra do firewall
$ arr_new_bad_ips_for_firewall | % {$ new_rule.RemoteAddresses + = ',' + $ _}
# Escreva a qual regra os IPs foram adicionados ao arquivo de log
echo "Novos endereços IP acima adicionados à regra do Firewall do Windows recém-criada:" $ new_rule.Name | Arquivo de saída - Anexar - Codificação utf8 C: \ inetpub \ logs \ LogFiles \ blockattackers.txt
}
}
O nome da pasta de log do FTP FTPSVC*
na linha 54 deve ser preenchido por causa. Nas linhas 115 e 116, é necessário inserir o IP do servidor (IPv4 e IPv6), caso contrário, o próprio IP do servidor poderá ser adicionado à regra do firewall centenas de vezes. A variável $int_block_limit
que estou definindo como 1 no meu servidor, portanto, o script está bloqueando um ataque de hackers, causando um evento 4625 em dois segundos. Ainda estou pensando em executar o script adicionalmente para ocorrer 4625 eventos em um período de alguns minutos. Por uma causa, também seria possível separar os scripts e deixar um script verificar os eventos 4625 disparados pelo evento 4625 e outro as pastas de log do FTP verificando periodicamente a cada 5 ou 10 minutos, mesmo com regras de firewall separadas e arquivo de log.