Active Directory

bundle

#1

##Bundle details and download
https://www.extrahop.com/customers/community/bundles/extrahop/active-directory/

##Description
Builds real-time metrics for the following AD Services: User Accounts, Computer Accounts, DNS, LDAP, Global Catalog, and Group Policy loads.


#2

Version 2.1 updated on 5/30/016 added LDAP in the dashboard.

If you have an existing AD Bundle, simply upload the new bundle, but before hitting “apply” change to overwrite rather than skip existing objects.

NOTE: if you have modified the previous bundle, such as dashboard, custom page, trigger, etc, overwriting will undo your changes.


#3

Hey Apax,
I cannot find 2.1 on the bundle list. last one was updated in april.


#4

All, can I use EH AD bundle to know WHY an AD account was locked? Can I also UNLOCK the account via EH?


#5

Hi smsam!

We won’t be able to see the reason or what application is sending out the bad passwords. When an authentication attempt is made, your domain controller will send a PREAUTH_FAILED error when a bad password was sent.

After seeing X amount of bad passwords, your domain controller will send a PREAUTH_REVOKED showing the account was disabled (i.e. locked). That is how we count them.

The EH itself cannot unlock accounts, but if you have an AD automation system that can execute workflows, then the EH can send the data to it via REST, and execute a workflow.


#6

I’m not seeing “adrecord” types in the EXA from the commitRecord(“adrecord”,record) statement in the trigger. EXA record support appears to be controlled with the hasEXA variable which is set to false in the trigger, and I don’t seem to be able to edit the trigger to set the variable to true. What am I missing?

Later …
I’ll answer my own question … we have an ECA and two EDAs. I installed the bundle in the ECA twice, once for each EDA. My problem editing the “hasEXA” is that I was in one of the EDAs. Editing works fine via the ECA.

As an aside, you might want to include an instruction to set “hasEXA” to true. It appears that we should disable record commits for Kerberos Response. I’m letting them both run for now to see the effect.

Later…
Browsing records from the ECA, as expected, I received “Kerberos Response” and “Kerberos Response AD” records which were essentially duplicates, so I removed Kerberos Response from another trigger I had running in the associated EDA.
However, browsing records from the EDA, I am seeing records like this …
“Time: 2016-10-06 11:46:59.123, Record Type: adrecord”.

Again…
Ok, I just copied the “Kerberos Response AD” record format from the ECA to the EDA, so now browsing records from the EDA works.

The installation instructions might need some work for ECA installs.

Again, NICE DASHBOARD!


#7

If you have the Extrahop Active Directory Module installed. You may have noticed that the priv_names list is just a generic list of accounts to look for in the Ldap and Kerberos wire data. Instead of manually keeping this list current i created a PowerShell script that you can use to update this list from your list of privileged accounts in Active Directory. Domain Admins, Account Operators etc.

Protected Accounts and Groups in Active Directory


#Requires -Modules ActiveDirectory

#   Backup your current triggers before running this one!

#   Update-ADScriptTrigger
#   By: SmuRf3R5

<#
    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 
    files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 
    modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software 
    is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
    LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 
    IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#>

<#
    This script will update the Active Direcotry module trigger provided by Extrahop. First it will attempt to locate the trigger by
    $TriggerName = "Active Directory" 

    The priv_names list will be updated with a current list of 
        
        Domain Admins, 
        Enterprise Admins, 
        Account Operators, 
        Backup Administrors, 
        Schema Admins 
        or any other SAMAccountName that still has the 'AdminCount' attribute set to 1
    
    Source:
    https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory
#>

<#  
    API Information can be found here:
    Settings | Administrative | API Access | Extrahop API Explorer link

    Put your API key in the upper right box API_Key
    then find the Trigger category /triggers
    https://YOUR_APPLIANCE_URL/api/v1/explore/#!/Trigger/getAll
#>

# Change to SilentlyContinue to disable verbose logging
#$VerbosePreference = " Continue" 

# Found here https://YOUR_APPLIANCE_URL/admin/api/
$APIKey = "YOUR_API_HERE" 
$ExtraHopURI = "https://YOUR_APPLIANCE_URL/api/v1/triggers"
$TriggerName = 'Active Directory'

# By Default powershell uses 1.0
# The extrahop site appears to require tls 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

# Format a header for the extrahop rest request
$Headers = @{
                Accept = 'application/json'
                Authorization = 'ExtraHop apikey=' + $APIKey
            }
