Início > Active Directory Modules for Windows Powershell, Windows PowerShell > PoSh – Como determinar a origem de um account lockedout?

PoSh – Como determinar a origem de um account lockedout?

julho 2, 2015

Olá pessoALL,

Este é mais um post sobre algo que faz parte do nosso dia a dia, mas que quase sempre eu vejo tomar um tempo considerável para se chegar ao resultado esperado, o bloqueio de contas ou Account Locked Out.

Com a popularização de gadget, smartphones, tablets e todo e qualquer dispositivo móvel que permita acesso a e-mails, comunicação unificada, etc. e até mesmo pelo próprio descuido do usuário em digitar a senha incorretamente, este tipo de situação se tornou ainda mais comum do que era antigamente.

Como eu presumo que é de conhecimento da maioria, o evento registrado no momento do bloqueio da conta é o 4740 populado em Security, mas o que eu normalmente vejo no momento de determinar a origem do bloqueio é um completo desconhecimento de como isso funciona para otimizar o tempo empregado para chegar a este resultado.

É possível automatizar este tipo de processo usando scripts PowerShell de preferência, mas é preciso saber como otimizar o tempo de resposta entendendo onde devemos procurar esta informação primeiramente. A primeira coisa que precisamos ter em mente neste tipo de situação é como o processo de falha de logon funciona.

How Domain Controllers Verify Passwords

To illustrate the authentication process, the following diagram describes the steps that occur when a logon attempt does not work.

Figure 1: Process for a Failed Logon Attempt

 

  1. The client computer presents the user logon information to a domain controller. This includes the users account name and a cryptographic hash of their password. This information can be sent to any domain controller and is typically sent to the domain controller that is identified as the closest domain controller to the client computer.
  2. When a domain controller detects that an authentication attempt did not work and a condition of STATUS_WRONG_PASSWORD, STATUS_PASSWORD_EXPIRED, STATUS_PASSWORD_MUST_CHANGE, or STATUS_ACCOUNT_LOCKED_OUT is returned, the domain controller forwards the authentication attempt to the primary domain controller (PDC) emulator operations master. Essentially, the domain controller queries the PDC to authoritatively determine if the password is current. The domain controller queries the PDC for this information because the domain controller may not have the most current password for the user but, by design, the PDC emulator operations master always has the most current password.
  3. The authentication request is retried by the PDC emulator operations master to verify that the password is correct. If the PDC emulator operations master rejects the bad password, the PDC emulator operations master increments the badPwdCount attribute for that user object. The PDC is the authority on the user’s password validity.
  4. The failed logon result information is sent by the PDC emulator operations master to the authenticating domain controller.
  5. The authenticating domain controller also increments its copy of the badPwdCount attribute for the user object.
  6. The authenticating domain controller then sends a response to the client computer that notifies the domain controller that the logon attempt did not work.
  7. As long as that user, program, or service continues to send incorrect credentials to the authenticating domain controller, logon attempts that failed because of an incorrect password continue to be forwarded to the PDC until the threshold value for incorrect logon attempts is reached (if you set it in a policy). When this occurs, the account is locked out.

Sabendo agora como o processo funciona, o que nós podemos fazer para melhorar o processo para determinar o bloqueio de um conta?

Após a conta do usuário ser bloqueada, além do evento 4740 gerado no Domain Controller mais próximo do usuário, o mesmo evento será gerado no Domain Controller com a função de PDC Emulator devido ao encaminhamento que o DC utilizado para autenticar o usuário fez com o objetivo de conferir a senha informada e validar sua informação atual.

Tendo em mente esta informação, podemos concluir que há um local centralizado de onde podemos obter a informação sobre o bloqueio de uma conta de usuário. Agora imagine uma infraestrutura com vários Domain Controllers. Como seria feito o processo para determinar a origem do bloqueio?

Infelizmente, eu já me deparei e ainda me deparo com profissionais fazendo uma pesquisa por todos os Domain Controllers em suas infraestruturas por eventos 4740. Este processo além de levar um tempo muito maior, mostra o desconhecimento da informação anterior sobre o PDC Emulator.

Utilizando PowerShell (PoSh), os módulos do Active Directory e algumas linhas de código é possível otimizar este processo fazendo uma pesquisa inicialmente no Domain Controller que suporta a FSMO de PDC Emulator para determinar a origem do bloqueio da conta. Mas como seria este código? Simples!

Write-Host
Import-Module ActiveDirectory
$PDCEmulator   = Get-ADDomain | %{$_.PDCEmulator}
$UserAccount  = Read-Host “Type the user SAM account name to find out the locked out location”
$UserAccount  = $UserAccount.ToLower()
If (!(Get-ADObject -Filter “SAMAccountName -eq ‘$UserAccount'”)){
Write-Host
Write-Warning “You typed an invalid SAM Account Name! Try again…”
Write-Host
}
Else{
Write-Host
Write-Host “Searching for events on PDC Emulator $PDCEmulator related to $UserAccount locked out.”
Get-WinEvent -ComputerName $PDCEmulator -LogName Security -FilterXPath “*[System/EventID=4740 and (EventData/Data[@Name=’TargetUserName’] =’$UserAccount’)]” | Select -Property @{Name = ‘UserName’;Expression = {$_.Properties[0].Value}},@{Name = ‘PDCEmulator’;Expression = {$_.MachineName}},@{Name = ‘EventId’;Expression = {$_.Id}},@{Name = ‘TimeStamp’; Expression = {$_.TimeCreated}},@{Name = ‘Locked Out Location’;Expression = {$_.Properties[1].Value}} | Ft -AutoSize
}

Como podemos ver acima, com poucas linhas de código é possível determinar quem é o DC com a FSMO de PDC Emulator, procurar o evento relacionado a uma conta específica sobre ele e retornar de uma forma muito amigável as informações que precisamos para determinar a origem do bloqueio.

AccountLockedOut_0001

Na imagem anterior nós podemos visualizar o resultado após a execução do script para um usuário chamado Alvin Holder. Pretty Cool, huh?

Agora, vamos so pontos negativos e ou de atenção e que podem interferir neste tipo de abordagem para determinar a origem do bloqueio de uma conta de usuário de forma correta.

  • para que o script funcione corretamente, o PDC Emulator precisa estar Online, caso contrário, ele irá falhar.
  • infelizmente, o log de segurança do PDC Emulator é altamente rotatívo dependendo do tamanho da infraestrutura, então, se a solicitação para determinar a origem do bloqueio for feita tardiamente, pode não ser possível determinar a origem usando este método.
  • o evento 4740 só está disponível no Windows Server 2008 e posteriores. Em versões anteriores o evento gerado tem outro ID, o 644.
  • infelizmente, o uso do CmdLet Get-WinEvent só é possível a partir do Windows Server 2008. No Windows Server 2003 não é possível usá-lo.
  • Para o correto funcionamento do CmdLet Get-WinEvent, o serviço Active Directory Web Services precisa estar em execução do Domain Controller onde ele irá executar a pesquisa no Event Viewer.
  • Você precisa das ferramentas administrativas (RSAT) e os módulos do PowerShell para o Active Directory instalados no host onde irá executar o script, pois ele depende deste item.

Mas eu não entendi toda a lógica do script… Então vamos lá! Quebrando em partes menores o nosso pequeno script nós temos:

Import-Module ActiveDirectory

Este comando garante que se você não estiver executando o script dentro de uma janela do Windows PowerShell Modules for Active Directory que o mesmo seja carregado.

$PDCEmulator   = Get-ADDomain | %{$_.PDCEmulator}

O comando Get-ADDomain permite extrair várias informações sobre o domínio atual ou qualquer outro onde você tenha credenciais para se conectar a ele e uma destas informações é o nome do DC cujo a FSMO de PDC Emulator está. %{$_.PDCEmulator} significa que desejamos retornar apenas o valor do campo PDCEmulator como resultado e armazená-lo na variável $PDCEmulator.

$UserAccount  = Read-Host “Type the user SAM account name to find out the locked out location”

Este comando irá questioná-lo sobre o nome do usuário, neste caso SAMAccountName, que é preciso procurar nos eventos 4740 do PDC Emulator e armazena esta informação em uma variável $UserAccount.

$UserAccount  = $UserAccount.ToLower()

Utiliza o método .ToLower() da variável $UserAccount para converter a string armazenada completamente para letras minúsculas caso tenha sido informada em maiúsculas ou variando entre ambos os formatos.

If (!(Get-ADObject -Filter “SAMAccountName -eq ‘$UserAccount'”)){
Write-Host
Write-Warning “You typed an invalid SAM account name! Try again…”
Write-Host
}

É feita a validação de uma condião para garantir que o SAMAccountName informado anteriormente é válido e existe no domínio.

A expressão (!(Get-ADObject -Filter “SAMAccountName -eq ‘$UserAccount'”)) significa que se o comando (Get-ADObject -Filter “SAMAccountName -eq ‘$UserAccount'”) retornar um valor falso orientado pelo sinal de exclamação (!(Expression)), você será informado que digitou um SAMAccountName inválido. Caso sejá verdadeiro, passamos para o segundo passo da condição.

Else{
Write-Host
Write-Host “Searching for events on PDC Emulator $PDCEmulator related to $UserAccount locked out.”
Get-WinEvent -ComputerName $PDCEmulator -LogName Security -FilterXPath “*[System/EventID=4740 and (EventData/Data[@Name=’TargetUserName’] =’$UserAccount’)]” | Select -Property @{Name = ‘UserName’;Expression = {$_.Properties[0].Value}},@{Name = ‘PDCEmulator’;Expression = {$_.MachineName}},@{Name = ‘EventId’;Expression = {$_.Id}},@{Name = ‘TimeStamp’; Expression = {$_.TimeCreated}},@{Name = ‘Locked Out Location’;Expression = {$_.Properties[1].Value}} | Ft -AutoSize
}

É aqui onde ocorre a magia! O CmdLet Get-WinEvent é pouco explorado na minha opinião, pois é mais comum encontrarmos o uso do CmdLet Get-EventLog. No entanto, o CmdLet Get-WinEvent tem alguns caracteristicas que o seu irmão mais próximo não tem. Uma delas é a possíbilidade de criarmos filtros para metadados XML.

Uma boa e prática leitura sobre Event Viewer e XML Metadata é esta: Advanced XML filtering in the Windows Event Viewer

Não vou me aprofundar no assunto sobre queries XML, pois este assunto é extremamente extenso e não é o objetivo deste post. O que é preciso ter em mente neste momento é que todo evento a partir do Windows Server 2008 e Windows Vista é baseado em uma estrutura XML.

AccountLockedOut_0002

Acima temos uma imagem de um evento e do que podemos encontrar na guia Details selecionando a opção XML View e com o conhecimento correto sobre Queries XML com a expressão -FilterXPath “*[System/EventID=4740 and (EventData/Data[@Name=’TargetUserName’] =’$UserAccount’)]” é possível extrair as informações que precisamos dos campos corretos.

AccountLockedOut_0003

Após localizarmos vamos usar expressões formatadas Select -Property @{Name = ‘Name’;Expression={Expression}} para mostrarmos as informações como desejamos na saída do comando. Aqui está outro ponto importante do uso do CmdLet Get-WinEvent.

Os campos onde as informações da conta de usuário, host de origem do bloqueio, etc. estão dentro do campo Message do evento. Utilizando CmdLet Get-EventLog é possível localizar estas informações com o parametro -Message, mas não é possível extrair estas informações de forma prática para montarmos uma saída amigável.

É aqui que o uso do CmdLet Get-WinEvent se mostra mais poderoso, pois com o seu uso é possível visualizar as propriedades do evento e os campos que precisamos para montarmos a visualização amigavel como saída do comando. Como podemos fazer isso? Tomando como referencia o evento 4740, vamos dar uma olhada na janela do mesmo.

AccountLockedOut_0004

Como podemos ver na imagem acima, os campos necessários para montarmos nossa saída amigável está distribuídos dentro do campo message do evento, então, como podemos descobrir suas posições? Para fazer isto, primeiramente nós precisamos visualizar as propriedades deste evento usando o seguinte comando:

(Get-WinEvent -ComputerName BRSPOADCO-P0001 -LogName Security -FilterXPath “*[System/EventID=4740 and (EventData/Data[@Name=’T
argetUserName’] =’alvin.holder’)]”).Properties

A saída deste comando será:

AccountLockedOut_0005

Como podemos ver as informações disponíveis na janela gráfica agora estão disponíveis através do PowerShell. O que não fica muito claro neste comando é como estas informações estão disponíveis. O acesso a este tipo de propriedade precisa ser feito como em um array de dados – array[0], array[1],…,array[n].

A posição no array de cada informação disponível também é algo que não fica muito clara na saída do comando, mas felizmente é simples de calcular. Para a saída acima você precisa usar a simples regra de:

Value
—–
alvin.holder [0]
USNYCBFC0-PN001 [1]
S-1-5-21-3546721565-2705311972-509830587-9535 [2]
S-1-5-18 [3]
BRSPOADCO-P0001$ [4]
NSFW [5]
999 [6]

Da parte superior para a inferior nós iremos imaginar as posições a partir de zero representadas em vermelho anteriormente, pois todo array de dados tem como primeira posição o número zero como referência. Tendo feito isso, nós seremos capazes de extrair estes dados usando o PowerShell usando expressões como $_.Properties[0].Value,…,$_.Properties[n].Value para representarmos o que precisamos.

Espero que este tipo de situação tenha ficado muito mais clara e que o uso de PoSh para este tipo de situação ajude no dia a dia e em outras tarefas.

Até o próximo post…

Referências:

Account Lockout and Password Concepts

Download:

CheckAccountLockedOut.ps1

PS: Renomear o arquivo de CheckAccountLockedOut-ps1.key para CheckAccountLockedOut.ps1.

%d blogueiros gostam disto: