Code Monkey home page Code Monkey logo

ad-ldap-enum's Introduction

ad-ldap-enum

An LDAP based Active Directory object (users, groups, and computers) enumeration tool.

About

ad-ldap-enum is a Python script developed to collect users/computers and their group memberships from Active Directory. In large Active Directory environments, tools such as NBTEnum were not performing fast enough. By executing LDAP queries against a domain controller, ad-ldap-enum is able to target specific Active Directory attributes and quickly build out group membership. ad-ldap-enum outputs three tab delimited files:

  • Domain_Group_Membership.csv
  • Extended_Domain_User_Information.csv
  • Extended_Domain_Computer_Information.csv

The first file contains users, computers, groups, and their memberships. The second file contains users and extra information about the users from Active Directory (e.g. a user's home folder or email address). The third file contains computers in the 'Domain Computers' group and extra information about them from Active Directory (e.g. operating system type and service pack version). ad-ldap-enum supports both authenticated and unauthenticated LDAP connections. Additionally, ad-ldap-enum can process nested groups and display a user's actual group membership. This tool also supports password and Pass-the-Hash (PtH) LM:NTLM style authentication. ad-ldap-enum also supports LDAP over SSL/TLS connections, IPv4, and IPv6 networks.

Requirements

The package primarily uses the ldap3 Python package to execute the LDAP connections and queries. To install all requirements, please run the below command:

python -m pip install -r 'requirements.txt'

Additionally, this tool has been built and tested against Python v3.10 on both Kali Linux and Windows 10. Regardless, this tool aims to be OS-agnostic working on both UNIX/Linux systems and Windows. Furthermore, Python 2.X will not be supported.

Usage

Please see the tool's help menu below:

usage: ad-ldap-enum.py [-h] (-n | -u USERNAME | -dn DISTINGUISHED_NAME)
                       [-p PASSWORD] [-P] [-s] [-t TIMEOUT] [-ql QUERY_LIMIT]
                       [--verbosity {OFF,ERROR,BASIC,PROTOCOL,NETWORK,EXTENDED}]
                       [--legacy] [-x] [-o FILENAME_PREPEND] -l LDAP_SERVER
                       [--port PORT] -d DOMAIN [-a ALT_DOMAIN] [-e] [-4] [-6]

Active Directory LDAP Enumerator

optional arguments:
  -h, --help            show this help message and exit
  -n, --null            Use a null binding to authenticate to LDAP.
  -u USERNAME, --username USERNAME
                        Authentication account's username.
  -dn DISTINGUISHED_NAME, --distinguished_name DISTINGUISHED_NAME
                        Authentication account's distinguished name
  -p PASSWORD, --password PASSWORD
                        Authentication account's password or "LM:NTLM".
  -P, --prompt          Prompt for the authentication account's password.
  -s, --secure          Connect to LDAP over SSL/TLS
  -t TIMEOUT, --timeout TIMEOUT
                        LDAP server connection timeout in seconds
  -ql QUERY_LIMIT, --query_limit QUERY_LIMIT
                        LDAP server query timeout in seconds
  --verbosity {OFF,ERROR,BASIC,PROTOCOL,NETWORK,EXTENDED}
                        Log file LDAP verbosity level
  --legacy              Gather and output attributes using the old python-ldap
                        package .tsv format (will be deprecated)
  -x, --excel           Output an .XLSX with all 3 sheets: users/groups/computers
  -o FILENAME_PREPEND, --prepend FILENAME_PREPEND
                        Prepend a string to all output file names.

Server Parameters:
  -l LDAP_SERVER, --server LDAP_SERVER
                        FQDN/IP address of the LDAP server.
  --port PORT           TCP port of the LDAP server.
  -d DOMAIN, --domain DOMAIN
                        Authentication account's domain. If an alternative domain
                        is not specified, this will be also used as the Base DN
                        for searching LDAP.
  -a ALT_DOMAIN, --alt-domain ALT_DOMAIN
                        Alternative FQDN to use as the Base DN for searching LDAP.
  -e, --nested          Expand nested groups.
  -4, --inet            Only use IPv4 networking (default prefer IPv4)
  -6, --inet6           Only use IPv6 networking (default prefer IPv4)

Example

Please see some examples below:

Password authentication

python 'ad-ldap-enum.py' -d contoso.com -l 10.0.0.1 -u 'Administrator' -p 'P@ssw0rd' -o 'ad-ldap-enum_2' --verbosity BASIC -lf 'ad-ldap-enum_Log.txt'

Pass-the-Hash LDAPS authentication

python 'ad-ldap-enum.py' -d contoso.com -l 10.0.0.1 -s -u 'Administrator' -p 'aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0'

Modification

If you would like to add more attributes to the non-legacy version, the following steps can be quickly added:

  1. Find the attribute's formatted name at All Active Directory Attributes
    1. Please note that modifying the group output may be a little more difficult.
  2. Append the attribute to the applicable object list within user_attributes, group_attributes, or computer_attributes
  3. Update the object's class to have a default value (i.e., distinguished_name = '')
  4. Update the object's class to have the __init__ function parse the retrieved attribute
  5. Update the object's output section to include appending the new attribute header and value

Planned Features

We should plan to include the following features moving forward:

  • Kerberos authentication (preferably not using the Impacket suite so that the tool can be OS-agnostic)
  • LDAP signing
  • LDAP channel binding
  • ObjectSID retrieval

Pull requests are welcome!

Assorted Links

Please see some assorted reference links and similar projects:

ad-ldap-enum's People

Contributors

ahhh avatar edepree avatar emperorcow avatar freddieoliveira avatar kielev avatar raul5660 avatar zamanry avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ad-ldap-enum's Issues

Inventory notification

ad-ldap-enum has been inventoried on Rawsec's CyberSecurity Inventory.

https://inventory.rawsec.ml/tools.html#ad-ldap-enum

What is Rawsec's CyberSecurity Inventory?

An inventory of tools and resources about CyberSecurity. This inventory aims to help people to find everything related to CyberSecurity.

More details about features here.

Note: the inventory is a FLOSS (Free, Libre and Open-Source Software) project.

Why should you care about being inventoried?

Mainly because this is giving visibility to your tool and improve its referencing.

Badges

The badge shows to your community that your are inventoried. It looks good but also shows you care about your project, that your tool is referenced.

Feel free to claim your badge here: http://inventory.rawsec.ml/features.html#badges, it looks like that Rawsec's CyberSecurity Inventory, but there are several styles available.

Want to thank us?

If you want to thank us, you can help make our open project better known by tweeting about it! For example: Twitter URL

So what?

That's all, this message is just to notify you if you care. Else you can close this issue.

More user attributes

Can we have a flag to pull the full list of LDAP attributes for users? I find myself wanting more information, but not sure it is worth trying to narrow that down. Thoughts?

Group Membership CSV Has Inconsistent Number of Columns

When values are not found, ad-ldap-enum sometimes outputs rows with different numbers of columns, instead of outputting a consistent number of columns with empty strings for values that aren't found. This causes problems when passing ad-ldap-enum output files to other tools.

I'm not sure if this applies to just Domain Group Membership, but many (though not all) members of the groups Domain Admins, Domain Computers, Domain Controllers, and Domain Users did not have a Distinguished Name returned. Additionally, all computer account members of Domain Users and Domain Computers were missing both Member Status and Group Distinguished name values.

The problem is not that the values were not present, but the output did not contain empty strings in their place. Instead, entries missing the Distinguished Name contained 3 columns instead of 4. I believe entries missing both Member Status and Group Distinguished Name contained only 2 columns. This problem was limited to the Domain Group Membership file in my case but may also apply to other files, apologies for the lack of detail. Further testing is required.

For the time being I am using the following function to normalize the number of columns in output files, but ideally a fix should be implemented to output empty strings in place of values (such as Group Distinguished Name) ad-ldap-enum can't retrieve.

def normalize_csv(file_path):
    """
    Normalize a CSV file by adding empty columns to each row as necessary.

    Args:
        file_path (str): The path to the CSV file.

    Returns:
        None
    """
    # Read the CSV file
    with open(file_path, 'r') as file:
        reader = csv.reader(file)
        rows = list(reader)

    # Find the maximum number of columns in the CSV
    max_columns = max(len(row) for row in rows)

    # Normalize the rows by adding empty columns
    normalized_rows = [row + [''] * (max_columns - len(row)) for row in rows]

    # Write the normalized rows back to the CSV file
    with open(file_path, 'w', newline='') as file:
        writer = csv.writer(file)
        writer.writerows(normalized_rows)

help page

Running the script with no arguments should bring up the help page vs erroring out.

Not compatible with Python3

Unfortunately ad-ldap-enum.py is not compatible with python3.

Can anyone estimate how long it would take to migrate the script to python3?

Explode Nested Groups

Add the functionality to recursively go through group membership and display nested groups flattened out.

Null Password and NTLM Hash

On the HackTheBox machine Escape, the guest user was enabled on a DC. I attempted to authenticate using the password '' but the tool refused to accept it as a valid parameter value. Even when I used the prompt parameter, the issue arose.

Additionally, I attempted to use PassTheHash via the null NTLM hash, 31d6cfe0d16ae931b73c59d7e0c089c0, but the DC responded incorrect password.

We need to figure out the password null password (could be checking if variable exists vs. null). We also need to figure out why PassTheHash seems to not be accepted some time.

LDAP Channel Binding Support

Once the https://github.com/cannatag/ldap3/tree/dev branch is merged into master and pushed to pip, we can support LDAP channel binding due to cannatag/ldap3#1087 already being merged. Channel binding applies to both LDAP and LDAPS connections.

Please note that LDAP signing requirements can be achieved through using LDAPS or LDAP with STARTTLS. This tool does not support LDAP with STARTTLS.

The error you may receive IF LDAP channel binding is required is Invalid credentials or domain were provided. You could also use the -verbosity flags as needed to debug the LDAP traffic.

auth error

When -u is given a fully qualified domain, the script will state that incorrect username or password was given. For example:

-u crowesec\username < ok
-u crowesec.net\username < wrong auth

Switching to ldap3

This repository should consider moving to ldap3 over python-ldap as ldap3 is entirely Python-based while python-ldap is Python/C. python-ldap does not work easily on Windows which causes this tool to be Linux focused only seen here:

More information regarding the change can be found here:

Additionally, the Impacket suite uses ldap3 as their LDAP module which causes issues as both modules use the ldap Python naming scheme within import methods particularly on Kali Linux systems.

I don't think changing this tool to ldap3 will be an incredible amount of work once the data structure and manipulation is understood.

Reduce Code Duplication

The methods get_password_last_set_date and get_last_logon_date are duplicating code. Calculating time-stamps should be made generic to allow for future expansion.

Inaccurate Error Message

Fix the error message on line 419 from 'LDAP server is available' to 'LDAP server is not available'

Critical extension is unavailable

Queried our LDAP server. Got this:
ldap.UNAVAILABLE_CRITICAL_EXTENSION: {'desc': 'Critical extension is unavailable'}
Quick Google search turns up:
http://blogs.adobe.com/apugalia/ldap-error-code-12-unavailable-critical-extension/
https://www.ca.com/us/services-support/ca-support/ca-support-online/knowledge-base-articles.tec439052.html

...commonly occurs when asking an LDAP Server to return paged results but the LDAP doesn’t support the PagedResultsControl extension.

SunOne 5.2 and 6.3 don’t support PagedResultsControl extension.

...which is the problem I'm running into. Unfortunately, setting the batch size parameter to 0 on such systems is also not going to help, as there is (in our case) a hard limit on the return size configured.

One way around this is to rewrite queries to parse out the enumeration in small steps, using query strings with wildcard operators. For example, querying sn="dav*", sn="daw*", etc., and then combining the results later. Of course, any arbitrary query string has to match the actual data in LDAP and be adjusted in the event the return exceeds whatever arbitrary cut-off size is implemented.

Any hope that ad-ldap-enum would be updated to support these edge cases situations?

I can see why that would not be super important, since the objective is AD enumeration and not just LDAP enum...

Exploding large groups: ldap.FILTER_ERROR: {'desc': 'Bad search filter'}

As seen just now, query was to my AD logon server. Any hints?

$ python ad-ldap-enum.py -l host-fqdn -d my-domain -u me -p my_pass
2017-07-05 15:00:55 INFO Querying users
2017-07-05 15:06:32 INFO Querying groups
2017-07-05 15:14:01 INFO Querying computers
2017-07-05 15:15:16 INFO Building users dictionary
2017-07-05 15:15:16 INFO Building groups dictionary
2017-07-05 15:15:16 INFO Building computers dictionary
2017-07-05 15:15:16 INFO Exploding large groups
Traceback (most recent call last):
File "ad-ldap-enum.py", line 460, in
ldap_queries(ldap_client, base_dn, args.nested_groups)
File "ad-ldap-enum.py", line 210, in ldap_queries
groups_dictionary[group_key].members = get_membership_with_ranges(ldap_client, base_dn, group_key)
File "ad-ldap-enum.py", line 387, in get_membership_with_ranges
membership_results = query_ldap_with_paging(ldap_client, base_dn, membership_filter, ['distinguishedName'])
File "ad-ldap-enum.py", line 356, in query_ldap_with_paging
msgid = ldap_client.search_ext(base_dn, ldap.SCOPE_SUBTREE, search_filter, attributes, serverctrls=[ldap_control])
File "/usr/lib64/python2.7/site-packages/ldap/ldapobject.py", line 586, in search_ext
timeout,sizelimit,
File "/usr/lib64/python2.7/site-packages/ldap/ldapobject.py", line 106, in _ldap_call
result = func(*args,**kwargs)
ldap.FILTER_ERROR: {'desc': 'Bad search filter'}

Unable to Bind Output

If the tool is unable to bind through a null/authenticated or insecure/secure LDAP connection, the tool outputs an error rather than a statement stating "Unable to bind to requested LDAP connection." See the current output now:

ad-ldap-enum-output

Empty results

# ad-ldap-enum -d 'example.com' -l 'ldap.forumsys.com' -n ; cat ./*
2017-04-17 00:00:00 INFO     Querying users
2017-04-17 00:00:00 INFO     Querying groups
2017-04-17 00:00:00 INFO     Querying computers
2017-04-17 00:00:00 INFO     Building users dictionary
2017-04-17 00:00:00 INFO     Building groups dictionary
2017-04-17 00:00:00 INFO     Building computers dictionary
2017-04-17 00:00:00 INFO     Exploding large groups
2017-04-17 00:00:00 INFO     Building group membership
2017-04-17 00:00:00 INFO     There is a total of [0] groups
2017-04-17 00:00:00 INFO     Writing domain user information to [Extended Domain User Information.tsv]
2017-04-17 00:00:00 INFO     Writing domain computer information to [Extended Domain Computer Information.tsv]
2017-04-17 00:00:00 INFO     Writing membership information to [Domain Group Membership.tsv]
2017-04-17 00:00:00 INFO     Elapsed Time [0:00:00.533394]
Group Name      SAM Account Name        Status
SAM Account Name        OS      OS Hotfix       OS Service Pack OS Version
SAM Account Name        Status  Locked Out      Display Name    Email   Home Directory  Profile Path    Logon Script Path       Password Last Set    Last Logon       User Comment    Description

SPN Support

Can we have it pull the spns associated with domain user accounts?

These attributes will be stored in the servicePrincipalName attribute for each user account if there are existing spns.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.