Metadata-Version: 2.4
Name: adpentest
Version: 2.14.213.78.21.13
Summary: Active Directory penetration testing framework with automatic Domain Controller detection
Author-email: Netanel Cyber <nsh531@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/netanelcyber/AdPentestAI-Python
Project-URL: Repository, https://github.com/netanelcyber/AdPentestAI-Python.git
Project-URL: Issues, https://github.com/netanelcyber/AdPentestAI-Python/issues
Project-URL: Documentation, https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/README.md
Keywords: active-directory,penetration-testing,ad-enumeration,kerberos,smb,ldap,security,offensive-security,red-team
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Natural Language :: English
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Security
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx<1,>=0.27
Requires-Dist: dnspython<3,>=2.4
Requires-Dist: ldap3<3,>=2.9
Requires-Dist: jinja2>=3.0
Requires-Dist: SQLAlchemy<3,>=2.0
Requires-Dist: impacket<0.14,>=0.13
Provides-Extra: smb
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: black>=23.0; extra == "dev"
Requires-Dist: flake8>=6.0; extra == "dev"
Requires-Dist: mypy>=1.0; extra == "dev"
Dynamic: license-file

# AdPentestAI-Python

Version `2.14.213.78.21.13` updates the PyPI user guide with an emphasis on
Kerberos evidence and backward compatibility. Runtime behavior is
unchanged from `.12`: website entrypoint inventory, detailed JSON/HTML reports,
explicit F5/FortiGate access review and existing diagnostics remain compatible.

## User guide

### Install and choose a profile

Use Python 3.10 or newer in a virtual environment:

```console
python -m venv .venv
python -m pip install --upgrade "adpentest==2.14.213.78.21.13"
python -c "import adpentest; print(adpentest.__version__)"
```

Activate the environment before the last two commands: `source .venv/bin/activate`
on Linux/macOS, or `.\.venv\Scripts\Activate.ps1` in Windows PowerShell.
The `adpentest` console command and `python -m adpentest` use the same dispatcher.
Use `./python` only when a Python executable actually exists in the current directory.

Select the profile explicitly; their parsers accept different options:

| Goal | Profile | Data collected |
| --- | --- | --- |
| Inventory public login gateways | `--entrypoint-check` | Bounded DNS, HTTP and TLS observations |
| Map one host's TCP/VPN UDP ports | `--ALL-PORTS`, or `--port-map` | Nmap port states |
| Review F5/FortiGate API access | `--entrypoint-check --vpn-access-check both` | Unauthenticated API responses and public login controls |
| Inventory exported AD accounts | `--ldap-spn-data FILE` | Local JSON records and SPN observations |
| Review existing Kerberos tickets | `--ticket-inventory` | Current user's local cache metadata |
| Other legacy AD workflows | No explicit profile above | Existing broad legacy scanner; see the reference below |

Examples use reserved documentation domains. Replace them with systems covered
by your approved scope. For the network profiles below, the default `dry-run`
does no DNS queries or remote requests, but can write local reports and SQLite
history. `--mode active --scope-confirmed` enables traffic; the flag records your
scope declaration, rather than independently establishing authorization.

### Website and organization login gateways

Start with a preview:

```console
python -m adpentest --entrypoint-check --target https://www.example.com --domain example.com --ALL-PORTS --mode dry-run --db-path ./scan_history.db --info-report ./entrypoints-plan.json --html-report ./entrypoints-plan.html
```

For an approved active inventory, use new output filenames:

```console
python -m adpentest --entrypoint-check --target https://www.example.com --domain example.com --ALL-PORTS --mode active --scope-confirmed --db-path ./scan_history.db --info-report ./entrypoints.json --html-report ./entrypoints.html
```

`--domain` explicitly defines the organization scope when the website is a
subdomain. Without it, the profile uses the exact target hostname as its domain;
it does not infer a parent from `www`. Additional approved hosts can be supplied
with repeatable `--entrypoint-host HOST` inside that domain.

**In this profile, `--ALL-PORTS` alone expands gateway candidates, without
mapping ports.** Its fixed candidates are `vpn`, `remote`, `sso`, `login`,
`portal`, `mail`, `webmail`, `adfs` and `rdweb` under the explicit domain.
The inventory remains bounded: at most 16 hosts, 32 HTTP requests and 64 KiB per
response body, with a default 60-second total inventory deadline. Set
`--timeout` between 1 and 120 seconds to change that deadline. This is a
bounded inventory rather than exhaustive subdomain discovery.

Active inventory uses approved public DNS addresses, verified TLS and fixed
read-only HTTP paths. It does not follow redirects, submit login forms, send
credentials or retain response bodies. Private or mixed public/private DNS
answers block a website host; a private AD controller belongs to a separate
workflow. Product markers are candidates requiring owner review.

### Combined port map and F5/FortiGate access review

The following previews gateway inventory, full TCP mapping and both vendor
access reviews on the **exact target host**:

```console
python -m adpentest --entrypoint-check --target adfs.example.com --domain example.com --ALL-PORTS --port-map --port-map-timeout 600 --vpn-access-check both --mode dry-run --db-path ./scan_history.db --info-report ./combined-plan.json --html-report ./combined-plan.html
```

For the approved active run:

```console
python -m adpentest --entrypoint-check --target adfs.example.com --domain example.com --ALL-PORTS --port-map --port-map-timeout 600 --vpn-access-check both --mode active --scope-confirmed --db-path ./scan_history.db --info-report ./combined.json --html-report ./combined.html
```

