bloodyAD

repository·main·Indexed 25 days ago

https://github.com/cravaterouge/bloodyad

An Active Directory privilege escalation tool and library (version 2.5.4) designed to perform specific LDAP calls to domain controllers. It supports multiple authentication methods including cleartext passwords, pass-the-hash, pass-the-ticket, and certificates, and is compatible with SOCKS proxies. The tool provides a CLI for AD assessment and a Python package featuring Config and ConnectionHandler for managing network connections, as well as utilities for manipulating Security Descriptors (SDDL) and resolving AD identities.

Tokens
2.6K
Snippets
2
Records
19
Agent score
81%

What's inside bloodyAD

  1. Overview of bloodyAD

    main

    bloodyAD is an Active Directory (AD) privilege escalation tool designed to perform specific LDAP calls to a domain controller to facilitate AD privesc.

    Key capabilities include:

    • Multiple Authentication Methods: Supports cleartext passwords, pass-the-hash, pass-the-ticket, or certificates.
    • LDAP Binding: Binds to LDAP services of a domain controller.
    • Insecure Exchange Support: Supports the exchange of sensitive information without requiring LDAPS.
    • Proxy Support: Designed to work transparently with a SOCKS proxy.

    Note: The autobloody component has been moved to its own repository: https://github.com/CravateRouge/autobloody.

  2. How `LazyAdSchema` handles identity resolution

    main
    The LazyAdSchema class provides an efficient way to resolve SIDs, GUIDs, and Distinguished Names (DNs) to their human-readable names. Instead of resolving every identity immediately, it queues them using addguid(), addsid(), and adddn(). When _resolveAll() is called (either manually or when a user requests a specific identity via getguid(), getsid(), or getdn()), it performs a single batch LDAP search to resolve all queued identities at once, minimizing network round-trips.
  3. Use the bloodyAD CLI for Active Directory assessment

    main

    bloodyAD is a command-line tool designed for Active Directory privilege escalation and assessment. It uses a modular command structure where you first specify a module (category), then a specific command (function).

    Basic Usage Pattern: python3 -m bloodyAD.main [GLOBAL_OPTIONS] <MODULE> <COMMAND> [COMMAND_OPTIONS]

    Authentication Options:

    • NTLM: Use -u <username> and -p <password> or -p <LMHASH:NTHASH>.
    • Kerberos: Use -k <keywords> (e.g., kdc=192.168.100.1 realmc=corp.local). If -p is provided, it attempts to query a TGT.
    • Certificates: Use -c "path/to/key:path/to/cert" for Schannel or Kerberos PKINIT.

    Connection Options:

    • -H, --host: The hostname or IP of the Domain Controller (Required).
    • -i, --dc-ip: IP of the DC (useful if --host cannot resolve).
    • --gc: Connect to the Global Catalog.
    • -s, --secure: Increase count to use LDAPS/GCS (e.g., -ss for simple bind, -sss to remove channel binding/signing).
  4. Run a simple bloodyAD command

    main

    To use bloodyAD, you must specify the target host, domain, and user credentials. The following example demonstrates setting a password for a user using a NTLM hash (pass-the-hash style) as the password argument.

    Note: The password argument in the example starts with a colon (:), which is the convention for providing an NTLM hash.

    bloodyAD --host 172.16.1.15 -d bloody.local -u jane.doe -p :70016778cb0524c799ac25b439bd6a31 set password john.doe 'Password123!'
  5. Handle LDAP and Result errors using the exception hierarchy

    main

    The bloodyAD library uses a specific exception hierarchy for error handling. You can catch the base BloodyError to handle all library-related errors, or catch more specific errors like LDAPError for directory service issues.

    Exception Hierarchy:

    • BloodyError (Base class)
      • LDAPError (Base for LDAP-related issues)
        • ResultError: Raised when an LDAP operation returns an error code (e.g., insufficient rights or constraint violations). It contains the original result dictionary.
        • NoResultError: Raised when a search returns no objects. It includes the base (search base) and filter used.
        • TooManyResultsError: Raised when a search returns more results than the allowed limit (defaulting to 10). It includes the base, filter, and the entries found.
  6. Render a Security Descriptor with `renderSD()`

    main

    Use renderSD() to transform a raw SDDL string into a structured, human-readable dictionary. This function:

    1. Parses the SDDL into a Security Descriptor.
    2. Groups ACEs by ObjectType, Trustee, Flags, InheritedObjectType, and Right using groupBy().
    3. Uses LazySid and LazyGuid to defer the resolution of identities (SIDs/GUIDs) until they are actually needed.
    4. Returns a dictionary containing the Owner, Control, and a list of ACL entries.
  7. Remove an Access Control Entry (ACE) with `delRight()`

    main
    Use delRight() to remove a specific permission from a user SID within a Security Descriptor. It targets 'Access-Allowed' ACEs and removes the specified privilege from the mask. If the resulting mask becomes 0, the entire ACE is removed from the DACL. Returns True if a right was removed, False otherwise.
  8. Group rows with `groupBy()`

    main
    The groupBy() function merges rows (dictionaries) based on a provided grouping_order. The first element in the grouping_order list acts as the primary criterion. Rows that share the same values for all keys in the grouping_order are merged, with their values combined using the bitwise OR (|) operator.
  9. Connect to a reachable server with `connectReachable()`

    main
    Use connectReachable() to attempt to find and connect to a reachable server from a list of candidates. It uses the reacher utility to check for availability on common LDAP/GC ports (389, 636, 3268, 3269). If a reachable server is found, it returns a new connection object configured with the correct scheme (ldap, ldaps, gc, or gc-ssl) and host/IP.
  10. Retrieve a Security Descriptor with `getSD()`

    main
    Use getSD() to asynchronously fetch a Security Descriptor for a specific LDAP object. It returns a tuple containing the parsed Security Descriptor object and the raw sd_data list. If no security descriptor is found, it returns an empty Security Descriptor.