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.