try 
{
    # Find Active Directory Trigger
    Write-Verbose "Searching for TriggerMame: $TriggerName"
    
    $trigger = Invoke-RestMethod -UseBasicParsing -uri $ExtraHopURI -Method Get -Headers $Headers -Body $Body -ErrorAction Stop
    $TriggerID  = ($trigger | Where-Object{$_.name -eq $TriggerName}).id
    
    Write-Verbose "Trigger ID: $TriggerID"

    try
    {
        # Get the script
        Write-Verbose "Attempting to get current script from extrahop appliance..."
        $Existing_Script = Invoke-RestMethod -UseBasicParsing -uri ($ExtraHopURI + "/" + $TriggerID) -Method Get -Headers $Headers -Body $Body -ErrorAction Stop

        # Backup Existing Script
        $Existing_Script.script | Out-File "$PSScriptRoot\ADScriptTrigger.js"

        # Preserve default values that were is original script
        $ExtraHopDefaultValues = ("const priv_names = [
            'admin',
            'administrator',
            'root',
            'sa',
            'sys',
            'sysman',
            'sysadmin',
            'informix',
            'db2admin',
            'postgres'`n`n
            // Company Specific Admin Accounts`n`n`n")

        # Get the list of current  Privileged accounts in Active Directory {AdminCOunt -eq 1}
        Write-Verbose "Getting list of  Privileged Users..."
        $UpdatedPrivNames = (((get-aduser -Filter {AdminCount -eq 1} -Properties AdminCount).SamAccountName.toLower() ) -replace ('\A',"`t,'") -replace ('\z', "'") | Sort-Object | out-string )
        Write-Verbose " Privileged Users retrieved!"        

        # Debug to display what was captured and formated
        #$ExtrahopDefaultValues + $UpdatedPrivNames + "`n`t//Upadted $(get-date)`n];"

        # Update Script in Memmory $Existing_Script
        $UpdatedScript = $Existing_Script.script -replace 'const priv_names = \[[\u0000-\uFFFF]*?];' , $($ExtrahopDefaultValues + $UpdatedPrivNames + "`n`t//Upadted $(get-date)`n];")

        # Generate PATCH update body and convert to JSON
        $UpdatedBody = @{   
                            apply_all = $false
                            debug = $false
                            disabled = $false                        
                            script = $UpdatedScript
                        }  | ConvertTo-Json 
        
        # For debug purposes. Saves the JSON file to the scriptroot directory
        #$UpdatedBody | ConvertTo-Json | Out-File "$PSScriptRoot\UpdatedJson.json"

        Write-Verbose "Updating Trigger"
        $UpdateTrigger =  Invoke-RestMethod -UseBasicParsing -uri ($ExtraHopURI + "/" + $TriggerID) -Method Patch -Headers $Headers -Body $UpdatedBody -ErrorAction Stop     

        Write-Verbose "Script completed!"

    }
    catch [exception]
    {
        Write-warning $_.exception
        Write-Verbose "Return: 1"
        return 1;
    }

}
catch 
{
    Write-Warning $_.exception.message 
    Write-Verbose "Return: 1"
    return 1;
}

Write-Verbose "Return: 0"
return 0;

#8

What if Account lockout duration and Reset account lockout counter after are Not defined?


#9

Is there a way to partial match admin accounts?? ie: adm.steve.mcgee

I tried just putting adm. in the priv user array, but it looks to me like it’s doing a match… but I often question my javascript knowledge :slight_smile:


#10

So this bundle is still looking at SRV records and not really SRV records for AD, We had to put a regex in.

if (DNS.qtype == “SRV” && regex.test(DNS.qname))

and then add the regex to get it to specifically look at DNS srv records. we have a ton of sip srv records which throughs off the timing and makes it look like DNS is performing poorly.


#11

Hello! You can see the “PREAUTH_REVOKED” message in the payload of the packet? I’m not sure why, but I’m unable to see this. Can you share a screenshot please? Thanks in advance!

Jamie


#12

Sorry, Jamie. That was a mistype above. A bad password is:

KDC_ERR_PREAUTH_FAILED
KRB5_KDC_ERR_PREAUTH_FAILED

A disabled account (or lockout) will show as:

KDC_ERR_CLIENT_REVOKED
KRB5_KDC_ERR_CLIENT_REVOKED


#13

Sorry. I misunderstood your question. Here is a screenshot of a packet in Wireshark showing bad password. The highlighted hex-data is the bytes used to show the error in the payload.


#14

Hey, thanks dude! I found these couple articles too.

https://blogs.technet.microsoft.com/askpfeplat/2017/04/04/network-capture-best-practices/
https://technet.microsoft.com/en-us/library/bb463166.aspx

Interesting stuff, appreciate the response.


#15

Surprised this doesn’t require a key, I always assumed this traffic was encrypted.


#16

This new version of the bundle should maintain the previous Username -> IP combination Key, vs just a Username key. Since there is no spyglass drill down, when you view something like invalid passwords or disabled accounts by user or by IP, and you have any number of these metrics it is not easy to correlate the username to the IP address the auth request is coming from.

You now need to navigate to kerberos AD records, and apply some filters to get specific username and IP associations.


#17

Matching works great for me. we have all our PRIV accounts being “watched”