`--port-map` adds Nmap TCP ports 1–65535 and the fixed VPN UDP ports
500, 1194, 1701, 4500 and 51820 when combined with `--ALL-PORTS`.
This does not map every discovered subdomain. Install Nmap separately and put
it on PATH; the entrypoint profile never automatically installs external tools.
UDP discovery may need elevated local privileges. A 600-second mapping deadline
can expire before all ports finish; inspect status and truncation indicators.
For a selected TCP range, replace `--ALL-PORTS` with `--ports 443,8443` and keep
`--port-map`. The two port-selection options cannot be combined.

If the actual VPN gateway differs from the website target, select it explicitly:

```console
python -m adpentest --entrypoint-check --target adfs.example.com --domain example.com --vpn-access-check both --vpn-access-host vpn.example.com --mode dry-run --db-path ./scan_history.db --info-report ./vpn-plan.json --html-report ./vpn-plan.html
```

`--vpn-access-check` accepts `f5`, `forti` or `both`. Repeat
`--vpn-access-host` for up to four approved hosts inside the domain.
The default is the exact website target; gateway discovery never automatically
enables access checks on every subdomain. Selecting a VPN host does not move
the diagnostic port map to that host: use a separate one-host port-map command
if that gateway also needs mapping.

The vendor review performs credential-free GET requests to the F5 management
status endpoint and login control, or the FortiGate system status endpoint and
login control. It records denials, redirects without following them, missing
endpoints, login pages, errors and recognized unauthenticated API responses.
Only bounded classifications, metadata and body hashes are retained; API values
are omitted. Public login pages or HTTP 200 alone do not establish bypass.
Even a recognized status response requires the owner's access-policy review.
VPN tunnel access, MFA bypass and CVE exploitation are not tested or confirmed.
See the [detailed entrypoint reference](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/ENTRYPOINTS.md).

### Detailed reports and existing databases

| Output | Option | Contents |
| --- | --- | --- |
| JSON evidence | `--info-report ./review.json` | Scope, coverage, planned/performed/skipped requests, HTTP timings, DNS answers/TTLs, TLS metadata, errors, VPN review and combined diagnostics |
| Standalone HTML | `--html-report ./review.html` | The same evidence in readable tables, full request details, review guidance and print styles; no external scripts or resources |
| SQLite history | `--db-path ./scan_history.db` | Existing diagnostic ORM records and entrypoint results, with persistence receipts |

Choose **distinct, new report paths in an existing directory**. Report files are
not overwritten. Reusing an existing database preserves its older tables;
required ORM tables are added. Combined diagnostics and entrypoint inventory
have their own persisted records. Check the JSON persistence receipts rather
than assuming the presence of a report proves a successful database write.

Read `coverage`, errors and skipped work before interpreting results. A dry-run
report is a plan. Timeouts, blocked addresses, missing tools and unperformed
checks leave coverage incomplete. Port states and tentative vendor markers do
not prove vulnerabilities. Older reports retain missing evidence as
`Not recorded` in the HTML renderer.

### Kerberos review: SPNs, encryption and existing tickets

Keep three kinds of evidence distinct: an account's exported configuration,
an already issued ticket in the current user's local cache, and a remote port
state. These profiles do not perform a Kerberos login or enumerate users by
testing guessed account names against a KDC.

| Evidence | What to inspect | Limit of the observation |
| --- | --- | --- |
| Exported `servicePrincipalName` | Parsed service class, hostname, optional port and duplicate owners | Registration does not prove that the service is reachable or the account can authenticate. |
| Exported `msDS-SupportedEncryptionTypes` | Advertised DES, RC4 and AES bits; unknown/missing values | Effective ticket encryption remains `not_assessed`; a missing value does not prove RC4. |
| Exported account status/timestamps | UAC-derived disabled state and supplied password/logon dates | Export metadata does not establish current access or a complete authentication history. |
| Local TGT and service tickets | Client/server principals, ticket/session encryption, flags and validity timestamps | Current user's default cache only; no other sessions or directory-wide user inventory. |
| TCP 88/464 port states | A limited endpoint connectivity observation | Open ports do not establish successful Kerberos authentication, service identity or a CVE. |

Use the offline account command in the next section to review SPNs and advertised
encryption. Duplicate-SPN groups identify different GUID/DN owners in the supplied
export; reconcile them with the directory administrator. An account without an
SPN still appears in `accounts`.

For existing tickets, preview and then collect metadata locally:

```console
python -m adpentest --ticket-inventory --mode dry-run --domain lab.example --db-path ./scan_history.db --ticket-report ./tickets-plan.json
python -m adpentest --ticket-inventory --mode active --domain lab.example --db-path ./scan_history.db --ticket-report ./tickets.json
```

This independent route uses the system `klist` for the current user's existing
default cache. `active` enables the local collector, without selecting a remote
target; `--domain` only groups saved results. Use `--ticket-report` for its JSON
file, rather than the website profile's report options. It saves sanitized
metadata through the existing ORM and discards raw command output. Ticket bytes
and session-key values are not exported. Collection does not request, renew,
purge, inject or replay tickets.

Inspect `inventory.status` and `ticket_count`. Missing `klist`, unsupported
localization/format, incomplete or truncated output means unknown coverage,
rather than zero tickets. English Windows and MIT Kerberos output are supported;
there is a 256-ticket parser limit. Timestamps retain their source format, without
guessing timezones or expiration state. Observed RC4/DES algorithm names are
manual configuration-review findings, not confirmed vulnerabilities.
See the [ticket inventory reference](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/TICKET_INVENTORY.md).

