go-windapsearch
windapsearch
is a tool to assist in Active Directory Domain enumeration through LDAP queries. It contains several modules to enumerate users, groups, computers, as well as perform searching and unauthenticated information gathering.
For usage examples of each of the modules, view the modules README
In addition to performing common LDAP searches, windapsearch
now also has the option to convert LDAP results to JSON format for easy parsing. When performing JSON encoding, windapsearch
will automatically convert certain LDAP attributes to a more human friendly format as well (e.g. timestamps, GUIDs, enumerations, etc)
This is a complete re-write of my earlier Python implementation. For some more background/explanation on how I'm using Go, and more advanced usage examples see this blog post.
Installation
It is recommended to download pre-compiled binaries for amd64 Linux/Mac/Windows from the latest releases
Install from Source
To build from source, I use mage, a Make like tool written in Go. Install mage
then run the mage targets:
$ git clone https://github.com/ropnop/go-windapsearch.git && cd go-windapsearch
$ go get github.com/magefile/mage
$ mage
Targets:
build Compile windapsearch for current OS and ARCH
clean Delete bin and dist dirs
dist Cross-compile for Windows, Linux, Mac x64 and put in ./dist
$ mage build
$ ./windapsearch --version
Usage
windapsearch
is a standalone binary with multiple modules for various common LDAP queries
$ ./windapsearch -h
windapsearch: a tool to perform Windows domain enumeration through LDAP queries
Version: dev (9f91330) | Built: 03/04/21 (go1.16) | Ronnie Flathers @ropnop
Usage: ./windapsearch [options] -m [module] [module options]
Options:
-d, --domain string The FQDN of the domain (e.g. 'lab.example.com'). Only needed if dc not provided
--dc string The Domain Controller to query against
-u, --username string The full username with domain to bind with (e.g. '[email protected]' or 'LAB\ropnop')
If not specified, will attempt anonymous bind
--bindDN string Full DN to use to bind (as opposed to -u for just username)
e.g. cn=rflathers,ou=users,dc=example,dc=com
-p, --password string Password to use. If not specified, will be prompted for
--hash string NTLM Hash to use instead of password (i.e. pass-the-hash)
--ntlm Use NTLM auth (automatic if hash is set)
--port int Port to connect to (if non standard)
--secure Use LDAPS. This will not verify TLS certs, however. (default: false)
--proxy string SOCKS5 Proxy to use (e.g. 127.0.0.1:9050)
--full Output all attributes from LDAP
--ignore-display-filters Ignore any display filters set by the module and always output every entry
-o, --output string Save results to file
-j, --json Convert LDAP output to JSON
--page-size int LDAP page size to use (default 1000)
--version Show version info and exit
-v, --verbose Show info logs
--debug Show debug logs
-h, --help Show this help
-m, --module string Module to use
Available modules:
admin-objects Enumerate all objects with protected ACLs (i.e admins)
computers Enumerate AD Computers
custom Run a custom LDAP syntax filter
dns-names List all DNS Names
dns-zones List all DNS Zones
domain-admins Recursively list all users objects in Domain Admins group
gpos Enumerate Group Policy Objects
groups List all AD groups
members Query for members of a group
metadata Print LDAP server metadata
privileged-users Recursively list members of all highly privileged groups
search Perform an ANR Search and return the results
unconstrained Find objects that allow unconstrained delegation
user-spns Enumerate all users objects with Service Principal Names (for kerberoasting)
users List all user objects
Selecting a Module
Select a module to use with the -m
option. Some modules have additional options which can be seen by specifying a module when running -h
:
$ ./windapsearch -m users -h
<...>
Options for "users" module:
--attrs strings Comma separated custom atrributes to display (default [cn,sAMAccountName])
--filter string Extra LDAP syntax filter to use
-s, --search string Search term to filter on
Each module defines a default set of attributes to return. These can always be overriden by the comma separated --attrs
option, or by specifying --full
, which will always return every attribute.
Output Formats
With no other options specified, windapsearch
will display output to the terminal in the same text based format used by ldapsearch
. Output can also be written to a file by specifying the -o
option.
When specifying the -j
option, the tool will convert LDAP responses to JSON format and outut a JSON array of LDAP entries. During the marshalling, windapsearch
will also convert binary values to human-readable formats, and perform some enumeration substitution with string values.
For example, when looking a single user, these are the normal "text" attributes:
whenCreated: 20170806185838.0Z
objectSid: AQUAAAAAAAUVAAAAoWuXYvBp2/Bf49rCUgQAAA==
lastLogonTimestamp: 132340658159483754
userAccountControl: 66048
But in JSON format, they are converted:
"whenCreated": "2017-08-06T18:58:38Z",
"objectSid": "S-1-5-21-1654090657-4040911344-3269124959-1106",
"lastLogonTimestamp": "2020-05-15T20:23:35.9483754-05:00",
"userAccountControl": [
"DONT_EXPIRE_PASSWORD",
"NORMAL_ACCOUNT"
],
Note: I have not implemented full mapping/pretty printing of every LDAP attribute. If you see one that should be converted to something else and isn't, please open an Issue - or better yet a PR ;)
Logging
To see more information, including the full LDAP queries that are being sent, use the --verbose
option, which will display helpful information.
If you are experiencing issues, please use the --debug
option for much more detailed log information, including every entry being parsed
Credits
- The authors of go-ldap for the LDAP client that powers all of this
- Michael Eder for his PR and contributions to the
dns-names
anddns-zones
modules! - audibleblink for the idea and the package to parse UserAccountControl from LDAP
- dirkjanm for adidnsdump