Have You Been Pwned by CVE-2014-6324/MS14-068?

In case you haven't heard, there is a critical [Windows implementation of] Kerberos bug that you need to be updating, right now.

More information on the vulnerability can be found here.

In the "Detection Guidance" section of the above blog post, you will see that you can detect if the vulnerability has been exploited on an unpatched machine by analyzing the Security event logs. Specifically, looking at Event ID 4624 logon events, and taking note that the "Security ID" and "Account Name" fields in that event description match.  If they don't, chances are high that you have been a victim of a privilege escalation attack.

I whipped up a detection script to check all the domain controllers:

#Requires -Module ActiveDirectory
Set-StrictMode -Version Latest
Get-Job | Remove-Job -Force
[String]$DomainName = $(Get-ADDomain).Name
$DCs = $(Get-ADDomain).ReplicaDirectoryServers

:NextDC Foreach ($DC In $DCs)
{
    Start-Job -ScriptBlock {
        Param($DC)
        [Int]$PotentialMS14068s = 0
        Write-Output "Fetching Security event log from $DC."
        Try
        {
            $Events = Get-EventLog -LogName Security -InstanceId 4624 -ComputerName $DC -ErrorAction Stop
        }
        Catch
        {
            Write-Error "An error occurred while reading event log from $DC.`r`n$($_.Exception.Message)"
        }

        :NextEvent Foreach ($Event In $Events)
        {            
            $MessageLines  = $Event.Message -Split [Environment]::NewLine
            
            [String]$SecurityID    = [String]::Empty
            [String]$AccountName   = [String]::Empty
            [String]$AccountDomain = [String]::Empty

            # Server 2012 Format
            If ($MessageLines[13].Trim() -Like 'Security ID:*')
            {
                $SecurityID    = ($MessageLines[13].Trim() -Split ':')[1].Trim()
                $AccountName   = ($MessageLines[14].Trim() -Split ':')[1].Trim()
                $AccountDomain = ($MessageLines[15].Trim() -Split ':')[1].Trim() 
            }
            
            # Server 2008 R2 Format
            If ($MessageLines[11].Trim() -Like 'Security ID:*')
            {
                $SecurityID    = ($MessageLines[11].Trim() -Split ':')[1].Trim()
                $AccountName   = ($MessageLines[12].Trim() -Split ':')[1].Trim()
                $AccountDomain = ($MessageLines[13].Trim() -Split ':')[1].Trim()
            }

            If (($SecurityID -EQ [String]::Empty) -OR ($AccountName -EQ [String]::Empty) -OR ($AccountDomain -EQ [String]::Empty))
            {
                Write-Error "Event log message format unrecognized on $DC!"
                $Event | Format-List
                Break NextEvent
            }

            If ($AccountDomain -Like $DomainName -And $SecurityID -NotLike 'S-1-5-18')
            {
                $SID = New-Object System.Security.Principal.SecurityIdentifier($SecurityID)
                $Username = $SID.Translate([System.Security.Principal.NTAccount])        
                If ($Username -Like '*\*')
                {
                    $Username = ($Username -Split '\\')[-1]
                }
                If ($Username -Like '*@*')
                {
                    $Username = ($Username -Split '@')[0]
                }
                If ($Username -NE $AccountName)
                {
                    $Event | Format-List
                    $PotentialMS14068s++
                }        
            }
        }
        Write-Output "Finished with $DC. $PotentialMS14068s interesting events found."
    } -ArgumentList $DC
}

While ($(Get-Job -State Running).Count -GT 0)
{
    Get-Job -State Completed | Receive-Job   
    Start-Sleep -Seconds 10 
}

The script uses Powershell jobs to achieve some parallelism, because if you have more than one or two domain controllers in your environment, this quickly becomes a Herculean, time-consuming task.  The script will display potential security event log events that may indicate exploits currently being used in your environment.

Comments (4) -

Instead of Get-EventLog using Get-WinEvent would be faster to get results from remote DCs.
Get-WinEvent -FilterHashtable @{logname='security'; id=4624}, and use MaxEvents or add StartTime="mm/dd/yy";EndTime="mm/dd/yy" to filter on date.

Hi Raghu,

Thanks for stopping by.

I found this to be untrue for me.  Using Get-EventLog against a remote system took 12 minutes, while Get-WinEvent took much longer than 12 minutes... so long in fact that I ran out of patience and didn't let it finish.

For Windows 2008 R2 DCs, change the line numbers 13-15 to 11-13 in the code for $MessageLines to get SecurityID etc.. on Win2012 13-15 works fine.

Thanks for this, you are correct!  I will be enhancing this script and updating the post shortly.

Comments are closed