Skip to content

Releases: dehobbs/ADScan

v1.3.4

Choose a tag to compare

@dehobbs dehobbs released this 18 Jun 22:29

Fixed

AdminSDHolder ACL check — multiple correctness fixes

These bugs caused both false positives (legitimate principals flagged) and missed findings (real write-access not reported):

  • Trustee SIDs were rendered as raw hex blobs. ACE SIDs used str(sid) (e.g. 0105…00020000) instead of formatCanonical(), which defeated every
    name/RID match — so every principal, including Domain Admins and SYSTEM, was flagged. Now converted to canonical S-1-5-… form.
  • Tier-0 groups now recognized by RID. Domain Admins, Enterprise Admins, Schema Admins, Domain Controllers, and Administrators are matched by their
    SID RID, so they're excluded even when SID→name resolution is unavailable.
  • Mislabeled access-mask constants corrected. 0x00020000 (READ_CONTROL — a read right) was treated as WriteDACL and included in the "dangerous"
    mask, so any principal with normal read access was flagged as having write. Corrected to the real Win32/ADS write bits (WriteProperty, WriteDACL,
    WriteOwner, GenericWrite, GenericAll).
  • Authenticated Users and Everyone removed from the expected allowlist. They should only ever have read access, so write access for them is now
    correctly reported instead of suppressed.

SID resolution — well-known SIDs resolve to friendly names

ADConnector.resolve_sid() now consults a static well-known-SID table before the LDAP lookup, so reports show Authenticated Users / SYSTEM /
Administrators instead of S-1-5-11 / S-1-5-18 / S-1-5-32-544 (these have no queryable directory object and can't be resolved via LDAP). Benefits
every check that resolves SIDs.

Full Changelog: v1.3.3...v1.3.4

v1.3.3

Choose a tag to compare

@dehobbs dehobbs released this 18 Jun 17:38

Added

  • Generic check preflight hook: a check module may now define an optional preflight(connector) function. adscan.run_preflight() invokes every
    loaded check's hook (in CHECK_ORDER) before the scan loop, so interactive setup happens up front and the scan then runs unattended. A hook that raises
    is logged and skipped so it cannot abort the scan. Covered by unit tests.

Changed

  • BloodHound engine prompt moved to the start of the run. The Legacy vs Community Edition question is now asked up front via check_bloodhound's
    preflight() hook instead of mid-scan when the collection step is reached. The operator answers once and can walk away; data collection still runs last
    (CHECK_ORDER 99) — only the prompt moved. The prompt is skipped entirely when BloodHound is excluded via --checks/--skip, and non-interactive
    sessions still default to Legacy.

Full Changelog: v1.3.2...v1.3.3

v1.3.2

Choose a tag to compare

@dehobbs dehobbs released this 10 Jun 00:42

Added
Fine-Grained Password Policies (PSO) check - flags 'msDS-PasswordSettings' objects weaker than the default domain policy; escalates when linked to a privileged principal.
Print Spooler on Domain Controllers check - detects the Print Spooler (MS-PRN / PrinterBug) on DCs via NetExec; coercion --> ESC8/RBCD/unconstrained relay.
WebClient (WebDAV) Coercion Surface check - sweeps hosts for the WebClient service (HTTP coercion -> ESC8/LDAP relay).
First unit test suite ('tests/').

Check count: 40 --> 43.

Full changelog: https://github.com/dehobbs/ADScan/blob/v1.3.2/CHANGELOG.md

ADScan v1.3.1

Choose a tag to compare

@dehobbs dehobbs released this 29 May 18:41

Highlights

  • Plaintext-password leak in the redacted customer report — fixed. The "Passwords Found in Privileged Account Description Fields" finding in check_privileged_accounts.py was populating its details list with <sam>: <description> strings, where the description body is the leaked credential. The finding never set a details_redacted companion list, so lib/report.py:_get_details(redact=True) fell through and rendered the plaintext into the redacted customer report. The finding now provides both details (operator) and details_redacted (customer), so passwords no longer appear in the default report when --unredacted is not specified. Every other check that handles credential material was audited; only this one was leaking.

  • CLI help layout. The --timeout flag was registered under the Output argument group, so it appeared next to report-path and log-file flags. It is a connection-level setting like --protocol, --dns-server, and --dns-tcp, so it now lives at the bottom of the Target group where it belongs. Functional behaviour is unchanged; only the help layout shifts.

  • CLI Reference completeness. Four flags that existed in adscan.py but were missing from the README's CLI Reference tables are now listed there: --dns-server / -ns, --dns-tcp, --unredacted, and -V / --version. The --timeout row was also tightened to mention its dual role as the LDAP receive-timeout used by the stall detector introduced in v1.3.0.

Install (existing users)

Pipx users:

pipx install --force git+https://github.com/dehobbs/ADScan.git@v1.3.1
adscan --setup-tools

Editable clone:

git pull origin main
pip install -e 

ADScan v1.2.0

Choose a tag to compare

@dehobbs dehobbs released this 04 May 15:40

ADScan v1.2.0

Highlights

  • One-line install via pipx

    pipx install git+https://github.com/dehobbs/ADScan.git
    adscan --setup-tools
    

    setup-tools now bootstraps uv itself when it is not already on PATH, then provisions every external CLI tool into its own isolated virtual environment.

  • BloodHound engine selector. When the BloodHound step starts, you are prompted to choose between Legacy BloodHound (bloodhound-python) and BloodHound Community Edition (bloodhound-ce-python). Both ingestors install via uv tool install. Non-interactive sessions default to Legacy.

  • Kerberos works against arbitrary lab DCs. ADScan now synthesizes a usable krb5.conf on the fly when the host system has none or omits a default realm, and resolves the DC FQDN via SRV when you pass an IP for dc-ip so GSSAPI builds the correct service principal name.

  • Pre-Windows 2000 computer accounts check rewritten. The check no longer depends on the standalone pre2k binary; it invokes the NetExec pre2k LDAP module instead and parses both the pre-created and the verified-vulnerable account sets.

  • ADCS check expanded. The Certipy phase is now joined by a NetExec adcs module phase. Certipy retains priority for any ESC class it reports; NetExec fills in gaps. The legacy LDAP-only checks are muted by default.

Authentication

  • Synthesize a temp krb5.conf when Kerberos is requested and none is configured (deleted at process exit).
  • Resolve the DC FQDN via SRV when dc-ip is an IP, then patch the in-process DNS resolver so the FQDN routes to the original IP. Subsequent ldap3 and impacket calls build SPNs as ldap or cifs slash FQDN, which Active Directory actually has registered.
  • pre2k auth path now supports Kerberos cleanly and no longer falls through to an empty password when no credential material is available.

Reports and UX

  • Spinner is suspended for the duration of any interactive prompt so the elapsed-time counter never overwrites the question.
  • MATCH_KEYS for verify_pre2k and verify_pre_windows_2000 disambiguated; each check's findings now route to the correct verification module regardless of import order.
  • Comprehensive developer reference added at docs/REFERENCE.md.

Cleanup

  • Removed the standalone pre2k entry from the tool registry (NetExec covers the same surface area).
  • Dropped the unsupported BloodHound op flag for bloodhound-python 1.6 plus.
  • README, pyproject, requirements: install instructions consolidated, Git prerequisite removed.

Install (existing users)

If you previously installed by clone, pull main and re-run pip install. If you want the new pipx workflow:

pipx install git+https://github.com/dehobbs/ADScan.git@v1.2.0
adscan --setup-tools

Pinning to v1.2.0 gives you a reproducible install rather than tracking main.