If TCP port mapping is needed, select a controller already identified and
approved by its administrator, rather than assuming an ADFS website is a KDC:

```console
python -m adpentest --port-map --ports 88,464 --target dc.lab.example --domain lab.example --mode dry-run --db-path ./scan_history.db
```

This maps only the selected TCP ports using Nmap. It does not test UDP Kerberos,
request tickets or authenticate. For an approved remote run, change to
`--mode active --scope-confirmed`. Effective encryption, preauthentication,
delegation policy and KDC security-update status require separate administrator
evidence; the metadata profiles do not verify them. Microsoft references:
[klist](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/klist)
and [encryption attribute](https://learn.microsoft.com/en-us/windows/win32/adschema/a-msds-supportedencryptiontypes).

### AD users: analyze an existing authorized export

A public website or ADFS login page cannot supply a complete AD user directory
through the entrypoint profile. There is no `FULLY SCAN FOR DETECTION USERS`
switch. Use an existing authorized directory export for account inventory:

```console
python -m adpentest --ldap-spn-data ad-users.json > ad-users-report.json
```

This route reads local files and outputs JSON. It accepts a JSON array of flat
account records, ldap3-style `{ "dn": "...", "attributes": { ... } }` entries,
or an `{ "entries": [ ... ], "rootdse": { ... } }` envelope. UTF-8 with an
optional BOM is supported. Limits are 8 MiB per input file, 50,000 records and
200,000 SPN values. Split larger exports into appropriately scoped files;
duplicate-SPN analysis then covers only the records in each file.

The report includes every supplied account, including accounts without SPNs:
`sAMAccountName`, GUID/DN identity, object classes, UAC-derived disabled status,
supplied timestamps, advertised encryption types and parsed SPNs. It also
reports duplicate SPNs and unknown account status. An exported username is an
observation, not a live authentication check. Missing UAC remains unknown.

An optional RootDSE export can be supplied with `--ldap-spn-rootdse rootdse.json`.
Use `--ldap-spn-complete` only to record your own completeness declaration;
`directory_completeness_verified` remains false. A website scan, RootDSE response
or successful parse cannot verify a complete domain/forest account inventory.
Do not combine this offline route with `--domain`, `--mode`, `--db-path`,
`--info-report` or `--html-report`; it has a separate parser and no automatic ORM
or HTML output. In PowerShell, use explicit UTF-8 output instead of legacy `>`:

```powershell
python -m adpentest --ldap-spn-data ad-users.json | Set-Content -Encoding utf8 ad-users-report.json
```

Try the [synthetic two-account JSON export](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/examples/ad-users.json), supplied
in the source distribution. Download it as `ad-users.json`; its expected
coverage is two entries, one disabled account and one SPN. It contains no real
organization data.

#### Administrator export example

On a Windows administration workstation with the ActiveDirectory PowerShell
module, directory connectivity and an account authorized to read the selected
scope, export the supported attributes from an **explicit approved controller**:

```powershell
Import-Module ActiveDirectory
$dc = 'dc.lab.example'
$searchBase = 'OU=Users,DC=lab,DC=example'
$entries = @(Get-ADUser -Server $dc -SearchBase $searchBase -Filter * -ErrorAction Stop -Properties userAccountControl,servicePrincipalName,msDS-SupportedEncryptionTypes,pwdLastSet,lastLogonTimestamp |
    Select-Object distinguishedName,sAMAccountName,userAccountControl,'msDS-SupportedEncryptionTypes',pwdLastSet,lastLogonTimestamp,
        @{Name='objectGUID';Expression={$_.ObjectGUID.ToString()}},
        @{Name='objectClass';Expression={@('top','person','organizationalPerson','user')}},
        @{Name='servicePrincipalName';Expression={@($_.servicePrincipalName)}})
ConvertTo-Json -InputObject $entries -Depth 6 | Set-Content -Encoding utf8 ad-users.json
python -m adpentest --ldap-spn-data ad-users.json | Set-Content -Encoding utf8 ad-users-report.json
```

Replace the controller and search base with your authorized values. This
read-only export uses the current Windows identity and covers users in the
selected search base; it does not include all forests, computers, groups or
managed service accounts. Review permissions, export errors and scope before
declaring completeness. The script does not add a network-query feature to
AdPentest. Microsoft references: [Get-ADUser](https://learn.microsoft.com/en-us/powershell/module/activedirectory/get-aduser)
and [ConvertTo-Json](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/convertto-json?view=powershell-5.1).

### Compatibility and troubleshooting

Existing standalone diagnostic and legacy AD commands retain their behavior.
The `adpentest[smb]` installation extra remains a compatibility alias;
Impacket is already a required dependency. Existing entrypoint report fields and
the original bounded `planned_requests` list remain available; full coverage
and combined diagnostic results are additive fields. Existing report consumers
should tolerate additional keys.

| Existing integration | Compatibility in this release |
| --- | --- |
| `.12` CLI scripts | Runtime arguments and defaults are unchanged; `.13` updates documentation and release metadata. |
| `.11` entrypoint inventory with `--ALL-PORTS` alone | Retains inventory-only behavior. Diagnostic port mapping requires an explicit diagnostic selection such as `--port-map`. |
| Existing `--db-path` SQLite history | Older rows/tables remain intact; new ORM tables are additive. Historical findings are not reclassified by upgrading. |
| Existing entrypoint JSON consumers | Schema version 1 and original root fields remain; new evidence fields are additive, and combined diagnostics retain their own schema version 2. |
| Existing report-generator imports | `generate_html_report` and `export_html_report` remain exported from `adpentest`. |
| Older Kerberos metadata workflows | `--ticket-inventory` and offline `--ldap-spn-data` remain separate routes with their existing options, rather than being folded into website scans. |
| Existing `adpentest[smb]` install commands | Remain accepted; Impacket is a mandatory dependency. |

To upgrade an existing installation, first back up its history database while
no scan is writing to it, then install the pinned version above. Keep your
existing command arguments and validate the selected profile in `dry-run` with
new report filenames before the next active run. Compare scope, planned work
and persistence receipts. Do not add website-profile options to legacy or
offline scripts merely because the new guide shows them in other examples.
This documentation release does not retroactively change old findings or
guarantee compatibility of independently installed external executable versions.

| Symptom | Action |
| --- | --- |
| Unrecognized `-vpn-access-check` | Use the double-hyphen `--vpn-access-check` and the `--entrypoint-check` profile. |
| No port map with gateway inventory | Add `--port-map` alongside `--ALL-PORTS`. |
| Wrong host selected for VPN review | Supply `--vpn-access-host` explicitly; the default is the exact website host. |
| Missing Nmap or another diagnostic executable | Install the selected tool separately and verify PATH; review the recorded missing-tool result. |
| Existing JSON/HTML path rejected | Choose a new filename and ensure its parent directory exists. |
| Website host blocked by DNS scope | Inspect the recorded addresses and scope; this public profile rejects private/mixed answers. |
| Offline account count is unexpected | Inspect `coverage.entry_count`, export scope and errors; the analyzer cannot discover omitted users. |
| Options from different profiles rejected | Read the selected route's help, e.g. `--entrypoint-check --help` or `--ldap-spn-data ad-users.json --help`. |

Do not mix `--active-search` or `--pentest-technique` into the entrypoint or
offline account commands. The legacy broad scanner is not a users-only
inventory. See [release notes](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/RELEASE_2.14.213.78.21.13.md) for this
documentation release.

## Other supported profiles

Local Kerberos ticket metadata for the current user's existing cache:

```console
python -m adpentest --ticket-inventory --mode active --db-path ./ticket-history.sqlite
```

This independent route lists principals, TGT/service type, encryption, flags
and validity timestamps, and saves sanitized metadata through the existing ORM.
It does not start a target scan or export ticket/key material. The default mode
is a dry run. See [ticket inventory and CVE evidence handling](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/TICKET_INVENTORY.md).

DNS metadata checks for one host with an explicit resolver:

```console
python -m adpentest --dns-check --target files.lab.example --dns-server 192.0.2.53 --mode active --scope-confirmed --db-path ./dns-history.sqlite
```

This route records A/AAAA/CNAME/PTR evidence, TTLs, lookup errors and a bounded
forward/reverse check in the ORM. It requires no Nmap executable. See
[DNS host diagnostics](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/DNS_HOST_CHECKS.md) for resolver selection, limits
and the existing hostname-based service configuration checks.

The PyPI `2.14.213.78.21.6` files published on 2026-10-06 are the
`cb4ce2426765704ddb53d14276e5aacb2cf238fa` snapshot. The features introduced in
`.7` and retained in `.10` are absent from those published `.6` files. See the
[verified artifact provenance](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/PYPI_2.14.213.78.21.6_PROVENANCE.md).

SMBv1 host, user and UNC inventory from existing exports (2.14.213.78.21.10):

```console
python -m adpentest --smbv1-data existing-report.json
python -m adpentest --smbv1-data existing-report.json --smbv1-only --smbv1-host fileserver --smbv1-user alice --smbv1-unc Team
python -m adpentest --smbv1-data existing-nmap.xml --smbv1-db ./scan_history.db
```

This local-file route reports enabled, disabled, unknown or conflicting SMBv1
evidence, exported usernames and UNC paths with source references. Search filters
select whole host records and combine with AND. Share roots built from an exported
host and share name are marked as constructed; usernames and paths do not establish
account validity or share access. Try [the synthetic inventory](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/examples/smbv1-inventory.json).
See [SMBv1 export analysis](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/SMBV1_DATA.md#host-user-and-unc-inventory) for formats and API use.

`SMBv1ExportParser` provides `parse_json`, `parse_xml`, `parse_text`, `parse_data`
and `parse_file`. Its reports can be saved to SQLAlchemy import, host, user and
UNC tables, with source evidence and relationships:

```python
from adpentest.smbv1_data import SMBv1ExportParser

parser = SMBv1ExportParser()
report = parser.parse_file("existing-nmap.xml")  # JSON files work too.
receipt = parser.save_to_orm(report, "scan_history.db")
```

See [class and ORM examples](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/SMBV1_DATA.md#python-class-and-orm-tables).

Single-host TCP and VPN UDP port inventory is explicitly selected with
`--ALL-PORTS` (or `--all-ports`), including targets without an AD controller:

```console
python -m adpentest --ALL-PORTS --target vpn.example --mode dry-run --db-path ./vpn-history.sqlite
```

This selects TCP 1-65535 and UDP 500, 1194, 1701, 4500 and 51820 with Nmap.
PPTP control port 1723 is included; its GRE prerequisite is reported as untested.
Results are port states and candidate labels, without service or vulnerability
verification. See [VPN port prerequisites and output](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/DIAGNOSTIC_TOOLS.md#all-tcp-ports-and-vpn-port-states).

For a PPTP control check on one endpoint:

```console
python -m adpentest --pptp-check --target vpn.example --mode dry-run --domain lab.example --info-report ./pptp-review.json --db-path ./pptp-history.sqlite
```

Choose `--mode active --scope-confirmed` for an authorized control exchange. It
uses Python's standard library on TCP/1723, validates the bounded reply, records
the server's result code and metadata, and closes its connection. Domain-linked
ORM history includes failures and dry runs. Authentication, GRE and VPN tunnel
connectivity are reported as untested. See [PPTP checks](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/DIAGNOSTIC_TOOLS.md#pptp-control-check).

For fixed TLS certificate, SMB and SSH metadata checks with a configuration
review report:

```console
python -m adpentest --info-checks --target vpn.example --mode dry-run --info-report ./information-review.json --db-path ./information-history.sqlite
```

Active collection requires `--mode active --scope-confirmed`. The report retains
evidence, unknown checks and review guidance; it does not confirm CVEs or run
exploit probes. See [information checks and reporting](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/DIAGNOSTIC_TOOLS.md#limited-information-checks-and-report).

Single-host diagnostics accept an exclusive DNS server list:

```console
python -m adpentest --target fileserver.lab.example --smbv1-check --dns-server="192.0.2.53,2001:db8::53" --dns-timeout 3 --db-path ./scan_history.db --mode dry-run
```

Active diagnostics pin one resolved address. Public IP inputs use a
forward-confirmed PTR FQDN in `host` and `target`, retaining `input_host`,
`input_target` and `resolved_address`. A public IP without a verified FQDN is
recorded as `dns-name-unavailable` and is not probed. Targets in
`172.16.199.0/24`, including hostname answers, are recorded as `ignored`.
Dry runs perform no DNS queries. Completed, untruncated single-host Nmap XML is
automatically parsed through `SMBv1ExportParser` into linked ORM inventory rows
in the selected database. See [DNS and XML persistence](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/DIAGNOSTIC_TOOLS.md#dns-target-identity-and-exclusions).

To check protocol negotiation on one authorized host, with Nmap installed:

```console
python -m adpentest --diagnostic-tools nmap_smbv1 --target 192.0.2.10 --mode active --scope-confirmed
```

This opt-in profile checks TCP 445 and saves raw output and a structured SMBv1
observation through the diagnostic ORM. Nmap commands always include `-vv` for
increased verbosity; diagnostic captures retain the existing 65,536-byte limit
per stream and flag truncated output. See [diagnostic profiles](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/DIAGNOSTIC_TOOLS.md).
The Python SMB client (`impacket>=0.13,<0.14`) is a required package dependency:

```console
python -m pip install --upgrade --no-cache-dir --index-url https://pypi.org/simple "adpentest==2.14.213.78.21.13"
```

With Nmap on PATH, run the combined built-in diagnostics on one host you administer:

```console
python -m adpentest --target 192.0.2.10 --port-map --ports 1-65535 --port-map-timeout 600 --smbv1-check --smbv1-access --smb-share SHARE --smb-user alice --smb-domain LAB --mode active --scope-confirmed
```

The SMB password is prompted without echo. The access profile negotiates SMBv1,
authenticates once using the supplied existing account, and returns a root directory
listing for the specified share. It rejects guest sessions. Results are stored in
diagnostic ORM history; passwords are passed to the worker over a private pipe.
Omit `--mode active --scope-confirmed` to preview all three operations without
network traffic or a password prompt. See [port mapping and SMB access](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/docs/SMBV1_DATA.md#port-mapping-and-authenticated-share-access)
for prerequisites, result fields and timeouts.

[![GitHub stars](https://img.shields.io/github/stars/netanelcyber/AdPentestAI-Python?style=flat)](https://github.com/netanelcyber/AdPentestAI-Python/stargazers)
[![GitHub issues](https://img.shields.io/github/issues/netanelcyber/AdPentestAI-Python)](https://github.com/netanelcyber/AdPentestAI-Python/issues)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![PyPI](https://img.shields.io/pypi/v/adpentest)](https://pypi.org/project/adpentest/)

**Active Directory penetration testing framework** with automatic Domain Controller detection, multi-threaded tool execution, WAF bypass engine, CVE scanning, and SQLite scan history.

> **For authorized penetration testing only.** Always get explicit written permission before testing any systems.

---

## Table of Contents

- [Quick Start](#quick-start)
- [Features](#features)
- [Installation](#installation)
- [Usage](#usage)
- [CVE Scanners](#cve-scanners)
- [WAF Detection & Bypass](#waf-detection--bypass)
- [Scan History Database](#scan-history-database)
- [DC Detection Strategies](#dc-detection-strategies)
- [Tool Registry](#tool-registry)
- [Email Protocol Enumeration](#email-protocol-enumeration)
- [DNS Configuration](#dns-configuration)
- [Architecture](#architecture)
- [Contributing](#contributing)
- [License](#license)

---

## Quick Start

This section describes the existing broad legacy scanner. For website gateways
and exported user inventories, use the explicit profiles in the user guide above.
Its active workflows have a wider scope than the entrypoint profile.

```bash
pip install adpentest

# Dry-run — preview what would execute, no actual tool runs
adpentest --target 10.0.0.1 --mode dry-run --scope-confirmed

# Active scan with auto DC detection
adpentest --target corp.local --mode active --scope-confirmed

# View scan history
adpentest --history

# View all vulnerable CVE findings
adpentest --cve-report
```

## Features

### Core Capabilities

- **Auto DC Detection** — discovers Domain Controllers via DNS SRV records, LDAP RootDSE probes, port fingerprinting, and subnet sweep
- **Multi-threaded execution** — 16 parallel workers for tool execution, 32 workers for port/DNS/credential tasks (10-15x speedup)
- **35+ AD/SMB/Kerberos/ADCS/Email tools** — cross-platform binary tools + pure Python implementations
- **7 CVE scanners** — automated detection of critical AD vulnerabilities (CVSS 7.5-9.4)
- **WAF detection & bypass** — identifies WAF/CDN vendors and attempts bypass via HTTP spoofing, raw LDAP/Kerberos, TCP fragmentation
- **SQLite scan history** — persistent storage of all scan runs, tool results, and CVE findings
- **Auto-install** — missing tools installed automatically via apt/pip/git
- **Safety** — `dry-run` is the default mode; `--scope-confirmed` required for authorization

### Attack Vectors

| Category | Tools | Description |
|----------|-------|-------------|
| **Reconnaissance** | nmap, masscan, enum4linux-ng, rpcdump, bloodhound-python, ldapdomaindump | Network & AD enumeration |
| **SMB** | smbclient, smbmap, crackmapexec, impacket | Null sessions, share enum, signing detection, credential testing |
| **Kerberos** | GetUserSPNs, AS-REP roast, Kerberoast, kerbrute | SPN enum, ticket extraction, user enumeration |
| **ADCS** | certipy (find, shadow, ESC1, ESC3, ESC9) | Certificate template analysis & exploitation |
| **Email** | SMTP/POP3/IMAP enum & auth testing | User discovery, credential testing, Exchange detection |
| **Privilege Escalation** | ACL scanner, GPO abuse, delegation chain, auto privesc | Permission analysis & escalation paths |
| **Persistence** | Golden/silver ticket, DCshadow, skeleton key, DSRM, SID history | Domain persistence techniques |
| **Coercion & Relay** | PetitPotam, PrinterBug, NTLM relay | Authentication coercion attacks |
| **CVE Scanning** | 7 dedicated scanners | Certighost, ResetNightmare, NTLM bypass, RC4, RPC RCE |

---

## Installation

### From PyPI

```bash
pip install adpentest
```

### From Source

```bash
git clone https://github.com/netanelcyber/AdPentestAI-Python.git
cd AdPentestAI-Python
pip install -e .
```

### Dependencies

| Package | Version | Purpose |
|---------|---------|---------|
| `httpx` | >= 0.27 | HTTP client for EWS/web enumeration |
| `dnspython` | >= 2.4 | DNS resolution with SRV record support |
| `ldap3` | >= 2.9 | LDAP operations (RootDSE, anonymous bind) |
| `impacket` | >= 0.13, < 0.14 | Required Python SMB backend |

Standard library modules used: `smtplib`, `poplib`, `imaplib`, `socket`, `concurrent.futures`, `subprocess`, `sqlite3`, `json`.

---

## Usage

### Basic Scans

```bash
# Dry-run (check tools, detect DCs, preview commands — no actual execution)
adpentest --target 10.0.0.1 --mode dry-run --scope-confirmed

# Active scan with auto DC detection
adpentest --target corp.local --mode active --scope-confirmed

# Custom timeout and no auto-install of missing tools
adpentest --target 192.168.1.10 --mode active --scope-confirmed --timeout 600 --no-auto-install

# Custom DNS servers
adpentest --target corp.local --mode active --scope-confirmed --dns-server 1.1.1.1,8.8.8.8

# Connect via VPN before scanning
adpentest --target 10.10.10.1 --mode active --scope-confirmed --vpn lab.ovpn
```

### Scan History & Reports

```bash
# Show all past scan runs
adpentest --history

# Show last 5 runs
adpentest --history --history-limit 5

# Show all vulnerable CVE findings across all runs
adpentest --cve-report

# Show details for a specific run
adpentest --run-details run-8824073e5124-20260904055457

# Use custom database path
adpentest --history --db-path /path/to/custom.db
```

### HTML Pentest Report Generation

Generate an executive-ready, standalone, and interactive HTML penetration test report (<100KB):

```bash
# Generate report during active scan
adpentest --target corp.local --mode active --scope-confirmed --html-report report.html

# Generate report from an existing JSON output file
python -m adpentest.report_generator scan_results.json report.html
```

- **0.0 - 10.0 Executive Risk Score** with CVSS & severity metrics gauge
- **Interactive Dark / Light mode** toggle & print-optimized layout
- **Target architecture & Domain Controller detection** breakdown
- **Categorized security findings** with remediation advice
- **Collapsible tool execution logs** with timing and duration metrics


### Lab Setup

```bash
# Interactive lab setup orchestrator
adpentest --setup-labs
```

### Output Format

All scan output is JSON:

```json
{
  "status": "completed",
  "run_id": "run-abc123-20260901120000",
  "db_path": "~/.adpentest/scan_history.db",
  "dc_detection": {
    "dc_count": 2,
    "detected_domain": "corp.local",
    "domain_controllers": [...]
  },
  "execution": {
    "result_count": 35,
    "completed": 28,
    "failed": 7
  }
}
```

See [`examples/sample-dry-run-output.json`](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/examples/sample-dry-run-output.json) for a complete example.

---

## CVE Scanners

The framework includes 7 built-in CVE scanners that run as part of every scan. All scanners are **safe and read-only** — they use port probes, anonymous LDAP queries, and raw protocol checks only.

| CVE | Name | CVSS | Description |
|-----|------|------|-------------|
| CVE-2026-59270 | Spring LDAP | 9.4 | Hardcoded credentials in Spring Security embedded LDAP (UnboundIdContainer) |
| CVE-2026-54121 | Certighost | 8.8 | AD CS enrollment bypass — certificate enrollment for arbitrary computer accounts |
| CVE-2025-54918 | NTLM LDAP Bypass | 8.1 | NTLM authentication bypass on DC LDAP — privilege escalation to SYSTEM |
| CVE-2026-33826 | AD RPC RCE | 8.0 | Windows AD RPC remote code execution via improper input validation |
| CVE-2026-27912 | ResetNightmare | 8.0 | Kerberos kpasswd password reset bypass via UPN collision — full domain takeover |
| CVE-2026-24294 | NTLM Reflection | 7.8 | NTLM reflection via SMB port multiplexing (Server 2025 / Win 11 24H2) |
| CVE-2026-20833 | Kerberos RC4 | 7.5 | KDC accepts RC4-HMAC encryption — enables Kerberoasting attacks |

### What Each Scanner Checks

**CVE-2026-59270** — Attempts LDAP bind with known hardcoded credentials (`uid=admin,ou=system` / `secret`) on ports 389, 636, 53389, 33389, 10389, 8389. Reports exposed entry count.

**CVE-2026-54121** — Queries AD CS Enrollment Services and certificate templates via LDAP. Identifies templates with `ENROLLEE_SUPPLIES_SUBJECT` flag or risky enrollment configurations.

**CVE-2025-54918** — Checks if LDAP accepts NTLM/GSS-SPNEGO authentication without enforced signing. Extracts DC functional level and domain context.

**CVE-2026-33826** — Probes RPC endpoint mapper (port 135), confirms AD DC via LDAP, checks for exposed RPC-related ports (135, 593, 445, 139).

**CVE-2026-27912** — Checks if kpasswd (port 464) and Kerberos (port 88) are open. Queries `ms-DS-MachineAccountQuota` to assess exploitation feasibility.

**CVE-2026-24294** — Sends SMB2 Negotiate to detect protocol version and signing mode. Checks for alternative SMB ports (8445, 9445, etc.) indicating port multiplexing.

**CVE-2026-20833** — Sends raw Kerberos AS-REQ with RC4 (etype 23), AES256 (etype 18), and AES128 (etype 17) to detect which encryption types the KDC accepts.

---

## WAF Detection & Bypass

When scanning targets behind WAF/CDN services, the framework automatically:

1. **Detects WAF vendor** — checks HTTP headers and body content for signatures of 17+ WAF vendors (Incapsula/Imperva, Cloudflare, Akamai, AWS WAF, Azure Front Door, Sucuri, etc.)
2. **Attempts bypass** via 5 technique layers:
   - **HTTP bypass** — header spoofing (X-Forwarded-For, X-Real-IP, CF-Connecting-IP), User-Agent rotation, path obfuscation, verb tampering
   - **Raw LDAP** — BER-encoded LDAPv3 anonymous bind directly to port 389
   - **Raw Kerberos** — AS-REQ with TCP framing to port 88
   - **TCP fragmentation** — 1 byte per TCP segment with TCP_NODELAY
   - **Email/HTTP** — OWA, EWS NTLM handshake, Autodiscover, ActiveSync, MAPI probing

If raw LDAP or Kerberos bypasses the WAF, the framework extracts domain info and adjusts DC detection confidence accordingly.

---

## Scan History Database

All scan data is automatically stored in SQLite at `~/.adpentest/scan_history.db`.

### Database Schema

**`scan_runs`** — One row per scan execution:
- `run_id`, `target`, `mode`, `started_at`, `finished_at`, `status`
- `dc_count`, `live_hosts`, `tools_executed`, `tools_succeeded`, `tools_failed`
- `cves_checked`, `cves_vulnerable`

**`tool_results`** — One row per tool execution:
- `tool`, `host`, `is_dc`, `fqdn`, `status`, `duration_sec`, `output`, `error`

**`cve_findings`** — One row per CVE check:
- `cve_id`, `target`, `cvss`, `severity`, `vulnerable`, `impact`, `details_json`

### Querying Directly

```bash
# Open the database
sqlite3 ~/.adpentest/scan_history.db

# All vulnerable findings
SELECT cve_id, target, cvss, severity, impact FROM cve_findings WHERE vulnerable=1 ORDER BY cvss DESC;

# Scan history summary
SELECT run_id, target, mode, status, tools_executed, cves_vulnerable, started_at FROM scan_runs ORDER BY started_at DESC;

# Tool success rate
SELECT tool, COUNT(*) as runs, SUM(CASE WHEN status='completed' THEN 1 ELSE 0 END) as ok FROM tool_results GROUP BY tool ORDER BY runs DESC;
```

---

## DC Detection Strategies

The framework uses a multi-strategy pipeline to discover Domain Controllers:

| Strategy | Method | Confidence |
|----------|--------|------------|
| DNS SRV | Queries `_ldap._tcp.dc._msdcs.<domain>` | High (0.9) |
| LDAP RootDSE | Anonymous bind to extract domain/forest info | High (0.9) |
| Port fingerprint | Checks Kerberos (88), LDAP (389/636), GC (3268/3269) | Medium (0.7) |
| Subnet sweep | Kerberos port 88 scan on /24 → /23 → /22 | Medium (0.6) |

When WAF is detected blocking ports, the bypass engine runs automatically. If raw LDAP/Kerberos bypasses succeed, confidence is adjusted to 0.7 ("waf-bypassed"); otherwise 0.1 ("waf-blocked").

---

## Tool Registry

### Available Tools (35+)

**Binary tools:** nmap, masscan, enum4linux-ng, rpcdump, smbclient, bloodhound-python, certipy, ldapdomaindump, kerbrute, crackmapexec, smbmap, impacket (secretsdump, psexec)

**Windows-native:** powershell_ldap_enum, powershell_smb_enum, powershell_ad_recon

**Kerberos:** GetUserSPNs, AS_REP_roast, kerberoast

**ADCS:** certipy_shadow, certipy_esc1, certipy_esc3, certipy_esc9

**Email:** smtp_enum, smtp_auth_test, pop3_auth_test, imap_auth_test, email_server_discovery

**Exploitation:** ntlm_null_session, auto_privesc, golden_ticket, silver_ticket, delegation_abuse, trust_enumeration, trust_abuse, petitpotam, printerbug, ntlm_relay, acl_scanner, acl_exploit, gpo_abuse, delegation_chain, sid_history, dsrm_backdoor, dcshadow, golden_gmsa, skeleton_key

**CVE scanners:** cve_2026_59270, cve_2026_54121, cve_2025_54918, cve_2026_33826, cve_2026_27912, cve_2026_24294, cve_2026_20833

---

## Email Protocol Enumeration

Pure Python email enumeration using standard library (no external dependencies):

- **SMTP VRFY** — discover valid usernames via VRFY command
- **SMTP RCPT TO** — validate recipients via RCPT TO
- **Credential testing** — automatic fallback chain: SMTP → POP3 → IMAP
- **Exchange detection** — OWA, EWS NTLM handshake (extracts domain/DC/forest from NTLM challenge), Autodiscover, ActiveSync, MAPI
- **Parallel testing** — 32 concurrent workers for credential testing

Ports scanned: 25, 465, 587 (SMTP), 110, 995 (POP3), 143, 993 (IMAP).

---

## DNS Configuration

### Priority Order

1. **CLI arguments** (`--dns-server`, `--dns-timeout`) — highest priority
2. **Environment variables** (`DNS_SERVERS`, `DNS_TIMEOUT`)
3. **System default DNS** — auto-detected
4. **Public DNS fallback** — Google (8.8.8.8, 8.8.4.4), Cloudflare (1.1.1.1, 1.0.0.1)

An explicit CLI or environment server list replaces system/public resolvers;
errors do not fall back to another resolver. The single-host diagnostic route
uses `--dns-server="IP1,IP2"` (also repeatable) or system DNS when omitted, without
public fallback. Its `--dns-timeout` bounds the entire target lookup.

```bash
# CLI
adpentest --target corp.local --mode active --scope-confirmed --dns-server 192.168.1.1,8.8.8.8 --dns-timeout 5.0

# Environment
export DNS_SERVERS=192.168.1.1,1.1.1.1
export DNS_TIMEOUT=5.0
adpentest --target corp.local --mode active --scope-confirmed
```

---

## Architecture

### Single-File Design

All framework logic is in `adpentest/core.py`. This monolithic approach provides clear dependency flow, centralized tool registry, unified error handling, and easy deployment.

### Execution Pipeline

```
Input: --target 10.0.0.1 --mode active --scope-confirmed
  │
  ├── Scope validation (dry-run vs active)
  ├── Tool discovery (scan $PATH)
  ├── SQLite run initialization
  │
  ├── DC Detection (multi-strategy)
  │   ├── DNS SRV queries
  │   ├── LDAP RootDSE probe
  │   ├── Port fingerprint (+ WAF detect/bypass)
  │   └── Subnet sweep (/24 → /23 → /22)
  │
  ├── Domain discovery + FQDN resolution
  ├── Email server discovery (MX + port scan)
  │
  ├── Parallel Tool Execution (ThreadPoolExecutor, 16 workers)
  │   ├── AD tools against DCs (prioritized)
  │   ├── CVE scanners against all targets
  │   └── Results → SQLite (tool_results + cve_findings)
  │
  └── Output: JSON + SQLite database
```

### Threading Model

| Pool | Workers | Purpose |
|------|---------|---------|
| Tool execution | 16 | AD diagnostic tools in parallel |
| Port scanning | 32 | Concurrent TCP port checks |
| DNS resolution | 32 | Concurrent DNS queries |
| Credential testing | 32 | SMTP/POP3/IMAP auth testing |

---

## Contributing

Contributions are welcome! See [CONTRIBUTING.md](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/CONTRIBUTING.md) for setup instructions and [CODE_OF_CONDUCT.md](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/CODE_OF_CONDUCT.md) for community guidelines.

Check the [open issues](https://github.com/netanelcyber/AdPentestAI-Python/issues) for tasks labeled `good-first-issue` or `help-wanted`.

### Adding a New CVE Scanner

1. Add scanner function `scan_cve_YYYY_NNNNN(target, timeout)` returning a dict with `cve`, `cvss`, `severity`, `vulnerable`, `impact`, `remediation`
2. Add tool name `cve_YYYY_NNNNN_short_name` to `AD_TOOLS` set
3. Add to `PIP_PACKAGES` (empty list for pure Python)
4. Add to `EXECUTABLES` (python3/python/python.exe)
5. Add `build_ad_command` handler

### Adding a New Tool

1. Add tool name to `AD_TOOLS` set
2. Add package mapping to `PIP_PACKAGES`/`APT_PACKAGES`/`WINGET_PACKAGES`
3. Add executable names to `EXECUTABLES` dict
4. Implement command building in `build_ad_command()`

---

## License

[MIT](https://github.com/netanelcyber/AdPentestAI-Python/blob/release/pypi-2.14.213.78.21.13/LICENSE)

---

**Disclaimer:** This tool is designed for authorized penetration testing and security research only. Users are responsible for obtaining proper authorization before testing any systems. The authors assume no liability for misuse.
