Skip to content

Instantly share code, notes, and snippets.

@cutaway
Last active December 11, 2024 17:46
Show Gist options
  • Save cutaway/31ab4067d131ccea8efd22effb580e96 to your computer and use it in GitHub Desktop.
Save cutaway/31ab4067d131ccea8efd22effb580e96 to your computer and use it in GitHub Desktop.
Bloodhound JSON Queries Using JQ

Started here to manually parse Bloodhound Data with JQ to Create Lists of Potentially Vulnerable Users and Computers

Get JQ for Windows

Windows jq is an executable that is downloaded and the download is JUST the executable and not an installer. For these examples the executable has been moved to the local directory and renamed 'jq.exe'.

Get jq: https://jqlang.github.io/jq/

Summary List of Commands

Set contents to a variable

The BH JSON files are date stamped files with names similar to '0241108103757_users.json'. Be sure to store these in directories that help you remember the origin.

$ufile = Get-Content -Path <users json file> -Raw
$cfile = Get-Content -Path <computers json file> -Raw
$gfile = Get-Content -Path <groups json file> -Raw
$gpofile = Get-Content -Path <gpos json file> -Raw
$dfile = Get-Content -Path <domains json file> -Raw
$oufile = Get-Content -Path <ous json file> -Raw
$conpfile = Get-Content -Path <containers json file> -Raw

To review the contents of the JSON files

Note that understanding / learning the JSON format for each BH file helps. The base objects have 'Properies', 'ACES', and other attributes. The following example will page output of a JSON file, using JQ, to the PS terminal.

$gpofile | .\jq.exe | Out-Host -Paging 

Learn how to to basic queries and do not forget that some data might be in other objects or attributes. 'Select-String' is your friend. The following example finds where the term 'quota' exists in the Domains JSON file, to help identify the name of the machine quota value.

$dfile | .\jq.exe '.data[0].Properties'  | Select-String -Pattern "quota"

Working with Users

# Get list of samaccountnames
$ufile | .\jq.exe '.data[].Properties | .samaccountname'

# Only select 'enabled' users
$ufile | .\jq.exe '.data[].Properties | select (.enabled == true) | .samaccountname'

# Get a list of names for 'enabled' users
$ufile | .\jq.exe '.data[].Properties | select (.enabled == true) | .name'

# Get the descriptions for the user
$ufile | .\jq.exe '.data[].Properties | .description'

# Get the name and description of a user where the account is enabled and the description is not null
$ufile | .\jq.exe '.data[].Properties | select (.enabled == true) | select (.description != null) | [.name, .description] | @csv'

# Users that have never logged in
$ufile | .\jq.exe '.data[].Properties | select (.lastlogon == -1) | [.name, .lastlogon] | @csv'

# Users whose passwords are set never to expire
$ufile | .\jq.exe '.data[].Properties | select (.pwdneverexpires == true) | [.name, .lastlogon] | @csv'

Working with Groups

# Get a list of groups from group file
$gfile | .\jq.exe '.data[].Properties | .name'

# Get a list of groups with samaccountnames
$gfile | .\jq.exe '.data[].Properties | select (.samaccountname != null) | .samaccountname'

# Get a list of the members in the Domain Admins group
$gfile | .\jq.exe '.data[] | select (.Properties.samaccountname == \"Domain Admins\") | .Members[].ObjectIdentifier'

# Get a list of user members in the Domain Admins group
$gfile | .\jq.exe '.data[] | select (.Properties.samaccountname == \"Domain Admins\")  | .Members[] | select (.ObjectType == \"User\") | .ObjectIdentifier '

# Get a list of members in the Domain Admins group that are NOT listed as Users (assume these are groups
$gfile | .\jq.exe '.data[] | select (.Properties.samaccountname == \"Domain Admins\")  | .Members[] | select (.ObjectType != \"User\") | .ObjectIdentifier '

# Get a list of users in the Enterprise Admins group
$gfile | .\jq.exe '.data[] | select (.Properties.samaccountname == \"Enterprise Admins\")  | .Members[] | select (.ObjectType == \"User\") | .ObjectIdentifier '

# Get the names from the Enterprise Admins group
$eadmins_sid = $gfile | .\jq.exe '.data[] | select (.Properties.samaccountname == \"Enterprise Admins\")  | .Members[] | select (.ObjectType == \"User\") | .ObjectIdentifier '
$eadmins_sid | ForEach { $ufile | .\jq.exe --arg sid $_ '.data[] | select (.ObjectIdentifier == $sid) | .Properties.samaccountname' }

# Get the names from the Domain Admins group
$dadmins_sid = $gfile | .\jq.exe '.data[] | select (.Properties.samaccountname == \"Domain Admins\")  | .Members[] | select (.ObjectType == \"User\") | .ObjectIdentifier '
$dadmins_sid | ForEach { $ufile | .\jq.exe --arg sid $_ '.data[] | select (.ObjectIdentifier == $sid) | .Properties.samaccountname' }

Working with GPOs

# Get a list of all of the GPO names
$gpofile | .\jq.exe '.data[].Properties.name'

# Get information about a policy by name
$gpofile | .\jq.exe '.data[].Properties | select (.name == \"<name of policy>\")'
# NOTE: You should mount SYSVOL and check for XML, TXT, VBS, PS1, BAT and other files for additional information

# Get mountable paths
$gpofile | .\jq.exe '.data[].Properties.gpcpath'

# Get mountable path for a specific policy
$gpofile | .\jq.exe '.data[].Properties | select (.name == \"<name of policy>\" | .gpcpath)'

Working with Domains

# Name of each domain
$dfile | .\jq.exe '.data[].Properties.name'

# Trusts for each domain
$dfile | .\jq.exe '.data[].Trusts'

# Basic information from domains includes 'machine quote' and 'password' settings
$dfile| .\jq.exe '.data[0].Properties'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment