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:
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:
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:
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:
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:
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:
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.
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:
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.
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:
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
and encryption attribute.
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:
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 >:
python -m adpentest --ldap-spn-data ad-users.json | Set-Content -Encoding utf8 ad-users-report.json
Try the synthetic two-account JSON export, 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:
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 and ConvertTo-Json.
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 for this
documentation release.
Other supported profiles
Local Kerberos ticket metadata for the current user's existing cache:
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.
DNS metadata checks for one host with an explicit resolver:
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 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.
SMBv1 host, user and UNC inventory from existing exports (2.14.213.78.21.10):
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. See SMBv1 export analysis 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:
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")
Single-host TCP and VPN UDP port inventory is explicitly selected with
--ALL-PORTS (or --all-ports), including targets without an AD controller:
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.
For a PPTP control check on one endpoint:
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.
For fixed TLS certificate, SMB and SSH metadata checks with a configuration review report:
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.
Single-host diagnostics accept an exclusive DNS server list:
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.
To check protocol negotiation on one authorized host, with Nmap installed:
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.
The Python SMB client (impacket>=0.13,<0.14) is a required package dependency:
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:
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
for prerequisites, result fields and timeouts.
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
- Features
- Installation
- Usage
- CVE Scanners
- WAF Detection & Bypass
- Scan History Database
- DC Detection Strategies
- Tool Registry
- Email Protocol Enumeration
- DNS Configuration
- Architecture
- Contributing
- 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.
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-runis the default mode;--scope-confirmedrequired 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 |
| 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
pip install adpentest
From Source
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
# 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
# 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):
# 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
# Interactive lab setup orchestrator
adpentest --setup-labs
Output Format
All scan output is 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 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:
- 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.)
- 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,statusdc_count,live_hosts,tools_executed,tools_succeeded,tools_failedcves_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
# 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
- CLI arguments (
--dns-server,--dns-timeout) — highest priority - Environment variables (
DNS_SERVERS,DNS_TIMEOUT) - System default DNS — auto-detected
- 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.
# 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 for setup instructions and CODE_OF_CONDUCT.md for community guidelines.
Check the open issues for tasks labeled good-first-issue or help-wanted.
Adding a New CVE Scanner
- Add scanner function
scan_cve_YYYY_NNNNN(target, timeout)returning a dict withcve,cvss,severity,vulnerable,impact,remediation - Add tool name
cve_YYYY_NNNNN_short_nametoAD_TOOLSset - Add to
PIP_PACKAGES(empty list for pure Python) - Add to
EXECUTABLES(python3/python/python.exe) - Add
build_ad_commandhandler
Adding a New Tool
- Add tool name to
AD_TOOLSset - Add package mapping to
PIP_PACKAGES/APT_PACKAGES/WINGET_PACKAGES - Add executable names to
EXECUTABLESdict - Implement command building in
build_ad_command()
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.
Metadata
Release files for adpentest 2.14.213.78.21.13
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| adpentest-2.14.213.78.21.13.tar.gz | 389.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| adpentest-2.14.213.78.21.13-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 602.2 kB
Release files / adpentest-2.14.213.78.21.13.tar.gz
| Download URL | adpentest-2.14.213.78.21.13.tar.gz |
|---|---|
| Size | 389.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
04619b0c9633bb397f8bf62c12a7aa1c9194205fcc2a1e3da6d846191a965c2e
|
|
BLAKE2b-256 checksum How to use checksums |
e2cac600814ab4efa19272507bd9e3b6cacc28a3c3a2e0fe89da81ec9eda44d6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / adpentest-2.14.213.78.21.13-py3-none-any.whl
| Download URL | adpentest-2.14.213.78.21.13-py3-none-any.whl |
|---|---|
| Size | 212.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
19be95ba8a721d69ff90b3829eac95e5eecc3c823a7f1b6ba88eaf24da12b020
|
|
BLAKE2b-256 checksum How to use checksums |
3380c57eaec0669810cc6a541d9e02e94c9d2b3dbe9a12907e4619a97fec895d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|